xref: /minix3/minix/fs/mfs/super.c (revision 0314acfb2d68447dfa1b0b33aa4c25b1cbfa85d3)
1433d6423SLionel Sambuc /* This file manages the super block table and the related data structures,
2433d6423SLionel Sambuc  * namely, the bit maps that keep track of which zones and which inodes are
3433d6423SLionel Sambuc  * allocated and which are free.  When a new inode or zone is needed, the
4433d6423SLionel Sambuc  * appropriate bit map is searched for a free entry.
5433d6423SLionel Sambuc  *
6433d6423SLionel Sambuc  * The entry points into this file are
7433d6423SLionel Sambuc  *   alloc_bit:       somebody wants to allocate a zone or inode; find one
8433d6423SLionel Sambuc  *   free_bit:        indicate that a zone or inode is available for allocation
9433d6423SLionel Sambuc  *   get_super:       search the 'superblock' table for a device
10433d6423SLionel Sambuc  *   mounted:         tells if file inode is on mounted (or ROOT) file system
11433d6423SLionel Sambuc  *   read_super:      read a superblock
12433d6423SLionel Sambuc  */
13433d6423SLionel Sambuc 
14433d6423SLionel Sambuc #include "fs.h"
15433d6423SLionel Sambuc #include <string.h>
16433d6423SLionel Sambuc #include <assert.h>
17433d6423SLionel Sambuc #include <minix/com.h>
18433d6423SLionel Sambuc #include <minix/u64.h>
19433d6423SLionel Sambuc #include <minix/bdev.h>
20433d6423SLionel Sambuc #include <machine/param.h>
21433d6423SLionel Sambuc #include <machine/vmparam.h>
22433d6423SLionel Sambuc #include "buf.h"
23433d6423SLionel Sambuc #include "inode.h"
24433d6423SLionel Sambuc #include "super.h"
25433d6423SLionel Sambuc #include "const.h"
26433d6423SLionel Sambuc 
27433d6423SLionel Sambuc static u32_t used_blocks = 0;
28433d6423SLionel Sambuc 
29433d6423SLionel Sambuc /*===========================================================================*
30433d6423SLionel Sambuc  *				alloc_bit				     *
31433d6423SLionel Sambuc  *===========================================================================*/
32433d6423SLionel Sambuc bit_t alloc_bit(sp, map, origin)
33433d6423SLionel Sambuc struct super_block *sp;		/* the filesystem to allocate from */
34433d6423SLionel Sambuc int map;			/* IMAP (inode map) or ZMAP (zone map) */
35433d6423SLionel Sambuc bit_t origin;			/* number of bit to start searching at */
36433d6423SLionel Sambuc {
37433d6423SLionel Sambuc /* Allocate a bit from a bit map and return its bit number. */
38433d6423SLionel Sambuc 
39433d6423SLionel Sambuc   block_t start_block;		/* first bit block */
40433d6423SLionel Sambuc   block_t block;
41433d6423SLionel Sambuc   bit_t map_bits;		/* how many bits are there in the bit map? */
42433d6423SLionel Sambuc   short bit_blocks;		/* how many blocks are there in the bit map? */
43433d6423SLionel Sambuc   unsigned word, bcount;
44433d6423SLionel Sambuc   struct buf *bp;
45433d6423SLionel Sambuc   bitchunk_t *wptr, *wlim, k;
46433d6423SLionel Sambuc   bit_t i, b;
47433d6423SLionel Sambuc 
48433d6423SLionel Sambuc   if (sp->s_rd_only)
49433d6423SLionel Sambuc 	panic("can't allocate bit on read-only filesys");
50433d6423SLionel Sambuc 
51433d6423SLionel Sambuc   if (map == IMAP) {
52433d6423SLionel Sambuc 	start_block = START_BLOCK;
53433d6423SLionel Sambuc 	map_bits = (bit_t) (sp->s_ninodes + 1);
54433d6423SLionel Sambuc 	bit_blocks = sp->s_imap_blocks;
55433d6423SLionel Sambuc   } else {
56433d6423SLionel Sambuc 	start_block = START_BLOCK + sp->s_imap_blocks;
57433d6423SLionel Sambuc 	map_bits = (bit_t) (sp->s_zones - (sp->s_firstdatazone - 1));
58433d6423SLionel Sambuc 	bit_blocks = sp->s_zmap_blocks;
59433d6423SLionel Sambuc   }
60433d6423SLionel Sambuc 
61433d6423SLionel Sambuc   /* Figure out where to start the bit search (depends on 'origin'). */
62433d6423SLionel Sambuc   if (origin >= map_bits) origin = 0;	/* for robustness */
63433d6423SLionel Sambuc 
64433d6423SLionel Sambuc   /* Locate the starting place. */
65433d6423SLionel Sambuc   block = (block_t) (origin / FS_BITS_PER_BLOCK(sp->s_block_size));
66433d6423SLionel Sambuc   word = (origin % FS_BITS_PER_BLOCK(sp->s_block_size)) / FS_BITCHUNK_BITS;
67433d6423SLionel Sambuc 
68433d6423SLionel Sambuc   /* Iterate over all blocks plus one, because we start in the middle. */
69433d6423SLionel Sambuc   bcount = bit_blocks + 1;
70433d6423SLionel Sambuc   do {
71433d6423SLionel Sambuc 	bp = get_block(sp->s_dev, start_block + block, NORMAL);
72433d6423SLionel Sambuc 	wlim = &b_bitmap(bp)[FS_BITMAP_CHUNKS(sp->s_block_size)];
73433d6423SLionel Sambuc 
74433d6423SLionel Sambuc 	/* Iterate over the words in block. */
75433d6423SLionel Sambuc 	for (wptr = &b_bitmap(bp)[word]; wptr < wlim; wptr++) {
76433d6423SLionel Sambuc 
77433d6423SLionel Sambuc 		/* Does this word contain a free bit? */
78433d6423SLionel Sambuc 		if (*wptr == (bitchunk_t) ~0) continue;
79433d6423SLionel Sambuc 
80433d6423SLionel Sambuc 		/* Find and allocate the free bit. */
81433d6423SLionel Sambuc 		k = (bitchunk_t) conv4(sp->s_native, (int) *wptr);
82433d6423SLionel Sambuc 		for (i = 0; (k & (1 << i)) != 0; ++i) {}
83433d6423SLionel Sambuc 
84433d6423SLionel Sambuc 		/* Bit number from the start of the bit map. */
85433d6423SLionel Sambuc 		b = ((bit_t) block * FS_BITS_PER_BLOCK(sp->s_block_size))
86433d6423SLionel Sambuc 		    + (wptr - &b_bitmap(bp)[0]) * FS_BITCHUNK_BITS
87433d6423SLionel Sambuc 		    + i;
88433d6423SLionel Sambuc 
89433d6423SLionel Sambuc 		/* Don't allocate bits beyond the end of the map. */
90433d6423SLionel Sambuc 		if (b >= map_bits) break;
91433d6423SLionel Sambuc 
92433d6423SLionel Sambuc 		/* Allocate and return bit number. */
93433d6423SLionel Sambuc 		k |= 1 << i;
94433d6423SLionel Sambuc 		*wptr = (bitchunk_t) conv4(sp->s_native, (int) k);
95433d6423SLionel Sambuc 		MARKDIRTY(bp);
96*0314acfbSDavid van Moolenbroek 		put_block(bp);
97433d6423SLionel Sambuc 		if(map == ZMAP) {
98433d6423SLionel Sambuc 			used_blocks++;
99*0314acfbSDavid van Moolenbroek 			lmfs_blockschange(1);
100433d6423SLionel Sambuc 		}
101433d6423SLionel Sambuc 		return(b);
102433d6423SLionel Sambuc 	}
103*0314acfbSDavid van Moolenbroek 	put_block(bp);
104433d6423SLionel Sambuc 	if (++block >= (unsigned int) bit_blocks) /* last block, wrap around */
105433d6423SLionel Sambuc 		block = 0;
106433d6423SLionel Sambuc 	word = 0;
107433d6423SLionel Sambuc   } while (--bcount > 0);
108433d6423SLionel Sambuc   return(NO_BIT);		/* no bit could be allocated */
109433d6423SLionel Sambuc }
110433d6423SLionel Sambuc 
111433d6423SLionel Sambuc /*===========================================================================*
112433d6423SLionel Sambuc  *				free_bit				     *
113433d6423SLionel Sambuc  *===========================================================================*/
114433d6423SLionel Sambuc void free_bit(sp, map, bit_returned)
115433d6423SLionel Sambuc struct super_block *sp;		/* the filesystem to operate on */
116433d6423SLionel Sambuc int map;			/* IMAP (inode map) or ZMAP (zone map) */
117433d6423SLionel Sambuc bit_t bit_returned;		/* number of bit to insert into the map */
118433d6423SLionel Sambuc {
119433d6423SLionel Sambuc /* Return a zone or inode by turning off its bitmap bit. */
120433d6423SLionel Sambuc 
121433d6423SLionel Sambuc   unsigned block, word, bit;
122433d6423SLionel Sambuc   struct buf *bp;
123433d6423SLionel Sambuc   bitchunk_t k, mask;
124433d6423SLionel Sambuc   block_t start_block;
125433d6423SLionel Sambuc 
126433d6423SLionel Sambuc   if (sp->s_rd_only)
127433d6423SLionel Sambuc 	panic("can't free bit on read-only filesys");
128433d6423SLionel Sambuc 
129433d6423SLionel Sambuc   if (map == IMAP) {
130433d6423SLionel Sambuc 	start_block = START_BLOCK;
131433d6423SLionel Sambuc   } else {
132433d6423SLionel Sambuc 	start_block = START_BLOCK + sp->s_imap_blocks;
133433d6423SLionel Sambuc   }
134433d6423SLionel Sambuc   block = bit_returned / FS_BITS_PER_BLOCK(sp->s_block_size);
135433d6423SLionel Sambuc   word = (bit_returned % FS_BITS_PER_BLOCK(sp->s_block_size))
136433d6423SLionel Sambuc   	 / FS_BITCHUNK_BITS;
137433d6423SLionel Sambuc 
138433d6423SLionel Sambuc   bit = bit_returned % FS_BITCHUNK_BITS;
139433d6423SLionel Sambuc   mask = 1 << bit;
140433d6423SLionel Sambuc 
141433d6423SLionel Sambuc   bp = get_block(sp->s_dev, start_block + block, NORMAL);
142433d6423SLionel Sambuc 
143433d6423SLionel Sambuc   k = (bitchunk_t) conv4(sp->s_native, (int) b_bitmap(bp)[word]);
144433d6423SLionel Sambuc   if (!(k & mask)) {
145433d6423SLionel Sambuc   	if (map == IMAP) panic("tried to free unused inode");
146433d6423SLionel Sambuc   	else panic("tried to free unused block: %u", bit_returned);
147433d6423SLionel Sambuc   }
148433d6423SLionel Sambuc 
149433d6423SLionel Sambuc   k &= ~mask;
150433d6423SLionel Sambuc   b_bitmap(bp)[word] = (bitchunk_t) conv4(sp->s_native, (int) k);
151433d6423SLionel Sambuc   MARKDIRTY(bp);
152433d6423SLionel Sambuc 
153*0314acfbSDavid van Moolenbroek   put_block(bp);
154433d6423SLionel Sambuc 
155433d6423SLionel Sambuc   if(map == ZMAP) {
156433d6423SLionel Sambuc 	used_blocks--;
157*0314acfbSDavid van Moolenbroek 	lmfs_blockschange(-1);
158433d6423SLionel Sambuc   }
159433d6423SLionel Sambuc }
160433d6423SLionel Sambuc 
161433d6423SLionel Sambuc /*===========================================================================*
162433d6423SLionel Sambuc  *				get_super				     *
163433d6423SLionel Sambuc  *===========================================================================*/
164433d6423SLionel Sambuc struct super_block *get_super(
165433d6423SLionel Sambuc   dev_t dev			/* device number whose super_block is sought */
166433d6423SLionel Sambuc )
167433d6423SLionel Sambuc {
168433d6423SLionel Sambuc   if (dev == NO_DEV)
169433d6423SLionel Sambuc   	panic("request for super_block of NO_DEV");
170433d6423SLionel Sambuc 
171433d6423SLionel Sambuc   if(superblock.s_dev != dev)
172433d6423SLionel Sambuc   	panic("wrong superblock: 0x%x", (int) dev);
173433d6423SLionel Sambuc 
174433d6423SLionel Sambuc   return(&superblock);
175433d6423SLionel Sambuc }
176433d6423SLionel Sambuc 
177433d6423SLionel Sambuc 
178433d6423SLionel Sambuc /*===========================================================================*
179433d6423SLionel Sambuc  *				get_block_size				     *
180433d6423SLionel Sambuc  *===========================================================================*/
181433d6423SLionel Sambuc unsigned int get_block_size(dev_t dev)
182433d6423SLionel Sambuc {
183433d6423SLionel Sambuc   if (dev == NO_DEV)
184433d6423SLionel Sambuc   	panic("request for block size of NO_DEV");
185433d6423SLionel Sambuc 
186433d6423SLionel Sambuc   return(lmfs_fs_block_size());
187433d6423SLionel Sambuc }
188433d6423SLionel Sambuc 
189433d6423SLionel Sambuc 
190433d6423SLionel Sambuc /*===========================================================================*
191433d6423SLionel Sambuc  *				rw_super				     *
192433d6423SLionel Sambuc  *===========================================================================*/
193433d6423SLionel Sambuc static int rw_super(struct super_block *sp, int writing)
194433d6423SLionel Sambuc {
195433d6423SLionel Sambuc /* Read/write a superblock. */
196433d6423SLionel Sambuc   dev_t save_dev = sp->s_dev;
197433d6423SLionel Sambuc   struct buf *bp;
198433d6423SLionel Sambuc   char *sbbuf;
199433d6423SLionel Sambuc 
200433d6423SLionel Sambuc /* To keep the 1kb on disk clean, only read/write up to and including
201433d6423SLionel Sambuc  * this field.
202433d6423SLionel Sambuc  */
203433d6423SLionel Sambuc #define LAST_ONDISK_FIELD s_disk_version
204433d6423SLionel Sambuc   int ondisk_bytes = (int) ((char *) &sp->LAST_ONDISK_FIELD - (char *) sp)
205433d6423SLionel Sambuc   	+ sizeof(sp->LAST_ONDISK_FIELD);
206433d6423SLionel Sambuc 
207433d6423SLionel Sambuc   assert(ondisk_bytes > 0);
208433d6423SLionel Sambuc   assert(ondisk_bytes < PAGE_SIZE);
209433d6423SLionel Sambuc   assert(ondisk_bytes < sizeof(struct super_block));
210433d6423SLionel Sambuc 
211433d6423SLionel Sambuc   if (sp->s_dev == NO_DEV)
212433d6423SLionel Sambuc   	panic("request for super_block of NO_DEV");
213433d6423SLionel Sambuc 
214433d6423SLionel Sambuc   /* we rely on the cache blocksize, before reading the
215433d6423SLionel Sambuc    * superblock, being big enough that our complete superblock
216433d6423SLionel Sambuc    * is in block 0.
217433d6423SLionel Sambuc    *
218433d6423SLionel Sambuc    * copy between the disk block and the superblock buffer (depending
219433d6423SLionel Sambuc    * on direction). mark the disk block dirty if the copy is into the
220433d6423SLionel Sambuc    * disk block.
221433d6423SLionel Sambuc    */
222433d6423SLionel Sambuc   assert(lmfs_fs_block_size() >= sizeof(struct super_block) + SUPER_BLOCK_BYTES);
223433d6423SLionel Sambuc   assert(SUPER_BLOCK_BYTES >= sizeof(struct super_block));
224433d6423SLionel Sambuc   assert(SUPER_BLOCK_BYTES >= ondisk_bytes);
225433d6423SLionel Sambuc   if(!(bp = get_block(sp->s_dev, 0, NORMAL)))
226433d6423SLionel Sambuc   	panic("get_block of superblock failed");
227433d6423SLionel Sambuc 
228433d6423SLionel Sambuc   /* sbbuf points to the disk block at the superblock offset */
229433d6423SLionel Sambuc   sbbuf = (char *) b_data(bp) + SUPER_BLOCK_BYTES;
230433d6423SLionel Sambuc 
231433d6423SLionel Sambuc   if(writing) {
232433d6423SLionel Sambuc   	memset(b_data(bp), 0, lmfs_fs_block_size());
233433d6423SLionel Sambuc   	memcpy(sbbuf, sp, ondisk_bytes);
234433d6423SLionel Sambuc 	lmfs_markdirty(bp);
235433d6423SLionel Sambuc   } else {
236433d6423SLionel Sambuc 	memset(sp, 0, sizeof(*sp));
237433d6423SLionel Sambuc   	memcpy(sp, sbbuf, ondisk_bytes);
238433d6423SLionel Sambuc   	sp->s_dev = save_dev;
239433d6423SLionel Sambuc   }
240433d6423SLionel Sambuc 
241*0314acfbSDavid van Moolenbroek   put_block(bp);
242433d6423SLionel Sambuc   lmfs_flushall();
243433d6423SLionel Sambuc 
244433d6423SLionel Sambuc   return OK;
245433d6423SLionel Sambuc }
246433d6423SLionel Sambuc 
247433d6423SLionel Sambuc /*===========================================================================*
248433d6423SLionel Sambuc  *				read_super				     *
249433d6423SLionel Sambuc  *===========================================================================*/
250433d6423SLionel Sambuc int read_super(struct super_block *sp)
251433d6423SLionel Sambuc {
252433d6423SLionel Sambuc   unsigned int magic;
253433d6423SLionel Sambuc   block_t offset;
254433d6423SLionel Sambuc   int version, native, r;
255433d6423SLionel Sambuc 
256433d6423SLionel Sambuc   if((r=rw_super(sp, 0)) != OK)
257433d6423SLionel Sambuc   	return r;
258433d6423SLionel Sambuc 
259433d6423SLionel Sambuc   magic = sp->s_magic;		/* determines file system type */
260433d6423SLionel Sambuc 
261433d6423SLionel Sambuc   if(magic == SUPER_V2 || magic == SUPER_MAGIC) {
262433d6423SLionel Sambuc 	printf("MFS: only supports V3 filesystems.\n");
263433d6423SLionel Sambuc 	return EINVAL;
264433d6423SLionel Sambuc   }
265433d6423SLionel Sambuc 
266433d6423SLionel Sambuc   /* Get file system version and type - only support v3. */
267433d6423SLionel Sambuc   if(magic != SUPER_V3) {
268433d6423SLionel Sambuc 	return EINVAL;
269433d6423SLionel Sambuc   }
270433d6423SLionel Sambuc   version = V3;
271433d6423SLionel Sambuc   native = 1;
272433d6423SLionel Sambuc 
273433d6423SLionel Sambuc   /* If the super block has the wrong byte order, swap the fields; the magic
274433d6423SLionel Sambuc    * number doesn't need conversion. */
275433d6423SLionel Sambuc   sp->s_ninodes =           (ino_t) conv4(native, (int) sp->s_ninodes);
276433d6423SLionel Sambuc   sp->s_nzones =          (zone1_t) conv2(native, (int) sp->s_nzones);
277433d6423SLionel Sambuc   sp->s_imap_blocks =       (short) conv2(native, (int) sp->s_imap_blocks);
278433d6423SLionel Sambuc   sp->s_zmap_blocks =       (short) conv2(native, (int) sp->s_zmap_blocks);
279433d6423SLionel Sambuc   sp->s_firstdatazone_old =(zone1_t)conv2(native,(int)sp->s_firstdatazone_old);
280433d6423SLionel Sambuc   sp->s_log_zone_size =     (short) conv2(native, (int) sp->s_log_zone_size);
281433d6423SLionel Sambuc   sp->s_max_size =          (off_t) conv4(native, sp->s_max_size);
282433d6423SLionel Sambuc   sp->s_zones =             (zone_t)conv4(native, sp->s_zones);
283433d6423SLionel Sambuc 
284433d6423SLionel Sambuc   /* Calculate some other numbers that depend on the version here too, to
285433d6423SLionel Sambuc    * hide some of the differences.
286433d6423SLionel Sambuc    */
287433d6423SLionel Sambuc   assert(version == V3);
288433d6423SLionel Sambuc   sp->s_block_size = (unsigned short) conv2(native,(int) sp->s_block_size);
289433d6423SLionel Sambuc   if (sp->s_block_size < PAGE_SIZE) {
290433d6423SLionel Sambuc  	return EINVAL;
291433d6423SLionel Sambuc   }
292433d6423SLionel Sambuc   sp->s_inodes_per_block = V2_INODES_PER_BLOCK(sp->s_block_size);
293433d6423SLionel Sambuc   sp->s_ndzones = V2_NR_DZONES;
294433d6423SLionel Sambuc   sp->s_nindirs = V2_INDIRECTS(sp->s_block_size);
295433d6423SLionel Sambuc 
296433d6423SLionel Sambuc   /* For even larger disks, a similar problem occurs with s_firstdatazone.
297433d6423SLionel Sambuc    * If the on-disk field contains zero, we assume that the value was too
298433d6423SLionel Sambuc    * large to fit, and compute it on the fly.
299433d6423SLionel Sambuc    */
300433d6423SLionel Sambuc   if (sp->s_firstdatazone_old == 0) {
301433d6423SLionel Sambuc 	offset = START_BLOCK + sp->s_imap_blocks + sp->s_zmap_blocks;
302433d6423SLionel Sambuc 	offset += (sp->s_ninodes + sp->s_inodes_per_block - 1) /
303433d6423SLionel Sambuc 		sp->s_inodes_per_block;
304433d6423SLionel Sambuc 
305433d6423SLionel Sambuc 	sp->s_firstdatazone = (offset + (1 << sp->s_log_zone_size) - 1) >>
306433d6423SLionel Sambuc 		sp->s_log_zone_size;
307433d6423SLionel Sambuc   } else {
308433d6423SLionel Sambuc 	sp->s_firstdatazone = (zone_t) sp->s_firstdatazone_old;
309433d6423SLionel Sambuc   }
310433d6423SLionel Sambuc 
311433d6423SLionel Sambuc   if (sp->s_block_size < PAGE_SIZE)
312433d6423SLionel Sambuc   	return(EINVAL);
313433d6423SLionel Sambuc 
314433d6423SLionel Sambuc   if ((sp->s_block_size % 512) != 0)
315433d6423SLionel Sambuc   	return(EINVAL);
316433d6423SLionel Sambuc 
317433d6423SLionel Sambuc   if (SUPER_SIZE > sp->s_block_size)
318433d6423SLionel Sambuc   	return(EINVAL);
319433d6423SLionel Sambuc 
320433d6423SLionel Sambuc   if ((sp->s_block_size % V2_INODE_SIZE) != 0) {
321433d6423SLionel Sambuc   	return(EINVAL);
322433d6423SLionel Sambuc   }
323433d6423SLionel Sambuc 
324433d6423SLionel Sambuc   /* Limit s_max_size to LONG_MAX */
325433d6423SLionel Sambuc   if ((unsigned long)sp->s_max_size > LONG_MAX)
326433d6423SLionel Sambuc 	sp->s_max_size = LONG_MAX;
327433d6423SLionel Sambuc 
328433d6423SLionel Sambuc   sp->s_isearch = 0;		/* inode searches initially start at 0 */
329433d6423SLionel Sambuc   sp->s_zsearch = 0;		/* zone searches initially start at 0 */
330433d6423SLionel Sambuc   sp->s_version = version;
331433d6423SLionel Sambuc   sp->s_native  = native;
332433d6423SLionel Sambuc 
333433d6423SLionel Sambuc   /* Make a few basic checks to see if super block looks reasonable. */
334433d6423SLionel Sambuc   if (sp->s_imap_blocks < 1 || sp->s_zmap_blocks < 1
335433d6423SLionel Sambuc 				|| sp->s_ninodes < 1 || sp->s_zones < 1
336433d6423SLionel Sambuc 				|| sp->s_firstdatazone <= 4
337433d6423SLionel Sambuc 				|| sp->s_firstdatazone >= sp->s_zones
338433d6423SLionel Sambuc 				|| (unsigned) sp->s_log_zone_size > 4) {
339433d6423SLionel Sambuc   	printf("not enough imap or zone map blocks, \n");
340433d6423SLionel Sambuc   	printf("or not enough inodes, or not enough zones, \n"
341433d6423SLionel Sambuc   		"or invalid first data zone, or zone size too large\n");
342433d6423SLionel Sambuc 	return(EINVAL);
343433d6423SLionel Sambuc   }
344433d6423SLionel Sambuc 
345433d6423SLionel Sambuc 
346433d6423SLionel Sambuc   /* Check any flags we don't understand but are required to. Currently
347433d6423SLionel Sambuc    * these don't exist so all such unknown bits are fatal.
348433d6423SLionel Sambuc    */
349433d6423SLionel Sambuc   if(sp->s_flags & MFSFLAG_MANDATORY_MASK) {
350433d6423SLionel Sambuc   	printf("MFS: unsupported feature flags on this FS.\n"
351433d6423SLionel Sambuc 		"Please use a newer MFS to mount it.\n");
352433d6423SLionel Sambuc 	return(EINVAL);
353433d6423SLionel Sambuc   }
354433d6423SLionel Sambuc 
355433d6423SLionel Sambuc   return(OK);
356433d6423SLionel Sambuc }
357433d6423SLionel Sambuc 
358433d6423SLionel Sambuc /*===========================================================================*
359433d6423SLionel Sambuc  *				write_super				     *
360433d6423SLionel Sambuc  *===========================================================================*/
361433d6423SLionel Sambuc int write_super(struct super_block *sp)
362433d6423SLionel Sambuc {
363433d6423SLionel Sambuc   if(sp->s_rd_only)
364433d6423SLionel Sambuc   	panic("can't write superblock of readonly filesystem");
365433d6423SLionel Sambuc   return rw_super(sp, 1);
366433d6423SLionel Sambuc }
367433d6423SLionel Sambuc 
368433d6423SLionel Sambuc static int blocks_known = 0;
369433d6423SLionel Sambuc 
370433d6423SLionel Sambuc u32_t get_used_blocks(struct super_block *sp)
371433d6423SLionel Sambuc {
372433d6423SLionel Sambuc 	if(!blocks_known)  {
373433d6423SLionel Sambuc 		/* how many blocks are in use? */
374433d6423SLionel Sambuc 		used_blocks = sp->s_zones - count_free_bits(sp, ZMAP);
375433d6423SLionel Sambuc 		blocks_known = 1;
376433d6423SLionel Sambuc 	}
377433d6423SLionel Sambuc 	return used_blocks;
378433d6423SLionel Sambuc }
379