source: trunk/minix/servers/fs/super.c@ 21

Last change on this file since 21 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 10.6 KB
Line 
1/* This file manages the super block table and the related data structures,
2 * namely, the bit maps that keep track of which zones and which inodes are
3 * allocated and which are free. When a new inode or zone is needed, the
4 * appropriate bit map is searched for a free entry.
5 *
6 * The entry points into this file are
7 * alloc_bit: somebody wants to allocate a zone or inode; find one
8 * free_bit: indicate that a zone or inode is available for allocation
9 * get_super: search the 'superblock' table for a device
10 * mounted: tells if file inode is on mounted (or ROOT) file system
11 * read_super: read a superblock
12 */
13
14#include "fs.h"
15#include <string.h>
16#include <minix/com.h>
17#include "buf.h"
18#include "inode.h"
19#include "super.h"
20#include "const.h"
21
22/*===========================================================================*
23 * alloc_bit *
24 *===========================================================================*/
25PUBLIC bit_t alloc_bit(sp, map, origin)
26struct super_block *sp; /* the filesystem to allocate from */
27int map; /* IMAP (inode map) or ZMAP (zone map) */
28bit_t origin; /* number of bit to start searching at */
29{
30/* Allocate a bit from a bit map and return its bit number. */
31
32 block_t start_block; /* first bit block */
33 bit_t map_bits; /* how many bits are there in the bit map? */
34 unsigned bit_blocks; /* how many blocks are there in the bit map? */
35 unsigned block, word, bcount;
36 struct buf *bp;
37 bitchunk_t *wptr, *wlim, k;
38 bit_t i, b;
39
40 if (sp->s_rd_only)
41 panic(__FILE__,"can't allocate bit on read-only filesys.", NO_NUM);
42
43 if (map == IMAP) {
44 start_block = START_BLOCK;
45 map_bits = sp->s_ninodes + 1;
46 bit_blocks = sp->s_imap_blocks;
47 } else {
48 start_block = START_BLOCK + sp->s_imap_blocks;
49 map_bits = sp->s_zones - (sp->s_firstdatazone - 1);
50 bit_blocks = sp->s_zmap_blocks;
51 }
52
53 /* Figure out where to start the bit search (depends on 'origin'). */
54 if (origin >= map_bits) origin = 0; /* for robustness */
55
56 /* Locate the starting place. */
57 block = origin / FS_BITS_PER_BLOCK(sp->s_block_size);
58 word = (origin % FS_BITS_PER_BLOCK(sp->s_block_size)) / FS_BITCHUNK_BITS;
59
60 /* Iterate over all blocks plus one, because we start in the middle. */
61 bcount = bit_blocks + 1;
62 do {
63 bp = get_block(sp->s_dev, start_block + block, NORMAL);
64 wlim = &bp->b_bitmap[FS_BITMAP_CHUNKS(sp->s_block_size)];
65
66 /* Iterate over the words in block. */
67 for (wptr = &bp->b_bitmap[word]; wptr < wlim; wptr++) {
68
69 /* Does this word contain a free bit? */
70 if (*wptr == (bitchunk_t) ~0) continue;
71
72 /* Find and allocate the free bit. */
73 k = conv2(sp->s_native, (int) *wptr);
74 for (i = 0; (k & (1 << i)) != 0; ++i) {}
75
76 /* Bit number from the start of the bit map. */
77 b = ((bit_t) block * FS_BITS_PER_BLOCK(sp->s_block_size))
78 + (wptr - &bp->b_bitmap[0]) * FS_BITCHUNK_BITS
79 + i;
80
81 /* Don't allocate bits beyond the end of the map. */
82 if (b >= map_bits) break;
83
84 /* Allocate and return bit number. */
85 k |= 1 << i;
86 *wptr = conv2(sp->s_native, (int) k);
87 bp->b_dirt = DIRTY;
88 put_block(bp, MAP_BLOCK);
89 return(b);
90 }
91 put_block(bp, MAP_BLOCK);
92 if (++block >= bit_blocks) block = 0; /* last block, wrap around */
93 word = 0;
94 } while (--bcount > 0);
95 return(NO_BIT); /* no bit could be allocated */
96}
97
98/*===========================================================================*
99 * free_bit *
100 *===========================================================================*/
101PUBLIC void free_bit(sp, map, bit_returned)
102struct super_block *sp; /* the filesystem to operate on */
103int map; /* IMAP (inode map) or ZMAP (zone map) */
104bit_t bit_returned; /* number of bit to insert into the map */
105{
106/* Return a zone or inode by turning off its bitmap bit. */
107
108 unsigned block, word, bit;
109 struct buf *bp;
110 bitchunk_t k, mask;
111 block_t start_block;
112
113 if (sp->s_rd_only)
114 panic(__FILE__,"can't free bit on read-only filesys.", NO_NUM);
115
116 if (map == IMAP) {
117 start_block = START_BLOCK;
118 } else {
119 start_block = START_BLOCK + sp->s_imap_blocks;
120 }
121 block = bit_returned / FS_BITS_PER_BLOCK(sp->s_block_size);
122 word = (bit_returned % FS_BITS_PER_BLOCK(sp->s_block_size))
123 / FS_BITCHUNK_BITS;
124
125 bit = bit_returned % FS_BITCHUNK_BITS;
126 mask = 1 << bit;
127
128 bp = get_block(sp->s_dev, start_block + block, NORMAL);
129
130 k = conv2(sp->s_native, (int) bp->b_bitmap[word]);
131 if (!(k & mask)) {
132 panic(__FILE__,map == IMAP ? "tried to free unused inode" :
133 "tried to free unused block", bit_returned);
134 }
135
136 k &= ~mask;
137 bp->b_bitmap[word] = conv2(sp->s_native, (int) k);
138 bp->b_dirt = DIRTY;
139
140 put_block(bp, MAP_BLOCK);
141}
142
143/*===========================================================================*
144 * get_super *
145 *===========================================================================*/
146PUBLIC struct super_block *get_super(dev)
147dev_t dev; /* device number whose super_block is sought */
148{
149/* Search the superblock table for this device. It is supposed to be there. */
150
151 register struct super_block *sp;
152
153 if (dev == NO_DEV)
154 panic(__FILE__,"request for super_block of NO_DEV", NO_NUM);
155
156 for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++)
157 if (sp->s_dev == dev) return(sp);
158
159 /* Search failed. Something wrong. */
160 panic(__FILE__,"can't find superblock for device (in decimal)", (int) dev);
161
162 return(NIL_SUPER); /* to keep the compiler and lint quiet */
163}
164
165/*===========================================================================*
166 * get_block_size *
167 *===========================================================================*/
168PUBLIC int get_block_size(dev_t dev)
169{
170/* Search the superblock table for this device. */
171
172 register struct super_block *sp;
173
174 if (dev == NO_DEV)
175 panic(__FILE__,"request for block size of NO_DEV", NO_NUM);
176
177 for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++) {
178 if (sp->s_dev == dev) {
179 return(sp->s_block_size);
180 }
181 }
182
183 /* no mounted filesystem? use this block size then. */
184 return _MIN_BLOCK_SIZE;
185}
186
187/*===========================================================================*
188 * mounted *
189 *===========================================================================*/
190PUBLIC int mounted(rip)
191register struct inode *rip; /* pointer to inode */
192{
193/* Report on whether the given inode is on a mounted (or ROOT) file system. */
194
195 register struct super_block *sp;
196 register dev_t dev;
197
198 dev = (dev_t) rip->i_zone[0];
199 if (dev == root_dev) return(TRUE); /* inode is on root file system */
200
201 for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++)
202 if (sp->s_dev == dev) return(TRUE);
203
204 return(FALSE);
205}
206
207/*===========================================================================*
208 * read_super *
209 *===========================================================================*/
210PUBLIC int read_super(sp)
211register struct super_block *sp; /* pointer to a superblock */
212{
213/* Read a superblock. */
214 dev_t dev;
215 int magic;
216 int version, native, r;
217 static char sbbuf[_MIN_BLOCK_SIZE];
218
219 dev = sp->s_dev; /* save device (will be overwritten by copy) */
220 if (dev == NO_DEV)
221 panic(__FILE__,"request for super_block of NO_DEV", NO_NUM);
222 r = dev_io(DEV_READ, dev, FS_PROC_NR,
223 sbbuf, SUPER_BLOCK_BYTES, _MIN_BLOCK_SIZE, 0);
224 if (r != _MIN_BLOCK_SIZE) {
225 return EINVAL;
226 }
227 memcpy(sp, sbbuf, sizeof(*sp));
228 sp->s_dev = NO_DEV; /* restore later */
229 magic = sp->s_magic; /* determines file system type */
230
231 /* Get file system version and type. */
232 if (magic == SUPER_MAGIC || magic == conv2(BYTE_SWAP, SUPER_MAGIC)) {
233 version = V1;
234 native = (magic == SUPER_MAGIC);
235 } else if (magic == SUPER_V2 || magic == conv2(BYTE_SWAP, SUPER_V2)) {
236 version = V2;
237 native = (magic == SUPER_V2);
238 } else if (magic == SUPER_V3) {
239 version = V3;
240 native = 1;
241 } else {
242 return(EINVAL);
243 }
244
245 /* If the super block has the wrong byte order, swap the fields; the magic
246 * number doesn't need conversion. */
247 sp->s_ninodes = conv4(native, sp->s_ninodes);
248 sp->s_nzones = conv2(native, (int) sp->s_nzones);
249 sp->s_imap_blocks = conv2(native, (int) sp->s_imap_blocks);
250 sp->s_zmap_blocks = conv2(native, (int) sp->s_zmap_blocks);
251 sp->s_firstdatazone = conv2(native, (int) sp->s_firstdatazone);
252 sp->s_log_zone_size = conv2(native, (int) sp->s_log_zone_size);
253 sp->s_max_size = conv4(native, sp->s_max_size);
254 sp->s_zones = conv4(native, sp->s_zones);
255
256 /* In V1, the device size was kept in a short, s_nzones, which limited
257 * devices to 32K zones. For V2, it was decided to keep the size as a
258 * long. However, just changing s_nzones to a long would not work, since
259 * then the position of s_magic in the super block would not be the same
260 * in V1 and V2 file systems, and there would be no way to tell whether
261 * a newly mounted file system was V1 or V2. The solution was to introduce
262 * a new variable, s_zones, and copy the size there.
263 *
264 * Calculate some other numbers that depend on the version here too, to
265 * hide some of the differences.
266 */
267 if (version == V1) {
268 sp->s_block_size = _STATIC_BLOCK_SIZE;
269 sp->s_zones = sp->s_nzones; /* only V1 needs this copy */
270 sp->s_inodes_per_block = V1_INODES_PER_BLOCK;
271 sp->s_ndzones = V1_NR_DZONES;
272 sp->s_nindirs = V1_INDIRECTS;
273 } else {
274 if (version == V2)
275 sp->s_block_size = _STATIC_BLOCK_SIZE;
276 if (sp->s_block_size < _MIN_BLOCK_SIZE)
277 return EINVAL;
278 sp->s_inodes_per_block = V2_INODES_PER_BLOCK(sp->s_block_size);
279 sp->s_ndzones = V2_NR_DZONES;
280 sp->s_nindirs = V2_INDIRECTS(sp->s_block_size);
281 }
282
283 if (sp->s_block_size < _MIN_BLOCK_SIZE) {
284 return EINVAL;
285 }
286 if (sp->s_block_size > _MAX_BLOCK_SIZE) {
287 printf("Filesystem block size is %d kB; maximum filesystem\n"
288 "block size is %d kB. This limit can be increased by recompiling.\n",
289 sp->s_block_size/1024, _MAX_BLOCK_SIZE/1024);
290 return EINVAL;
291 }
292 if ((sp->s_block_size % 512) != 0) {
293 return EINVAL;
294 }
295 if (SUPER_SIZE > sp->s_block_size) {
296 return EINVAL;
297 }
298 if ((sp->s_block_size % V2_INODE_SIZE) != 0 ||
299 (sp->s_block_size % V1_INODE_SIZE) != 0) {
300 return EINVAL;
301 }
302
303 sp->s_isearch = 0; /* inode searches initially start at 0 */
304 sp->s_zsearch = 0; /* zone searches initially start at 0 */
305 sp->s_version = version;
306 sp->s_native = native;
307
308 /* Make a few basic checks to see if super block looks reasonable. */
309 if (sp->s_imap_blocks < 1 || sp->s_zmap_blocks < 1
310 || sp->s_ninodes < 1 || sp->s_zones < 1
311 || (unsigned) sp->s_log_zone_size > 4) {
312 printf("not enough imap or zone map blocks, \n");
313 printf("or not enough inodes, or not enough zones, "
314 "or zone size too large\n");
315 return(EINVAL);
316 }
317 sp->s_dev = dev; /* restore device number */
318 return(OK);
319}
Note: See TracBrowser for help on using the repository browser.