super.c 11 KB

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