《操作系统》的实验代码。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

258 lines
7.0 KiB

12 years ago
  1. #include <defs.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <kmalloc.h>
  5. #include <list.h>
  6. #include <fs.h>
  7. #include <vfs.h>
  8. #include <dev.h>
  9. #include <sfs.h>
  10. #include <inode.h>
  11. #include <iobuf.h>
  12. #include <bitmap.h>
  13. #include <error.h>
  14. #include <assert.h>
  15. /*
  16. * sfs_sync - sync sfs's superblock and freemap in memroy into disk
  17. */
  18. static int
  19. sfs_sync(struct fs *fs) {
  20. struct sfs_fs *sfs = fsop_info(fs, sfs);
  21. lock_sfs_fs(sfs);
  22. {
  23. list_entry_t *list = &(sfs->inode_list), *le = list;
  24. while ((le = list_next(le)) != list) {
  25. struct sfs_inode *sin = le2sin(le, inode_link);
  26. vop_fsync(info2node(sin, sfs_inode));
  27. }
  28. }
  29. unlock_sfs_fs(sfs);
  30. int ret;
  31. if (sfs->super_dirty) {
  32. sfs->super_dirty = 0;
  33. if ((ret = sfs_sync_super(sfs)) != 0) {
  34. sfs->super_dirty = 1;
  35. return ret;
  36. }
  37. if ((ret = sfs_sync_freemap(sfs)) != 0) {
  38. sfs->super_dirty = 1;
  39. return ret;
  40. }
  41. }
  42. return 0;
  43. }
  44. /*
  45. * sfs_get_root - get the root directory inode from disk (SFS_BLKN_ROOT,1)
  46. */
  47. static struct inode *
  48. sfs_get_root(struct fs *fs) {
  49. struct inode *node;
  50. int ret;
  51. if ((ret = sfs_load_inode(fsop_info(fs, sfs), &node, SFS_BLKN_ROOT)) != 0) {
  52. panic("load sfs root failed: %e", ret);
  53. }
  54. return node;
  55. }
  56. /*
  57. * sfs_unmount - unmount sfs, and free the memorys contain sfs->freemap/sfs_buffer/hash_liskt and sfs itself.
  58. */
  59. static int
  60. sfs_unmount(struct fs *fs) {
  61. struct sfs_fs *sfs = fsop_info(fs, sfs);
  62. if (!list_empty(&(sfs->inode_list))) {
  63. return -E_BUSY;
  64. }
  65. assert(!sfs->super_dirty);
  66. bitmap_destroy(sfs->freemap);
  67. kfree(sfs->sfs_buffer);
  68. kfree(sfs->hash_list);
  69. kfree(sfs);
  70. return 0;
  71. }
  72. /*
  73. * sfs_cleanup - when sfs failed, then should call this function to sync sfs by calling sfs_sync
  74. *
  75. * NOTICE: nouse now.
  76. */
  77. static void
  78. sfs_cleanup(struct fs *fs) {
  79. struct sfs_fs *sfs = fsop_info(fs, sfs);
  80. uint32_t blocks = sfs->super.blocks, unused_blocks = sfs->super.unused_blocks;
  81. cprintf("sfs: cleanup: '%s' (%d/%d/%d)\n", sfs->super.info,
  82. blocks - unused_blocks, unused_blocks, blocks);
  83. int i, ret;
  84. for (i = 0; i < 32; i ++) {
  85. if ((ret = fsop_sync(fs)) == 0) {
  86. break;
  87. }
  88. }
  89. if (ret != 0) {
  90. warn("sfs: sync error: '%s': %e.\n", sfs->super.info, ret);
  91. }
  92. }
  93. /*
  94. * sfs_init_read - used in sfs_do_mount to read disk block(blkno, 1) directly.
  95. *
  96. * @dev: the block device
  97. * @blkno: the NO. of disk block
  98. * @blk_buffer: the buffer used for read
  99. *
  100. * (1) init iobuf
  101. * (2) read dev into iobuf
  102. */
  103. static int
  104. sfs_init_read(struct device *dev, uint32_t blkno, void *blk_buffer) {
  105. struct iobuf __iob, *iob = iobuf_init(&__iob, blk_buffer, SFS_BLKSIZE, blkno * SFS_BLKSIZE);
  106. return dop_io(dev, iob, 0);
  107. }
  108. /*
  109. * sfs_init_freemap - used in sfs_do_mount to read freemap data info in disk block(blkno, nblks) directly.
  110. *
  111. * @dev: the block device
  112. * @bitmap: the bitmap in memroy
  113. * @blkno: the NO. of disk block
  114. * @nblks: Rd number of disk block
  115. * @blk_buffer: the buffer used for read
  116. *
  117. * (1) get data addr in bitmap
  118. * (2) read dev into iobuf
  119. */
  120. static int
  121. sfs_init_freemap(struct device *dev, struct bitmap *freemap, uint32_t blkno, uint32_t nblks, void *blk_buffer) {
  122. size_t len;
  123. void *data = bitmap_getdata(freemap, &len);
  124. assert(data != NULL && len == nblks * SFS_BLKSIZE);
  125. while (nblks != 0) {
  126. int ret;
  127. if ((ret = sfs_init_read(dev, blkno, data)) != 0) {
  128. return ret;
  129. }
  130. blkno ++, nblks --, data += SFS_BLKSIZE;
  131. }
  132. return 0;
  133. }
  134. /*
  135. * sfs_do_mount - mount sfs file system.
  136. *
  137. * @dev: the block device contains sfs file system
  138. * @fs_store: the fs struct in memroy
  139. */
  140. static int
  141. sfs_do_mount(struct device *dev, struct fs **fs_store) {
  142. static_assert(SFS_BLKSIZE >= sizeof(struct sfs_super));
  143. static_assert(SFS_BLKSIZE >= sizeof(struct sfs_disk_inode));
  144. static_assert(SFS_BLKSIZE >= sizeof(struct sfs_disk_entry));
  145. if (dev->d_blocksize != SFS_BLKSIZE) {
  146. return -E_NA_DEV;
  147. }
  148. /* allocate fs structure */
  149. struct fs *fs;
  150. if ((fs = alloc_fs(sfs)) == NULL) {
  151. return -E_NO_MEM;
  152. }
  153. struct sfs_fs *sfs = fsop_info(fs, sfs);
  154. sfs->dev = dev;
  155. int ret = -E_NO_MEM;
  156. void *sfs_buffer;
  157. if ((sfs->sfs_buffer = sfs_buffer = kmalloc(SFS_BLKSIZE)) == NULL) {
  158. goto failed_cleanup_fs;
  159. }
  160. /* load and check superblock */
  161. if ((ret = sfs_init_read(dev, SFS_BLKN_SUPER, sfs_buffer)) != 0) {
  162. goto failed_cleanup_sfs_buffer;
  163. }
  164. ret = -E_INVAL;
  165. struct sfs_super *super = sfs_buffer;
  166. if (super->magic != SFS_MAGIC) {
  167. cprintf("sfs: wrong magic in superblock. (%08x should be %08x).\n",
  168. super->magic, SFS_MAGIC);
  169. goto failed_cleanup_sfs_buffer;
  170. }
  171. if (super->blocks > dev->d_blocks) {
  172. cprintf("sfs: fs has %u blocks, device has %u blocks.\n",
  173. super->blocks, dev->d_blocks);
  174. goto failed_cleanup_sfs_buffer;
  175. }
  176. super->info[SFS_MAX_INFO_LEN] = '\0';
  177. sfs->super = *super;
  178. ret = -E_NO_MEM;
  179. uint32_t i;
  180. /* alloc and initialize hash list */
  181. list_entry_t *hash_list;
  182. if ((sfs->hash_list = hash_list = kmalloc(sizeof(list_entry_t) * SFS_HLIST_SIZE)) == NULL) {
  183. goto failed_cleanup_sfs_buffer;
  184. }
  185. for (i = 0; i < SFS_HLIST_SIZE; i ++) {
  186. list_init(hash_list + i);
  187. }
  188. /* load and check freemap */
  189. struct bitmap *freemap;
  190. uint32_t freemap_size_nbits = sfs_freemap_bits(super);
  191. if ((sfs->freemap = freemap = bitmap_create(freemap_size_nbits)) == NULL) {
  192. goto failed_cleanup_hash_list;
  193. }
  194. uint32_t freemap_size_nblks = sfs_freemap_blocks(super);
  195. if ((ret = sfs_init_freemap(dev, freemap, SFS_BLKN_FREEMAP, freemap_size_nblks, sfs_buffer)) != 0) {
  196. goto failed_cleanup_freemap;
  197. }
  198. uint32_t blocks = sfs->super.blocks, unused_blocks = 0;
  199. for (i = 0; i < freemap_size_nbits; i ++) {
  200. if (bitmap_test(freemap, i)) {
  201. unused_blocks ++;
  202. }
  203. }
  204. assert(unused_blocks == sfs->super.unused_blocks);
  205. /* and other fields */
  206. sfs->super_dirty = 0;
  207. sem_init(&(sfs->fs_sem), 1);
  208. sem_init(&(sfs->io_sem), 1);
  209. sem_init(&(sfs->mutex_sem), 1);
  210. list_init(&(sfs->inode_list));
  211. cprintf("sfs: mount: '%s' (%d/%d/%d)\n", sfs->super.info,
  212. blocks - unused_blocks, unused_blocks, blocks);
  213. /* link addr of sync/get_root/unmount/cleanup funciton fs's function pointers*/
  214. fs->fs_sync = sfs_sync;
  215. fs->fs_get_root = sfs_get_root;
  216. fs->fs_unmount = sfs_unmount;
  217. fs->fs_cleanup = sfs_cleanup;
  218. *fs_store = fs;
  219. return 0;
  220. failed_cleanup_freemap:
  221. bitmap_destroy(freemap);
  222. failed_cleanup_hash_list:
  223. kfree(hash_list);
  224. failed_cleanup_sfs_buffer:
  225. kfree(sfs_buffer);
  226. failed_cleanup_fs:
  227. kfree(fs);
  228. return ret;
  229. }
  230. int
  231. sfs_mount(const char *devname) {
  232. return vfs_mount(devname, sfs_do_mount);
  233. }