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.
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
17 #include <minix/com.h>
18 #include <minix/u64.h>
19 #include <minix/bdev.h>
26 /*===========================================================================*
28 *===========================================================================*/
29 bit_t
alloc_bit(sp
, map
, origin
)
30 struct super_block
*sp
; /* the filesystem to allocate from */
31 int map
; /* IMAP (inode map) or ZMAP (zone map) */
32 bit_t origin
; /* number of bit to start searching at */
34 /* Allocate a bit from a bit map and return its bit number. */
36 block_t start_block
; /* first bit block */
38 bit_t map_bits
; /* how many bits are there in the bit map? */
39 short bit_blocks
; /* how many blocks are there in the bit map? */
40 unsigned word
, bcount
;
42 bitchunk_t
*wptr
, *wlim
, k
;
46 panic("can't allocate bit on read-only filesys");
49 start_block
= START_BLOCK
;
50 map_bits
= (bit_t
) (sp
->s_ninodes
+ 1);
51 bit_blocks
= sp
->s_imap_blocks
;
53 start_block
= START_BLOCK
+ sp
->s_imap_blocks
;
54 map_bits
= (bit_t
) (sp
->s_zones
- (sp
->s_firstdatazone
- 1));
55 bit_blocks
= sp
->s_zmap_blocks
;
58 /* Figure out where to start the bit search (depends on 'origin'). */
59 if (origin
>= map_bits
) origin
= 0; /* for robustness */
61 /* Locate the starting place. */
62 block
= (block_t
) (origin
/ FS_BITS_PER_BLOCK(sp
->s_block_size
));
63 word
= (origin
% FS_BITS_PER_BLOCK(sp
->s_block_size
)) / FS_BITCHUNK_BITS
;
65 /* Iterate over all blocks plus one, because we start in the middle. */
66 bcount
= bit_blocks
+ 1;
68 bp
= get_block(sp
->s_dev
, start_block
+ block
, NORMAL
);
69 wlim
= &b_bitmap(bp
)[FS_BITMAP_CHUNKS(sp
->s_block_size
)];
71 /* Iterate over the words in block. */
72 for (wptr
= &b_bitmap(bp
)[word
]; wptr
< wlim
; wptr
++) {
74 /* Does this word contain a free bit? */
75 if (*wptr
== (bitchunk_t
) ~0) continue;
77 /* Find and allocate the free bit. */
78 k
= (bitchunk_t
) conv4(sp
->s_native
, (int) *wptr
);
79 for (i
= 0; (k
& (1 << i
)) != 0; ++i
) {}
81 /* Bit number from the start of the bit map. */
82 b
= ((bit_t
) block
* FS_BITS_PER_BLOCK(sp
->s_block_size
))
83 + (wptr
- &b_bitmap(bp
)[0]) * FS_BITCHUNK_BITS
86 /* Don't allocate bits beyond the end of the map. */
87 if (b
>= map_bits
) break;
89 /* Allocate and return bit number. */
91 *wptr
= (bitchunk_t
) conv4(sp
->s_native
, (int) k
);
93 put_block(bp
, MAP_BLOCK
);
96 put_block(bp
, MAP_BLOCK
);
97 if (++block
>= (unsigned int) bit_blocks
) /* last block, wrap around */
100 } while (--bcount
> 0);
101 return(NO_BIT
); /* no bit could be allocated */
104 /*===========================================================================*
106 *===========================================================================*/
107 void free_bit(sp
, map
, bit_returned
)
108 struct super_block
*sp
; /* the filesystem to operate on */
109 int map
; /* IMAP (inode map) or ZMAP (zone map) */
110 bit_t bit_returned
; /* number of bit to insert into the map */
112 /* Return a zone or inode by turning off its bitmap bit. */
114 unsigned block
, word
, bit
;
120 panic("can't free bit on read-only filesys");
123 start_block
= START_BLOCK
;
125 start_block
= START_BLOCK
+ sp
->s_imap_blocks
;
127 block
= bit_returned
/ FS_BITS_PER_BLOCK(sp
->s_block_size
);
128 word
= (bit_returned
% FS_BITS_PER_BLOCK(sp
->s_block_size
))
131 bit
= bit_returned
% FS_BITCHUNK_BITS
;
134 bp
= get_block(sp
->s_dev
, start_block
+ block
, NORMAL
);
136 k
= (bitchunk_t
) conv4(sp
->s_native
, (int) b_bitmap(bp
)[word
]);
138 if (map
== IMAP
) panic("tried to free unused inode");
139 else panic("tried to free unused block: %u", bit_returned
);
143 b_bitmap(bp
)[word
] = (bitchunk_t
) conv4(sp
->s_native
, (int) k
);
146 put_block(bp
, MAP_BLOCK
);
150 /*===========================================================================*
152 *===========================================================================*/
153 struct super_block
*get_super(
154 dev_t dev
/* device number whose super_block is sought */
158 panic("request for super_block of NO_DEV");
160 if(superblock
.s_dev
!= dev
)
161 panic("wrong superblock: 0x%x", (int) dev
);
167 /*===========================================================================*
169 *===========================================================================*/
170 unsigned int get_block_size(dev_t dev
)
173 panic("request for block size of NO_DEV");
175 return(lmfs_fs_block_size());
179 /*===========================================================================*
181 *===========================================================================*/
182 static int rw_super(struct super_block
*sp
, int writing
)
184 /* Read/write a superblock. */
187 dev_t save_dev
= sp
->s_dev
;
189 /* To keep the 1kb on disk clean, only read/write up to and including
192 #define LAST_ONDISK_FIELD s_disk_version
193 int ondisk_bytes
= (int) ((char *) &sp
->LAST_ONDISK_FIELD
- (char *) sp
)
194 + sizeof(sp
->LAST_ONDISK_FIELD
);
196 STATICINIT(sbbuf
, _MIN_BLOCK_SIZE
);
198 assert(ondisk_bytes
> 0);
199 assert(ondisk_bytes
< _MIN_BLOCK_SIZE
);
200 assert(ondisk_bytes
< sizeof(struct super_block
));
202 if (sp
->s_dev
== NO_DEV
)
203 panic("request for super_block of NO_DEV");
206 memset(sbbuf
, 0, _MIN_BLOCK_SIZE
);
207 memcpy(sbbuf
, sp
, ondisk_bytes
);
208 r
= bdev_write(sp
->s_dev
, cvu64(SUPER_BLOCK_BYTES
), sbbuf
, _MIN_BLOCK_SIZE
,
211 r
= bdev_read(sp
->s_dev
, cvu64(SUPER_BLOCK_BYTES
), sbbuf
, _MIN_BLOCK_SIZE
,
213 memset(sp
, 0, sizeof(*sp
));
214 memcpy(sp
, sbbuf
, ondisk_bytes
);
215 sp
->s_dev
= save_dev
;
218 if (r
!= _MIN_BLOCK_SIZE
)
224 /*===========================================================================*
226 *===========================================================================*/
227 int read_super(struct super_block
*sp
)
231 int version
, native
, r
;
233 if((r
=rw_super(sp
, 0)) != OK
)
236 magic
= sp
->s_magic
; /* determines file system type */
238 /* Get file system version and type. */
239 if (magic
== SUPER_MAGIC
|| magic
== conv2(BYTE_SWAP
, SUPER_MAGIC
)) {
241 native
= (magic
== SUPER_MAGIC
);
242 } else if (magic
== SUPER_V2
|| magic
== conv2(BYTE_SWAP
, SUPER_V2
)) {
244 native
= (magic
== SUPER_V2
);
245 } else if (magic
== SUPER_V3
) {
252 /* If the super block has the wrong byte order, swap the fields; the magic
253 * number doesn't need conversion. */
254 sp
->s_ninodes
= (ino_t
) conv4(native
, (int) sp
->s_ninodes
);
255 sp
->s_nzones
= (zone1_t
) conv2(native
, (int) sp
->s_nzones
);
256 sp
->s_imap_blocks
= (short) conv2(native
, (int) sp
->s_imap_blocks
);
257 sp
->s_zmap_blocks
= (short) conv2(native
, (int) sp
->s_zmap_blocks
);
258 sp
->s_firstdatazone_old
=(zone1_t
)conv2(native
,(int)sp
->s_firstdatazone_old
);
259 sp
->s_log_zone_size
= (short) conv2(native
, (int) sp
->s_log_zone_size
);
260 sp
->s_max_size
= (off_t
) conv4(native
, sp
->s_max_size
);
261 sp
->s_zones
= (zone_t
)conv4(native
, sp
->s_zones
);
263 /* In V1, the device size was kept in a short, s_nzones, which limited
264 * devices to 32K zones. For V2, it was decided to keep the size as a
265 * long. However, just changing s_nzones to a long would not work, since
266 * then the position of s_magic in the super block would not be the same
267 * in V1 and V2 file systems, and there would be no way to tell whether
268 * a newly mounted file system was V1 or V2. The solution was to introduce
269 * a new variable, s_zones, and copy the size there.
271 * Calculate some other numbers that depend on the version here too, to
272 * hide some of the differences.
275 sp
->s_block_size
= _STATIC_BLOCK_SIZE
;
276 sp
->s_zones
= (zone_t
) sp
->s_nzones
; /* only V1 needs this copy */
277 sp
->s_inodes_per_block
= V1_INODES_PER_BLOCK
;
278 sp
->s_ndzones
= V1_NR_DZONES
;
279 sp
->s_nindirs
= V1_INDIRECTS
;
282 sp
->s_block_size
= _STATIC_BLOCK_SIZE
;
284 sp
->s_block_size
= (unsigned short)
285 conv2(native
,(int) sp
->s_block_size
);
287 if (sp
->s_block_size
< _MIN_BLOCK_SIZE
) {
290 sp
->s_inodes_per_block
= V2_INODES_PER_BLOCK(sp
->s_block_size
);
291 sp
->s_ndzones
= V2_NR_DZONES
;
292 sp
->s_nindirs
= V2_INDIRECTS(sp
->s_block_size
);
295 /* For even larger disks, a similar problem occurs with s_firstdatazone.
296 * If the on-disk field contains zero, we assume that the value was too
297 * large to fit, and compute it on the fly.
299 if (sp
->s_firstdatazone_old
== 0) {
300 offset
= START_BLOCK
+ sp
->s_imap_blocks
+ sp
->s_zmap_blocks
;
301 offset
+= (sp
->s_ninodes
+ sp
->s_inodes_per_block
- 1) /
302 sp
->s_inodes_per_block
;
304 sp
->s_firstdatazone
= (offset
+ (1 << sp
->s_log_zone_size
) - 1) >>
307 sp
->s_firstdatazone
= (zone_t
) sp
->s_firstdatazone_old
;
310 if (sp
->s_block_size
< _MIN_BLOCK_SIZE
)
313 if ((sp
->s_block_size
% 512) != 0)
316 if (SUPER_SIZE
> sp
->s_block_size
)
319 if ((sp
->s_block_size
% V2_INODE_SIZE
) != 0 ||
320 (sp
->s_block_size
% V1_INODE_SIZE
) != 0) {
324 /* Limit s_max_size to LONG_MAX */
325 if ((unsigned long)sp
->s_max_size
> LONG_MAX
)
326 sp
->s_max_size
= LONG_MAX
;
328 sp
->s_isearch
= 0; /* inode searches initially start at 0 */
329 sp
->s_zsearch
= 0; /* zone searches initially start at 0 */
330 sp
->s_version
= version
;
331 sp
->s_native
= native
;
333 /* Make a few basic checks to see if super block looks reasonable. */
334 if (sp
->s_imap_blocks
< 1 || sp
->s_zmap_blocks
< 1
335 || sp
->s_ninodes
< 1 || sp
->s_zones
< 1
336 || sp
->s_firstdatazone
<= 4
337 || sp
->s_firstdatazone
>= sp
->s_zones
338 || (unsigned) sp
->s_log_zone_size
> 4) {
339 printf("not enough imap or zone map blocks, \n");
340 printf("or not enough inodes, or not enough zones, \n"
341 "or invalid first data zone, or zone size too large\n");
346 /* Check any flags we don't understand but are required to. Currently
347 * these don't exist so all such unknown bits are fatal.
349 if(sp
->s_flags
& MFSFLAG_MANDATORY_MASK
) {
350 printf("MFS: unsupported feature flags on this FS.\n"
351 "Please use a newer MFS to mount it.\n");
358 /*===========================================================================*
360 *===========================================================================*/
361 int write_super(struct super_block
*sp
)
364 panic("can't write superblock of readonly filesystem");
365 return rw_super(sp
, 1);