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