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