xref: /minix3/minix/fs/mfs/super.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc /* This file manages the super block table and the related data structures,
2*433d6423SLionel Sambuc  * namely, the bit maps that keep track of which zones and which inodes are
3*433d6423SLionel Sambuc  * allocated and which are free.  When a new inode or zone is needed, the
4*433d6423SLionel Sambuc  * appropriate bit map is searched for a free entry.
5*433d6423SLionel Sambuc  *
6*433d6423SLionel Sambuc  * The entry points into this file are
7*433d6423SLionel Sambuc  *   alloc_bit:       somebody wants to allocate a zone or inode; find one
8*433d6423SLionel Sambuc  *   free_bit:        indicate that a zone or inode is available for allocation
9*433d6423SLionel Sambuc  *   get_super:       search the 'superblock' table for a device
10*433d6423SLionel Sambuc  *   mounted:         tells if file inode is on mounted (or ROOT) file system
11*433d6423SLionel Sambuc  *   read_super:      read a superblock
12*433d6423SLionel Sambuc  */
13*433d6423SLionel Sambuc 
14*433d6423SLionel Sambuc #include "fs.h"
15*433d6423SLionel Sambuc #include <string.h>
16*433d6423SLionel Sambuc #include <assert.h>
17*433d6423SLionel Sambuc #include <minix/com.h>
18*433d6423SLionel Sambuc #include <minix/u64.h>
19*433d6423SLionel Sambuc #include <minix/bdev.h>
20*433d6423SLionel Sambuc #include <machine/param.h>
21*433d6423SLionel Sambuc #include <machine/vmparam.h>
22*433d6423SLionel Sambuc #include "buf.h"
23*433d6423SLionel Sambuc #include "inode.h"
24*433d6423SLionel Sambuc #include "super.h"
25*433d6423SLionel Sambuc #include "const.h"
26*433d6423SLionel Sambuc 
27*433d6423SLionel Sambuc static u32_t used_blocks = 0;
28*433d6423SLionel Sambuc 
29*433d6423SLionel Sambuc /*===========================================================================*
30*433d6423SLionel Sambuc  *				alloc_bit				     *
31*433d6423SLionel Sambuc  *===========================================================================*/
32*433d6423SLionel Sambuc bit_t alloc_bit(sp, map, origin)
33*433d6423SLionel Sambuc struct super_block *sp;		/* the filesystem to allocate from */
34*433d6423SLionel Sambuc int map;			/* IMAP (inode map) or ZMAP (zone map) */
35*433d6423SLionel Sambuc bit_t origin;			/* number of bit to start searching at */
36*433d6423SLionel Sambuc {
37*433d6423SLionel Sambuc /* Allocate a bit from a bit map and return its bit number. */
38*433d6423SLionel Sambuc 
39*433d6423SLionel Sambuc   block_t start_block;		/* first bit block */
40*433d6423SLionel Sambuc   block_t block;
41*433d6423SLionel Sambuc   bit_t map_bits;		/* how many bits are there in the bit map? */
42*433d6423SLionel Sambuc   short bit_blocks;		/* how many blocks are there in the bit map? */
43*433d6423SLionel Sambuc   unsigned word, bcount;
44*433d6423SLionel Sambuc   struct buf *bp;
45*433d6423SLionel Sambuc   bitchunk_t *wptr, *wlim, k;
46*433d6423SLionel Sambuc   bit_t i, b;
47*433d6423SLionel Sambuc 
48*433d6423SLionel Sambuc   if (sp->s_rd_only)
49*433d6423SLionel Sambuc 	panic("can't allocate bit on read-only filesys");
50*433d6423SLionel Sambuc 
51*433d6423SLionel Sambuc   if (map == IMAP) {
52*433d6423SLionel Sambuc 	start_block = START_BLOCK;
53*433d6423SLionel Sambuc 	map_bits = (bit_t) (sp->s_ninodes + 1);
54*433d6423SLionel Sambuc 	bit_blocks = sp->s_imap_blocks;
55*433d6423SLionel Sambuc   } else {
56*433d6423SLionel Sambuc 	start_block = START_BLOCK + sp->s_imap_blocks;
57*433d6423SLionel Sambuc 	map_bits = (bit_t) (sp->s_zones - (sp->s_firstdatazone - 1));
58*433d6423SLionel Sambuc 	bit_blocks = sp->s_zmap_blocks;
59*433d6423SLionel Sambuc   }
60*433d6423SLionel Sambuc 
61*433d6423SLionel Sambuc   /* Figure out where to start the bit search (depends on 'origin'). */
62*433d6423SLionel Sambuc   if (origin >= map_bits) origin = 0;	/* for robustness */
63*433d6423SLionel Sambuc 
64*433d6423SLionel Sambuc   /* Locate the starting place. */
65*433d6423SLionel Sambuc   block = (block_t) (origin / FS_BITS_PER_BLOCK(sp->s_block_size));
66*433d6423SLionel Sambuc   word = (origin % FS_BITS_PER_BLOCK(sp->s_block_size)) / FS_BITCHUNK_BITS;
67*433d6423SLionel Sambuc 
68*433d6423SLionel Sambuc   /* Iterate over all blocks plus one, because we start in the middle. */
69*433d6423SLionel Sambuc   bcount = bit_blocks + 1;
70*433d6423SLionel Sambuc   do {
71*433d6423SLionel Sambuc 	bp = get_block(sp->s_dev, start_block + block, NORMAL);
72*433d6423SLionel Sambuc 	wlim = &b_bitmap(bp)[FS_BITMAP_CHUNKS(sp->s_block_size)];
73*433d6423SLionel Sambuc 
74*433d6423SLionel Sambuc 	/* Iterate over the words in block. */
75*433d6423SLionel Sambuc 	for (wptr = &b_bitmap(bp)[word]; wptr < wlim; wptr++) {
76*433d6423SLionel Sambuc 
77*433d6423SLionel Sambuc 		/* Does this word contain a free bit? */
78*433d6423SLionel Sambuc 		if (*wptr == (bitchunk_t) ~0) continue;
79*433d6423SLionel Sambuc 
80*433d6423SLionel Sambuc 		/* Find and allocate the free bit. */
81*433d6423SLionel Sambuc 		k = (bitchunk_t) conv4(sp->s_native, (int) *wptr);
82*433d6423SLionel Sambuc 		for (i = 0; (k & (1 << i)) != 0; ++i) {}
83*433d6423SLionel Sambuc 
84*433d6423SLionel Sambuc 		/* Bit number from the start of the bit map. */
85*433d6423SLionel Sambuc 		b = ((bit_t) block * FS_BITS_PER_BLOCK(sp->s_block_size))
86*433d6423SLionel Sambuc 		    + (wptr - &b_bitmap(bp)[0]) * FS_BITCHUNK_BITS
87*433d6423SLionel Sambuc 		    + i;
88*433d6423SLionel Sambuc 
89*433d6423SLionel Sambuc 		/* Don't allocate bits beyond the end of the map. */
90*433d6423SLionel Sambuc 		if (b >= map_bits) break;
91*433d6423SLionel Sambuc 
92*433d6423SLionel Sambuc 		/* Allocate and return bit number. */
93*433d6423SLionel Sambuc 		k |= 1 << i;
94*433d6423SLionel Sambuc 		*wptr = (bitchunk_t) conv4(sp->s_native, (int) k);
95*433d6423SLionel Sambuc 		MARKDIRTY(bp);
96*433d6423SLionel Sambuc 		put_block(bp, MAP_BLOCK);
97*433d6423SLionel Sambuc 		if(map == ZMAP) {
98*433d6423SLionel Sambuc 			used_blocks++;
99*433d6423SLionel Sambuc 			lmfs_blockschange(sp->s_dev, 1);
100*433d6423SLionel Sambuc 		}
101*433d6423SLionel Sambuc 		return(b);
102*433d6423SLionel Sambuc 	}
103*433d6423SLionel Sambuc 	put_block(bp, MAP_BLOCK);
104*433d6423SLionel Sambuc 	if (++block >= (unsigned int) bit_blocks) /* last block, wrap around */
105*433d6423SLionel Sambuc 		block = 0;
106*433d6423SLionel Sambuc 	word = 0;
107*433d6423SLionel Sambuc   } while (--bcount > 0);
108*433d6423SLionel Sambuc   return(NO_BIT);		/* no bit could be allocated */
109*433d6423SLionel Sambuc }
110*433d6423SLionel Sambuc 
111*433d6423SLionel Sambuc /*===========================================================================*
112*433d6423SLionel Sambuc  *				free_bit				     *
113*433d6423SLionel Sambuc  *===========================================================================*/
114*433d6423SLionel Sambuc void free_bit(sp, map, bit_returned)
115*433d6423SLionel Sambuc struct super_block *sp;		/* the filesystem to operate on */
116*433d6423SLionel Sambuc int map;			/* IMAP (inode map) or ZMAP (zone map) */
117*433d6423SLionel Sambuc bit_t bit_returned;		/* number of bit to insert into the map */
118*433d6423SLionel Sambuc {
119*433d6423SLionel Sambuc /* Return a zone or inode by turning off its bitmap bit. */
120*433d6423SLionel Sambuc 
121*433d6423SLionel Sambuc   unsigned block, word, bit;
122*433d6423SLionel Sambuc   struct buf *bp;
123*433d6423SLionel Sambuc   bitchunk_t k, mask;
124*433d6423SLionel Sambuc   block_t start_block;
125*433d6423SLionel Sambuc 
126*433d6423SLionel Sambuc   if (sp->s_rd_only)
127*433d6423SLionel Sambuc 	panic("can't free bit on read-only filesys");
128*433d6423SLionel Sambuc 
129*433d6423SLionel Sambuc   if (map == IMAP) {
130*433d6423SLionel Sambuc 	start_block = START_BLOCK;
131*433d6423SLionel Sambuc   } else {
132*433d6423SLionel Sambuc 	start_block = START_BLOCK + sp->s_imap_blocks;
133*433d6423SLionel Sambuc   }
134*433d6423SLionel Sambuc   block = bit_returned / FS_BITS_PER_BLOCK(sp->s_block_size);
135*433d6423SLionel Sambuc   word = (bit_returned % FS_BITS_PER_BLOCK(sp->s_block_size))
136*433d6423SLionel Sambuc   	 / FS_BITCHUNK_BITS;
137*433d6423SLionel Sambuc 
138*433d6423SLionel Sambuc   bit = bit_returned % FS_BITCHUNK_BITS;
139*433d6423SLionel Sambuc   mask = 1 << bit;
140*433d6423SLionel Sambuc 
141*433d6423SLionel Sambuc   bp = get_block(sp->s_dev, start_block + block, NORMAL);
142*433d6423SLionel Sambuc 
143*433d6423SLionel Sambuc   k = (bitchunk_t) conv4(sp->s_native, (int) b_bitmap(bp)[word]);
144*433d6423SLionel Sambuc   if (!(k & mask)) {
145*433d6423SLionel Sambuc   	if (map == IMAP) panic("tried to free unused inode");
146*433d6423SLionel Sambuc   	else panic("tried to free unused block: %u", bit_returned);
147*433d6423SLionel Sambuc   }
148*433d6423SLionel Sambuc 
149*433d6423SLionel Sambuc   k &= ~mask;
150*433d6423SLionel Sambuc   b_bitmap(bp)[word] = (bitchunk_t) conv4(sp->s_native, (int) k);
151*433d6423SLionel Sambuc   MARKDIRTY(bp);
152*433d6423SLionel Sambuc 
153*433d6423SLionel Sambuc   put_block(bp, MAP_BLOCK);
154*433d6423SLionel Sambuc 
155*433d6423SLionel Sambuc   if(map == ZMAP) {
156*433d6423SLionel Sambuc 	used_blocks--;
157*433d6423SLionel Sambuc 	lmfs_blockschange(sp->s_dev, -1);
158*433d6423SLionel Sambuc   }
159*433d6423SLionel Sambuc }
160*433d6423SLionel Sambuc 
161*433d6423SLionel Sambuc /*===========================================================================*
162*433d6423SLionel Sambuc  *				get_super				     *
163*433d6423SLionel Sambuc  *===========================================================================*/
164*433d6423SLionel Sambuc struct super_block *get_super(
165*433d6423SLionel Sambuc   dev_t dev			/* device number whose super_block is sought */
166*433d6423SLionel Sambuc )
167*433d6423SLionel Sambuc {
168*433d6423SLionel Sambuc   if (dev == NO_DEV)
169*433d6423SLionel Sambuc   	panic("request for super_block of NO_DEV");
170*433d6423SLionel Sambuc 
171*433d6423SLionel Sambuc   if(superblock.s_dev != dev)
172*433d6423SLionel Sambuc   	panic("wrong superblock: 0x%x", (int) dev);
173*433d6423SLionel Sambuc 
174*433d6423SLionel Sambuc   return(&superblock);
175*433d6423SLionel Sambuc }
176*433d6423SLionel Sambuc 
177*433d6423SLionel Sambuc 
178*433d6423SLionel Sambuc /*===========================================================================*
179*433d6423SLionel Sambuc  *				get_block_size				     *
180*433d6423SLionel Sambuc  *===========================================================================*/
181*433d6423SLionel Sambuc unsigned int get_block_size(dev_t dev)
182*433d6423SLionel Sambuc {
183*433d6423SLionel Sambuc   if (dev == NO_DEV)
184*433d6423SLionel Sambuc   	panic("request for block size of NO_DEV");
185*433d6423SLionel Sambuc 
186*433d6423SLionel Sambuc   return(lmfs_fs_block_size());
187*433d6423SLionel Sambuc }
188*433d6423SLionel Sambuc 
189*433d6423SLionel Sambuc 
190*433d6423SLionel Sambuc /*===========================================================================*
191*433d6423SLionel Sambuc  *				rw_super				     *
192*433d6423SLionel Sambuc  *===========================================================================*/
193*433d6423SLionel Sambuc static int rw_super(struct super_block *sp, int writing)
194*433d6423SLionel Sambuc {
195*433d6423SLionel Sambuc /* Read/write a superblock. */
196*433d6423SLionel Sambuc   int r;
197*433d6423SLionel Sambuc   dev_t save_dev = sp->s_dev;
198*433d6423SLionel Sambuc   struct buf *bp;
199*433d6423SLionel Sambuc   char *sbbuf;
200*433d6423SLionel Sambuc 
201*433d6423SLionel Sambuc /* To keep the 1kb on disk clean, only read/write up to and including
202*433d6423SLionel Sambuc  * this field.
203*433d6423SLionel Sambuc  */
204*433d6423SLionel Sambuc #define LAST_ONDISK_FIELD s_disk_version
205*433d6423SLionel Sambuc   int ondisk_bytes = (int) ((char *) &sp->LAST_ONDISK_FIELD - (char *) sp)
206*433d6423SLionel Sambuc   	+ sizeof(sp->LAST_ONDISK_FIELD);
207*433d6423SLionel Sambuc 
208*433d6423SLionel Sambuc   assert(ondisk_bytes > 0);
209*433d6423SLionel Sambuc   assert(ondisk_bytes < PAGE_SIZE);
210*433d6423SLionel Sambuc   assert(ondisk_bytes < sizeof(struct super_block));
211*433d6423SLionel Sambuc 
212*433d6423SLionel Sambuc   if (sp->s_dev == NO_DEV)
213*433d6423SLionel Sambuc   	panic("request for super_block of NO_DEV");
214*433d6423SLionel Sambuc 
215*433d6423SLionel Sambuc   /* we rely on the cache blocksize, before reading the
216*433d6423SLionel Sambuc    * superblock, being big enough that our complete superblock
217*433d6423SLionel Sambuc    * is in block 0.
218*433d6423SLionel Sambuc    *
219*433d6423SLionel Sambuc    * copy between the disk block and the superblock buffer (depending
220*433d6423SLionel Sambuc    * on direction). mark the disk block dirty if the copy is into the
221*433d6423SLionel Sambuc    * disk block.
222*433d6423SLionel Sambuc    */
223*433d6423SLionel Sambuc   assert(lmfs_fs_block_size() >= sizeof(struct super_block) + SUPER_BLOCK_BYTES);
224*433d6423SLionel Sambuc   assert(SUPER_BLOCK_BYTES >= sizeof(struct super_block));
225*433d6423SLionel Sambuc   assert(SUPER_BLOCK_BYTES >= ondisk_bytes);
226*433d6423SLionel Sambuc   if(!(bp = get_block(sp->s_dev, 0, NORMAL)))
227*433d6423SLionel Sambuc   	panic("get_block of superblock failed");
228*433d6423SLionel Sambuc 
229*433d6423SLionel Sambuc   /* sbbuf points to the disk block at the superblock offset */
230*433d6423SLionel Sambuc   sbbuf = (char *) b_data(bp) + SUPER_BLOCK_BYTES;
231*433d6423SLionel Sambuc 
232*433d6423SLionel Sambuc   if(writing) {
233*433d6423SLionel Sambuc   	memset(b_data(bp), 0, lmfs_fs_block_size());
234*433d6423SLionel Sambuc   	memcpy(sbbuf, sp, ondisk_bytes);
235*433d6423SLionel Sambuc 	lmfs_markdirty(bp);
236*433d6423SLionel Sambuc   } else {
237*433d6423SLionel Sambuc 	memset(sp, 0, sizeof(*sp));
238*433d6423SLionel Sambuc   	memcpy(sp, sbbuf, ondisk_bytes);
239*433d6423SLionel Sambuc   	sp->s_dev = save_dev;
240*433d6423SLionel Sambuc   }
241*433d6423SLionel Sambuc 
242*433d6423SLionel Sambuc   put_block(bp, FULL_DATA_BLOCK);
243*433d6423SLionel Sambuc   lmfs_flushall();
244*433d6423SLionel Sambuc 
245*433d6423SLionel Sambuc   return OK;
246*433d6423SLionel Sambuc }
247*433d6423SLionel Sambuc 
248*433d6423SLionel Sambuc /*===========================================================================*
249*433d6423SLionel Sambuc  *				read_super				     *
250*433d6423SLionel Sambuc  *===========================================================================*/
251*433d6423SLionel Sambuc int read_super(struct super_block *sp)
252*433d6423SLionel Sambuc {
253*433d6423SLionel Sambuc   unsigned int magic;
254*433d6423SLionel Sambuc   block_t offset;
255*433d6423SLionel Sambuc   int version, native, r;
256*433d6423SLionel Sambuc 
257*433d6423SLionel Sambuc   if((r=rw_super(sp, 0)) != OK)
258*433d6423SLionel Sambuc   	return r;
259*433d6423SLionel Sambuc 
260*433d6423SLionel Sambuc   magic = sp->s_magic;		/* determines file system type */
261*433d6423SLionel Sambuc 
262*433d6423SLionel Sambuc   if(magic == SUPER_V2 || magic == SUPER_MAGIC) {
263*433d6423SLionel Sambuc 	printf("MFS: only supports V3 filesystems.\n");
264*433d6423SLionel Sambuc 	return EINVAL;
265*433d6423SLionel Sambuc   }
266*433d6423SLionel Sambuc 
267*433d6423SLionel Sambuc   /* Get file system version and type - only support v3. */
268*433d6423SLionel Sambuc   if(magic != SUPER_V3) {
269*433d6423SLionel Sambuc 	return EINVAL;
270*433d6423SLionel Sambuc   }
271*433d6423SLionel Sambuc   version = V3;
272*433d6423SLionel Sambuc   native = 1;
273*433d6423SLionel Sambuc 
274*433d6423SLionel Sambuc   /* If the super block has the wrong byte order, swap the fields; the magic
275*433d6423SLionel Sambuc    * number doesn't need conversion. */
276*433d6423SLionel Sambuc   sp->s_ninodes =           (ino_t) conv4(native, (int) sp->s_ninodes);
277*433d6423SLionel Sambuc   sp->s_nzones =          (zone1_t) conv2(native, (int) sp->s_nzones);
278*433d6423SLionel Sambuc   sp->s_imap_blocks =       (short) conv2(native, (int) sp->s_imap_blocks);
279*433d6423SLionel Sambuc   sp->s_zmap_blocks =       (short) conv2(native, (int) sp->s_zmap_blocks);
280*433d6423SLionel Sambuc   sp->s_firstdatazone_old =(zone1_t)conv2(native,(int)sp->s_firstdatazone_old);
281*433d6423SLionel Sambuc   sp->s_log_zone_size =     (short) conv2(native, (int) sp->s_log_zone_size);
282*433d6423SLionel Sambuc   sp->s_max_size =          (off_t) conv4(native, sp->s_max_size);
283*433d6423SLionel Sambuc   sp->s_zones =             (zone_t)conv4(native, sp->s_zones);
284*433d6423SLionel Sambuc 
285*433d6423SLionel Sambuc   /* Calculate some other numbers that depend on the version here too, to
286*433d6423SLionel Sambuc    * hide some of the differences.
287*433d6423SLionel Sambuc    */
288*433d6423SLionel Sambuc   assert(version == V3);
289*433d6423SLionel Sambuc   sp->s_block_size = (unsigned short) conv2(native,(int) sp->s_block_size);
290*433d6423SLionel Sambuc   if (sp->s_block_size < PAGE_SIZE) {
291*433d6423SLionel Sambuc  	return EINVAL;
292*433d6423SLionel Sambuc   }
293*433d6423SLionel Sambuc   sp->s_inodes_per_block = V2_INODES_PER_BLOCK(sp->s_block_size);
294*433d6423SLionel Sambuc   sp->s_ndzones = V2_NR_DZONES;
295*433d6423SLionel Sambuc   sp->s_nindirs = V2_INDIRECTS(sp->s_block_size);
296*433d6423SLionel Sambuc 
297*433d6423SLionel Sambuc   /* For even larger disks, a similar problem occurs with s_firstdatazone.
298*433d6423SLionel Sambuc    * If the on-disk field contains zero, we assume that the value was too
299*433d6423SLionel Sambuc    * large to fit, and compute it on the fly.
300*433d6423SLionel Sambuc    */
301*433d6423SLionel Sambuc   if (sp->s_firstdatazone_old == 0) {
302*433d6423SLionel Sambuc 	offset = START_BLOCK + sp->s_imap_blocks + sp->s_zmap_blocks;
303*433d6423SLionel Sambuc 	offset += (sp->s_ninodes + sp->s_inodes_per_block - 1) /
304*433d6423SLionel Sambuc 		sp->s_inodes_per_block;
305*433d6423SLionel Sambuc 
306*433d6423SLionel Sambuc 	sp->s_firstdatazone = (offset + (1 << sp->s_log_zone_size) - 1) >>
307*433d6423SLionel Sambuc 		sp->s_log_zone_size;
308*433d6423SLionel Sambuc   } else {
309*433d6423SLionel Sambuc 	sp->s_firstdatazone = (zone_t) sp->s_firstdatazone_old;
310*433d6423SLionel Sambuc   }
311*433d6423SLionel Sambuc 
312*433d6423SLionel Sambuc   if (sp->s_block_size < PAGE_SIZE)
313*433d6423SLionel Sambuc   	return(EINVAL);
314*433d6423SLionel Sambuc 
315*433d6423SLionel Sambuc   if ((sp->s_block_size % 512) != 0)
316*433d6423SLionel Sambuc   	return(EINVAL);
317*433d6423SLionel Sambuc 
318*433d6423SLionel Sambuc   if (SUPER_SIZE > sp->s_block_size)
319*433d6423SLionel Sambuc   	return(EINVAL);
320*433d6423SLionel Sambuc 
321*433d6423SLionel Sambuc   if ((sp->s_block_size % V2_INODE_SIZE) != 0) {
322*433d6423SLionel Sambuc   	return(EINVAL);
323*433d6423SLionel Sambuc   }
324*433d6423SLionel Sambuc 
325*433d6423SLionel Sambuc   /* Limit s_max_size to LONG_MAX */
326*433d6423SLionel Sambuc   if ((unsigned long)sp->s_max_size > LONG_MAX)
327*433d6423SLionel Sambuc 	sp->s_max_size = LONG_MAX;
328*433d6423SLionel Sambuc 
329*433d6423SLionel Sambuc   sp->s_isearch = 0;		/* inode searches initially start at 0 */
330*433d6423SLionel Sambuc   sp->s_zsearch = 0;		/* zone searches initially start at 0 */
331*433d6423SLionel Sambuc   sp->s_version = version;
332*433d6423SLionel Sambuc   sp->s_native  = native;
333*433d6423SLionel Sambuc 
334*433d6423SLionel Sambuc   /* Make a few basic checks to see if super block looks reasonable. */
335*433d6423SLionel Sambuc   if (sp->s_imap_blocks < 1 || sp->s_zmap_blocks < 1
336*433d6423SLionel Sambuc 				|| sp->s_ninodes < 1 || sp->s_zones < 1
337*433d6423SLionel Sambuc 				|| sp->s_firstdatazone <= 4
338*433d6423SLionel Sambuc 				|| sp->s_firstdatazone >= sp->s_zones
339*433d6423SLionel Sambuc 				|| (unsigned) sp->s_log_zone_size > 4) {
340*433d6423SLionel Sambuc   	printf("not enough imap or zone map blocks, \n");
341*433d6423SLionel Sambuc   	printf("or not enough inodes, or not enough zones, \n"
342*433d6423SLionel Sambuc   		"or invalid first data zone, or zone size too large\n");
343*433d6423SLionel Sambuc 	return(EINVAL);
344*433d6423SLionel Sambuc   }
345*433d6423SLionel Sambuc 
346*433d6423SLionel Sambuc 
347*433d6423SLionel Sambuc   /* Check any flags we don't understand but are required to. Currently
348*433d6423SLionel Sambuc    * these don't exist so all such unknown bits are fatal.
349*433d6423SLionel Sambuc    */
350*433d6423SLionel Sambuc   if(sp->s_flags & MFSFLAG_MANDATORY_MASK) {
351*433d6423SLionel Sambuc   	printf("MFS: unsupported feature flags on this FS.\n"
352*433d6423SLionel Sambuc 		"Please use a newer MFS to mount it.\n");
353*433d6423SLionel Sambuc 	return(EINVAL);
354*433d6423SLionel Sambuc   }
355*433d6423SLionel Sambuc 
356*433d6423SLionel Sambuc   return(OK);
357*433d6423SLionel Sambuc }
358*433d6423SLionel Sambuc 
359*433d6423SLionel Sambuc /*===========================================================================*
360*433d6423SLionel Sambuc  *				write_super				     *
361*433d6423SLionel Sambuc  *===========================================================================*/
362*433d6423SLionel Sambuc int write_super(struct super_block *sp)
363*433d6423SLionel Sambuc {
364*433d6423SLionel Sambuc   if(sp->s_rd_only)
365*433d6423SLionel Sambuc   	panic("can't write superblock of readonly filesystem");
366*433d6423SLionel Sambuc   return rw_super(sp, 1);
367*433d6423SLionel Sambuc }
368*433d6423SLionel Sambuc 
369*433d6423SLionel Sambuc static int blocks_known = 0;
370*433d6423SLionel Sambuc 
371*433d6423SLionel Sambuc u32_t get_used_blocks(struct super_block *sp)
372*433d6423SLionel Sambuc {
373*433d6423SLionel Sambuc 	if(!blocks_known)  {
374*433d6423SLionel Sambuc 		/* how many blocks are in use? */
375*433d6423SLionel Sambuc 		used_blocks = sp->s_zones - count_free_bits(sp, ZMAP);
376*433d6423SLionel Sambuc 		blocks_known = 1;
377*433d6423SLionel Sambuc 	}
378*433d6423SLionel Sambuc 	return used_blocks;
379*433d6423SLionel Sambuc }
380