《操作系统》的实验代码。
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.

987 lines
29 KiB

12 years ago
  1. #include <defs.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <list.h>
  5. #include <stat.h>
  6. #include <kmalloc.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. static const struct inode_ops sfs_node_dirops; // dir operations
  16. static const struct inode_ops sfs_node_fileops; // file operations
  17. /*
  18. * lock_sin - lock the process of inode Rd/Wr
  19. */
  20. static void
  21. lock_sin(struct sfs_inode *sin) {
  22. down(&(sin->sem));
  23. }
  24. /*
  25. * unlock_sin - unlock the process of inode Rd/Wr
  26. */
  27. static void
  28. unlock_sin(struct sfs_inode *sin) {
  29. up(&(sin->sem));
  30. }
  31. /*
  32. * sfs_get_ops - return function addr of fs_node_dirops/sfs_node_fileops
  33. */
  34. static const struct inode_ops *
  35. sfs_get_ops(uint16_t type) {
  36. switch (type) {
  37. case SFS_TYPE_DIR:
  38. return &sfs_node_dirops;
  39. case SFS_TYPE_FILE:
  40. return &sfs_node_fileops;
  41. }
  42. panic("invalid file type %d.\n", type);
  43. }
  44. /*
  45. * sfs_hash_list - return inode entry in sfs->hash_list
  46. */
  47. static list_entry_t *
  48. sfs_hash_list(struct sfs_fs *sfs, uint32_t ino) {
  49. return sfs->hash_list + sin_hashfn(ino);
  50. }
  51. /*
  52. * sfs_set_links - link inode sin in sfs->linked-list AND sfs->hash_link
  53. */
  54. static void
  55. sfs_set_links(struct sfs_fs *sfs, struct sfs_inode *sin) {
  56. list_add(&(sfs->inode_list), &(sin->inode_link));
  57. list_add(sfs_hash_list(sfs, sin->ino), &(sin->hash_link));
  58. }
  59. /*
  60. * sfs_remove_links - unlink inode sin in sfs->linked-list AND sfs->hash_link
  61. */
  62. static void
  63. sfs_remove_links(struct sfs_inode *sin) {
  64. list_del(&(sin->inode_link));
  65. list_del(&(sin->hash_link));
  66. }
  67. /*
  68. * sfs_block_inuse - check the inode with NO. ino inuse info in bitmap
  69. */
  70. static bool
  71. sfs_block_inuse(struct sfs_fs *sfs, uint32_t ino) {
  72. if (ino != 0 && ino < sfs->super.blocks) {
  73. return !bitmap_test(sfs->freemap, ino);
  74. }
  75. panic("sfs_block_inuse: called out of range (0, %u) %u.\n", sfs->super.blocks, ino);
  76. }
  77. /*
  78. * sfs_block_alloc - check and get a free disk block
  79. */
  80. static int
  81. sfs_block_alloc(struct sfs_fs *sfs, uint32_t *ino_store) {
  82. int ret;
  83. if ((ret = bitmap_alloc(sfs->freemap, ino_store)) != 0) {
  84. return ret;
  85. }
  86. assert(sfs->super.unused_blocks > 0);
  87. sfs->super.unused_blocks --, sfs->super_dirty = 1;
  88. assert(sfs_block_inuse(sfs, *ino_store));
  89. return sfs_clear_block(sfs, *ino_store, 1);
  90. }
  91. /*
  92. * sfs_block_free - set related bits for ino block to 1(means free) in bitmap, add sfs->super.unused_blocks, set superblock dirty *
  93. */
  94. static void
  95. sfs_block_free(struct sfs_fs *sfs, uint32_t ino) {
  96. assert(sfs_block_inuse(sfs, ino));
  97. bitmap_free(sfs->freemap, ino);
  98. sfs->super.unused_blocks ++, sfs->super_dirty = 1;
  99. }
  100. /*
  101. * sfs_create_inode - alloc a inode in memroy, and init din/ino/dirty/reclian_count/sem fields in sfs_inode in inode
  102. */
  103. static int
  104. sfs_create_inode(struct sfs_fs *sfs, struct sfs_disk_inode *din, uint32_t ino, struct inode **node_store) {
  105. struct inode *node;
  106. if ((node = alloc_inode(sfs_inode)) != NULL) {
  107. vop_init(node, sfs_get_ops(din->type), info2fs(sfs, sfs));
  108. struct sfs_inode *sin = vop_info(node, sfs_inode);
  109. sin->din = din, sin->ino = ino, sin->dirty = 0, sin->reclaim_count = 1;
  110. sem_init(&(sin->sem), 1);
  111. *node_store = node;
  112. return 0;
  113. }
  114. return -E_NO_MEM;
  115. }
  116. /*
  117. * lookup_sfs_nolock - according ino, find related inode
  118. *
  119. * NOTICE: le2sin, info2node MACRO
  120. */
  121. static struct inode *
  122. lookup_sfs_nolock(struct sfs_fs *sfs, uint32_t ino) {
  123. struct inode *node;
  124. list_entry_t *list = sfs_hash_list(sfs, ino), *le = list;
  125. while ((le = list_next(le)) != list) {
  126. struct sfs_inode *sin = le2sin(le, hash_link);
  127. if (sin->ino == ino) {
  128. node = info2node(sin, sfs_inode);
  129. if (vop_ref_inc(node) == 1) {
  130. sin->reclaim_count ++;
  131. }
  132. return node;
  133. }
  134. }
  135. return NULL;
  136. }
  137. /*
  138. * sfs_load_inode - If the inode isn't existed, load inode related ino disk block data into a new created inode.
  139. * If the inode is in memory alreadily, then do nothing
  140. */
  141. int
  142. sfs_load_inode(struct sfs_fs *sfs, struct inode **node_store, uint32_t ino) {
  143. lock_sfs_fs(sfs);
  144. struct inode *node;
  145. if ((node = lookup_sfs_nolock(sfs, ino)) != NULL) {
  146. goto out_unlock;
  147. }
  148. int ret = -E_NO_MEM;
  149. struct sfs_disk_inode *din;
  150. if ((din = kmalloc(sizeof(struct sfs_disk_inode))) == NULL) {
  151. goto failed_unlock;
  152. }
  153. assert(sfs_block_inuse(sfs, ino));
  154. if ((ret = sfs_rbuf(sfs, din, sizeof(struct sfs_disk_inode), ino, 0)) != 0) {
  155. goto failed_cleanup_din;
  156. }
  157. assert(din->nlinks != 0);
  158. if ((ret = sfs_create_inode(sfs, din, ino, &node)) != 0) {
  159. goto failed_cleanup_din;
  160. }
  161. sfs_set_links(sfs, vop_info(node, sfs_inode));
  162. out_unlock:
  163. unlock_sfs_fs(sfs);
  164. *node_store = node;
  165. return 0;
  166. failed_cleanup_din:
  167. kfree(din);
  168. failed_unlock:
  169. unlock_sfs_fs(sfs);
  170. return ret;
  171. }
  172. /*
  173. * sfs_bmap_get_sub_nolock - according entry pointer entp and index, find the index of indrect disk block
  174. * return the index of indrect disk block to ino_store. no lock protect
  175. * @sfs: sfs file system
  176. * @entp: the pointer of index of entry disk block
  177. * @index: the index of block in indrect block
  178. * @create: BOOL, if the block isn't allocated, if create = 1 the alloc a block, otherwise just do nothing
  179. * @ino_store: 0 OR the index of already inused block or new allocated block.
  180. */
  181. static int
  182. sfs_bmap_get_sub_nolock(struct sfs_fs *sfs, uint32_t *entp, uint32_t index, bool create, uint32_t *ino_store) {
  183. assert(index < SFS_BLK_NENTRY);
  184. int ret;
  185. uint32_t ent, ino = 0;
  186. off_t offset = index * sizeof(uint32_t); // the offset of entry in entry block
  187. // if entry block is existd, read the content of entry block into sfs->sfs_buffer
  188. if ((ent = *entp) != 0) {
  189. if ((ret = sfs_rbuf(sfs, &ino, sizeof(uint32_t), ent, offset)) != 0) {
  190. return ret;
  191. }
  192. if (ino != 0 || !create) {
  193. goto out;
  194. }
  195. }
  196. else {
  197. if (!create) {
  198. goto out;
  199. }
  200. //if entry block isn't existd, allocated a entry block (for indrect block)
  201. if ((ret = sfs_block_alloc(sfs, &ent)) != 0) {
  202. return ret;
  203. }
  204. }
  205. if ((ret = sfs_block_alloc(sfs, &ino)) != 0) {
  206. goto failed_cleanup;
  207. }
  208. if ((ret = sfs_wbuf(sfs, &ino, sizeof(uint32_t), ent, offset)) != 0) {
  209. sfs_block_free(sfs, ino);
  210. goto failed_cleanup;
  211. }
  212. out:
  213. if (ent != *entp) {
  214. *entp = ent;
  215. }
  216. *ino_store = ino;
  217. return 0;
  218. failed_cleanup:
  219. if (ent != *entp) {
  220. sfs_block_free(sfs, ent);
  221. }
  222. return ret;
  223. }
  224. /*
  225. * sfs_bmap_get_nolock - according sfs_inode and index of block, find the NO. of disk block
  226. * no lock protect
  227. * @sfs: sfs file system
  228. * @sin: sfs inode in memory
  229. * @index: the index of block in inode
  230. * @create: BOOL, if the block isn't allocated, if create = 1 the alloc a block, otherwise just do nothing
  231. * @ino_store: 0 OR the index of already inused block or new allocated block.
  232. */
  233. static int
  234. sfs_bmap_get_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, uint32_t index, bool create, uint32_t *ino_store) {
  235. struct sfs_disk_inode *din = sin->din;
  236. int ret;
  237. uint32_t ent, ino;
  238. // the index of disk block is in the fist SFS_NDIRECT direct blocks
  239. if (index < SFS_NDIRECT) {
  240. if ((ino = din->direct[index]) == 0 && create) {
  241. if ((ret = sfs_block_alloc(sfs, &ino)) != 0) {
  242. return ret;
  243. }
  244. din->direct[index] = ino;
  245. sin->dirty = 1;
  246. }
  247. goto out;
  248. }
  249. // the index of disk block is in the indirect blocks.
  250. index -= SFS_NDIRECT;
  251. if (index < SFS_BLK_NENTRY) {
  252. ent = din->indirect;
  253. if ((ret = sfs_bmap_get_sub_nolock(sfs, &ent, index, create, &ino)) != 0) {
  254. return ret;
  255. }
  256. if (ent != din->indirect) {
  257. assert(din->indirect == 0);
  258. din->indirect = ent;
  259. sin->dirty = 1;
  260. }
  261. goto out;
  262. } else {
  263. panic ("sfs_bmap_get_nolock - index out of range");
  264. }
  265. out:
  266. assert(ino == 0 || sfs_block_inuse(sfs, ino));
  267. *ino_store = ino;
  268. return 0;
  269. }
  270. /*
  271. * sfs_bmap_free_sub_nolock - set the entry item to 0 (free) in the indirect block
  272. */
  273. static int
  274. sfs_bmap_free_sub_nolock(struct sfs_fs *sfs, uint32_t ent, uint32_t index) {
  275. assert(sfs_block_inuse(sfs, ent) && index < SFS_BLK_NENTRY);
  276. int ret;
  277. uint32_t ino, zero = 0;
  278. off_t offset = index * sizeof(uint32_t);
  279. if ((ret = sfs_rbuf(sfs, &ino, sizeof(uint32_t), ent, offset)) != 0) {
  280. return ret;
  281. }
  282. if (ino != 0) {
  283. if ((ret = sfs_wbuf(sfs, &zero, sizeof(uint32_t), ent, offset)) != 0) {
  284. return ret;
  285. }
  286. sfs_block_free(sfs, ino);
  287. }
  288. return 0;
  289. }
  290. /*
  291. * sfs_bmap_free_nolock - free a block with logical index in inode and reset the inode's fields
  292. */
  293. static int
  294. sfs_bmap_free_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, uint32_t index) {
  295. struct sfs_disk_inode *din = sin->din;
  296. int ret;
  297. uint32_t ent, ino;
  298. if (index < SFS_NDIRECT) {
  299. if ((ino = din->direct[index]) != 0) {
  300. // free the block
  301. sfs_block_free(sfs, ino);
  302. din->direct[index] = 0;
  303. sin->dirty = 1;
  304. }
  305. return 0;
  306. }
  307. index -= SFS_NDIRECT;
  308. if (index < SFS_BLK_NENTRY) {
  309. if ((ent = din->indirect) != 0) {
  310. // set the entry item to 0 in the indirect block
  311. if ((ret = sfs_bmap_free_sub_nolock(sfs, ent, index)) != 0) {
  312. return ret;
  313. }
  314. }
  315. return 0;
  316. }
  317. return 0;
  318. }
  319. /*
  320. * sfs_bmap_load_nolock - according to the DIR's inode and the logical index of block in inode, find the NO. of disk block.
  321. * @sfs: sfs file system
  322. * @sin: sfs inode in memory
  323. * @index: the logical index of disk block in inode
  324. * @ino_store:the NO. of disk block
  325. */
  326. static int
  327. sfs_bmap_load_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, uint32_t index, uint32_t *ino_store) {
  328. struct sfs_disk_inode *din = sin->din;
  329. assert(index <= din->blocks);
  330. int ret;
  331. uint32_t ino;
  332. bool create = (index == din->blocks);
  333. if ((ret = sfs_bmap_get_nolock(sfs, sin, index, create, &ino)) != 0) {
  334. return ret;
  335. }
  336. assert(sfs_block_inuse(sfs, ino));
  337. if (create) {
  338. din->blocks ++;
  339. }
  340. if (ino_store != NULL) {
  341. *ino_store = ino;
  342. }
  343. return 0;
  344. }
  345. /*
  346. * sfs_bmap_truncate_nolock - free the disk block at the end of file
  347. */
  348. static int
  349. sfs_bmap_truncate_nolock(struct sfs_fs *sfs, struct sfs_inode *sin) {
  350. struct sfs_disk_inode *din = sin->din;
  351. assert(din->blocks != 0);
  352. int ret;
  353. if ((ret = sfs_bmap_free_nolock(sfs, sin, din->blocks - 1)) != 0) {
  354. return ret;
  355. }
  356. din->blocks --;
  357. sin->dirty = 1;
  358. return 0;
  359. }
  360. /*
  361. * sfs_dirent_read_nolock - read the file entry from disk block which contains this entry
  362. * @sfs: sfs file system
  363. * @sin: sfs inode in memory
  364. * @slot: the index of file entry
  365. * @entry: file entry
  366. */
  367. static int
  368. sfs_dirent_read_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, int slot, struct sfs_disk_entry *entry) {
  369. assert(sin->din->type == SFS_TYPE_DIR && (slot >= 0 && slot < sin->din->blocks));
  370. int ret;
  371. uint32_t ino;
  372. // according to the DIR's inode and the slot of file entry, find the index of disk block which contains this file entry
  373. if ((ret = sfs_bmap_load_nolock(sfs, sin, slot, &ino)) != 0) {
  374. return ret;
  375. }
  376. assert(sfs_block_inuse(sfs, ino));
  377. // read the content of file entry in the disk block
  378. if ((ret = sfs_rbuf(sfs, entry, sizeof(struct sfs_disk_entry), ino, 0)) != 0) {
  379. return ret;
  380. }
  381. entry->name[SFS_MAX_FNAME_LEN] = '\0';
  382. return 0;
  383. }
  384. #define sfs_dirent_link_nolock_check(sfs, sin, slot, lnksin, name) \
  385. do { \
  386. int err; \
  387. if ((err = sfs_dirent_link_nolock(sfs, sin, slot, lnksin, name)) != 0) { \
  388. warn("sfs_dirent_link error: %e.\n", err); \
  389. } \
  390. } while (0)
  391. #define sfs_dirent_unlink_nolock_check(sfs, sin, slot, lnksin) \
  392. do { \
  393. int err; \
  394. if ((err = sfs_dirent_unlink_nolock(sfs, sin, slot, lnksin)) != 0) { \
  395. warn("sfs_dirent_unlink error: %e.\n", err); \
  396. } \
  397. } while (0)
  398. /*
  399. * sfs_dirent_search_nolock - read every file entry in the DIR, compare file name with each entry->name
  400. * If equal, then return slot and NO. of disk of this file's inode
  401. * @sfs: sfs file system
  402. * @sin: sfs inode in memory
  403. * @name: the filename
  404. * @ino_store: NO. of disk of this file (with the filename)'s inode
  405. * @slot: logical index of file entry (NOTICE: each file entry ocupied one disk block)
  406. * @empty_slot: the empty logical index of file entry.
  407. */
  408. static int
  409. sfs_dirent_search_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, const char *name, uint32_t *ino_store, int *slot, int *empty_slot) {
  410. assert(strlen(name) <= SFS_MAX_FNAME_LEN);
  411. struct sfs_disk_entry *entry;
  412. if ((entry = kmalloc(sizeof(struct sfs_disk_entry))) == NULL) {
  413. return -E_NO_MEM;
  414. }
  415. #define set_pvalue(x, v) do { if ((x) != NULL) { *(x) = (v); } } while (0)
  416. int ret, i, nslots = sin->din->blocks;
  417. set_pvalue(empty_slot, nslots);
  418. for (i = 0; i < nslots; i ++) {
  419. if ((ret = sfs_dirent_read_nolock(sfs, sin, i, entry)) != 0) {
  420. goto out;
  421. }
  422. if (entry->ino == 0) {
  423. set_pvalue(empty_slot, i);
  424. continue ;
  425. }
  426. if (strcmp(name, entry->name) == 0) {
  427. set_pvalue(slot, i);
  428. set_pvalue(ino_store, entry->ino);
  429. goto out;
  430. }
  431. }
  432. #undef set_pvalue
  433. ret = -E_NOENT;
  434. out:
  435. kfree(entry);
  436. return ret;
  437. }
  438. /*
  439. * sfs_dirent_findino_nolock - read all file entries in DIR's inode and find a entry->ino == ino
  440. */
  441. static int
  442. sfs_dirent_findino_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, uint32_t ino, struct sfs_disk_entry *entry) {
  443. int ret, i, nslots = sin->din->blocks;
  444. for (i = 0; i < nslots; i ++) {
  445. if ((ret = sfs_dirent_read_nolock(sfs, sin, i, entry)) != 0) {
  446. return ret;
  447. }
  448. if (entry->ino == ino) {
  449. return 0;
  450. }
  451. }
  452. return -E_NOENT;
  453. }
  454. /*
  455. * sfs_lookup_once - find inode corresponding the file name in DIR's sin inode
  456. * @sfs: sfs file system
  457. * @sin: DIR sfs inode in memory
  458. * @name: the file name in DIR
  459. * @node_store: the inode corresponding the file name in DIR
  460. * @slot: the logical index of file entry
  461. */
  462. static int
  463. sfs_lookup_once(struct sfs_fs *sfs, struct sfs_inode *sin, const char *name, struct inode **node_store, int *slot) {
  464. int ret;
  465. uint32_t ino;
  466. lock_sin(sin);
  467. { // find the NO. of disk block and logical index of file entry
  468. ret = sfs_dirent_search_nolock(sfs, sin, name, &ino, slot, NULL);
  469. }
  470. unlock_sin(sin);
  471. if (ret == 0) {
  472. // load the content of inode with the the NO. of disk block
  473. ret = sfs_load_inode(sfs, node_store, ino);
  474. }
  475. return ret;
  476. }
  477. // sfs_opendir - just check the opne_flags, now support readonly
  478. static int
  479. sfs_opendir(struct inode *node, uint32_t open_flags) {
  480. switch (open_flags & O_ACCMODE) {
  481. case O_RDONLY:
  482. break;
  483. case O_WRONLY:
  484. case O_RDWR:
  485. default:
  486. return -E_ISDIR;
  487. }
  488. if (open_flags & O_APPEND) {
  489. return -E_ISDIR;
  490. }
  491. return 0;
  492. }
  493. // sfs_openfile - open file (no use)
  494. static int
  495. sfs_openfile(struct inode *node, uint32_t open_flags) {
  496. return 0;
  497. }
  498. // sfs_close - close file
  499. static int
  500. sfs_close(struct inode *node) {
  501. return vop_fsync(node);
  502. }
  503. /*
  504. * sfs_io_nolock - Rd/Wr a file contentfrom offset position to offset+ length disk blocks<-->buffer (in memroy)
  505. * @sfs: sfs file system
  506. * @sin: sfs inode in memory
  507. * @buf: the buffer Rd/Wr
  508. * @offset: the offset of file
  509. * @alenp: the length need to read (is a pointer). and will RETURN the really Rd/Wr lenght
  510. * @write: BOOL, 0 read, 1 write
  511. */
  512. static int
  513. sfs_io_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, void *buf, off_t offset, size_t *alenp, bool write) {
  514. struct sfs_disk_inode *din = sin->din;
  515. assert(din->type != SFS_TYPE_DIR);
  516. off_t endpos = offset + *alenp, blkoff;
  517. *alenp = 0;
  518. // calculate the Rd/Wr end position
  519. if (offset < 0 || offset >= SFS_MAX_FILE_SIZE || offset > endpos) {
  520. return -E_INVAL;
  521. }
  522. if (offset == endpos) {
  523. return 0;
  524. }
  525. if (endpos > SFS_MAX_FILE_SIZE) {
  526. endpos = SFS_MAX_FILE_SIZE;
  527. }
  528. if (!write) {
  529. if (offset >= din->size) {
  530. return 0;
  531. }
  532. if (endpos > din->size) {
  533. endpos = din->size;
  534. }
  535. }
  536. int (*sfs_buf_op)(struct sfs_fs *sfs, void *buf, size_t len, uint32_t blkno, off_t offset);
  537. int (*sfs_block_op)(struct sfs_fs *sfs, void *buf, uint32_t blkno, uint32_t nblks);
  538. if (write) {
  539. sfs_buf_op = sfs_wbuf, sfs_block_op = sfs_wblock;
  540. }
  541. else {
  542. sfs_buf_op = sfs_rbuf, sfs_block_op = sfs_rblock;
  543. }
  544. int ret = 0;
  545. size_t size, alen = 0;
  546. uint32_t ino;
  547. uint32_t blkno = offset / SFS_BLKSIZE; // The NO. of Rd/Wr begin block
  548. uint32_t nblks = endpos / SFS_BLKSIZE - blkno; // The size of Rd/Wr blocks
  549. //LAB8:EXERCISE1 YOUR CODE HINT: call sfs_bmap_load_nolock, sfs_rbuf, sfs_rblock,etc. read different kind of blocks in file
  550. /*
  551. * (1) If offset isn't aligned with the first block, Rd/Wr some content from offset to the end of the first block
  552. * NOTICE: useful function: sfs_bmap_load_nolock, sfs_buf_op
  553. * Rd/Wr size = (nblks != 0) ? (SFS_BLKSIZE - blkoff) : (endpos - offset)
  554. * (2) Rd/Wr aligned blocks
  555. * NOTICE: useful function: sfs_bmap_load_nolock, sfs_block_op
  556. * (3) If end position isn't aligned with the last block, Rd/Wr some content from begin to the (endpos % SFS_BLKSIZE) of the last block
  557. * NOTICE: useful function: sfs_bmap_load_nolock, sfs_buf_op
  558. */
  559. out:
  560. *alenp = alen;
  561. if (offset + alen > sin->din->size) {
  562. sin->din->size = offset + alen;
  563. sin->dirty = 1;
  564. }
  565. return ret;
  566. }
  567. /*
  568. * sfs_io - Rd/Wr file. the wrapper of sfs_io_nolock
  569. with lock protect
  570. */
  571. static inline int
  572. sfs_io(struct inode *node, struct iobuf *iob, bool write) {
  573. struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs);
  574. struct sfs_inode *sin = vop_info(node, sfs_inode);
  575. int ret;
  576. lock_sin(sin);
  577. {
  578. size_t alen = iob->io_resid;
  579. ret = sfs_io_nolock(sfs, sin, iob->io_base, iob->io_offset, &alen, write);
  580. if (alen != 0) {
  581. iobuf_skip(iob, alen);
  582. }
  583. }
  584. unlock_sin(sin);
  585. return ret;
  586. }
  587. // sfs_read - read file
  588. static int
  589. sfs_read(struct inode *node, struct iobuf *iob) {
  590. return sfs_io(node, iob, 0);
  591. }
  592. // sfs_write - write file
  593. static int
  594. sfs_write(struct inode *node, struct iobuf *iob) {
  595. return sfs_io(node, iob, 1);
  596. }
  597. /*
  598. * sfs_fstat - Return nlinks/block/size, etc. info about a file. The pointer is a pointer to struct stat;
  599. */
  600. static int
  601. sfs_fstat(struct inode *node, struct stat *stat) {
  602. int ret;
  603. memset(stat, 0, sizeof(struct stat));
  604. if ((ret = vop_gettype(node, &(stat->st_mode))) != 0) {
  605. return ret;
  606. }
  607. struct sfs_disk_inode *din = vop_info(node, sfs_inode)->din;
  608. stat->st_nlinks = din->nlinks;
  609. stat->st_blocks = din->blocks;
  610. stat->st_size = din->size;
  611. return 0;
  612. }
  613. /*
  614. * sfs_fsync - Force any dirty inode info associated with this file to stable storage.
  615. */
  616. static int
  617. sfs_fsync(struct inode *node) {
  618. struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs);
  619. struct sfs_inode *sin = vop_info(node, sfs_inode);
  620. int ret = 0;
  621. if (sin->dirty) {
  622. lock_sin(sin);
  623. {
  624. if (sin->dirty) {
  625. sin->dirty = 0;
  626. if ((ret = sfs_wbuf(sfs, sin->din, sizeof(struct sfs_disk_inode), sin->ino, 0)) != 0) {
  627. sin->dirty = 1;
  628. }
  629. }
  630. }
  631. unlock_sin(sin);
  632. }
  633. return ret;
  634. }
  635. /*
  636. *sfs_namefile -Compute pathname relative to filesystem root of the file and copy to the specified io buffer.
  637. *
  638. */
  639. static int
  640. sfs_namefile(struct inode *node, struct iobuf *iob) {
  641. struct sfs_disk_entry *entry;
  642. if (iob->io_resid <= 2 || (entry = kmalloc(sizeof(struct sfs_disk_entry))) == NULL) {
  643. return -E_NO_MEM;
  644. }
  645. struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs);
  646. struct sfs_inode *sin = vop_info(node, sfs_inode);
  647. int ret;
  648. char *ptr = iob->io_base + iob->io_resid;
  649. size_t alen, resid = iob->io_resid - 2;
  650. vop_ref_inc(node);
  651. while (1) {
  652. struct inode *parent;
  653. if ((ret = sfs_lookup_once(sfs, sin, "..", &parent, NULL)) != 0) {
  654. goto failed;
  655. }
  656. uint32_t ino = sin->ino;
  657. vop_ref_dec(node);
  658. if (node == parent) {
  659. vop_ref_dec(node);
  660. break;
  661. }
  662. node = parent, sin = vop_info(node, sfs_inode);
  663. assert(ino != sin->ino && sin->din->type == SFS_TYPE_DIR);
  664. lock_sin(sin);
  665. {
  666. ret = sfs_dirent_findino_nolock(sfs, sin, ino, entry);
  667. }
  668. unlock_sin(sin);
  669. if (ret != 0) {
  670. goto failed;
  671. }
  672. if ((alen = strlen(entry->name) + 1) > resid) {
  673. goto failed_nomem;
  674. }
  675. resid -= alen, ptr -= alen;
  676. memcpy(ptr, entry->name, alen - 1);
  677. ptr[alen - 1] = '/';
  678. }
  679. alen = iob->io_resid - resid - 2;
  680. ptr = memmove(iob->io_base + 1, ptr, alen);
  681. ptr[-1] = '/', ptr[alen] = '\0';
  682. iobuf_skip(iob, alen);
  683. kfree(entry);
  684. return 0;
  685. failed_nomem:
  686. ret = -E_NO_MEM;
  687. failed:
  688. vop_ref_dec(node);
  689. kfree(entry);
  690. return ret;
  691. }
  692. /*
  693. * sfs_getdirentry_sub_noblock - get the content of file entry in DIR
  694. */
  695. static int
  696. sfs_getdirentry_sub_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, int slot, struct sfs_disk_entry *entry) {
  697. int ret, i, nslots = sin->din->blocks;
  698. for (i = 0; i < nslots; i ++) {
  699. if ((ret = sfs_dirent_read_nolock(sfs, sin, i, entry)) != 0) {
  700. return ret;
  701. }
  702. if (entry->ino != 0) {
  703. if (slot == 0) {
  704. return 0;
  705. }
  706. slot --;
  707. }
  708. }
  709. return -E_NOENT;
  710. }
  711. /*
  712. * sfs_getdirentry - according to the iob->io_offset, calculate the dir entry's slot in disk block,
  713. get dir entry content from the disk
  714. */
  715. static int
  716. sfs_getdirentry(struct inode *node, struct iobuf *iob) {
  717. struct sfs_disk_entry *entry;
  718. if ((entry = kmalloc(sizeof(struct sfs_disk_entry))) == NULL) {
  719. return -E_NO_MEM;
  720. }
  721. struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs);
  722. struct sfs_inode *sin = vop_info(node, sfs_inode);
  723. int ret, slot;
  724. off_t offset = iob->io_offset;
  725. if (offset < 0 || offset % sfs_dentry_size != 0) {
  726. kfree(entry);
  727. return -E_INVAL;
  728. }
  729. if ((slot = offset / sfs_dentry_size) > sin->din->blocks) {
  730. kfree(entry);
  731. return -E_NOENT;
  732. }
  733. lock_sin(sin);
  734. if ((ret = sfs_getdirentry_sub_nolock(sfs, sin, slot, entry)) != 0) {
  735. unlock_sin(sin);
  736. goto out;
  737. }
  738. unlock_sin(sin);
  739. ret = iobuf_move(iob, entry->name, sfs_dentry_size, 1, NULL);
  740. out:
  741. kfree(entry);
  742. return ret;
  743. }
  744. /*
  745. * sfs_reclaim - Free all resources inode occupied . Called when inode is no longer in use.
  746. */
  747. static int
  748. sfs_reclaim(struct inode *node) {
  749. struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs);
  750. struct sfs_inode *sin = vop_info(node, sfs_inode);
  751. int ret = -E_BUSY;
  752. uint32_t ent;
  753. lock_sfs_fs(sfs);
  754. assert(sin->reclaim_count > 0);
  755. if ((-- sin->reclaim_count) != 0 || inode_ref_count(node) != 0) {
  756. goto failed_unlock;
  757. }
  758. if (sin->din->nlinks == 0) {
  759. if ((ret = vop_truncate(node, 0)) != 0) {
  760. goto failed_unlock;
  761. }
  762. }
  763. if (sin->dirty) {
  764. if ((ret = vop_fsync(node)) != 0) {
  765. goto failed_unlock;
  766. }
  767. }
  768. sfs_remove_links(sin);
  769. unlock_sfs_fs(sfs);
  770. if (sin->din->nlinks == 0) {
  771. sfs_block_free(sfs, sin->ino);
  772. if ((ent = sin->din->indirect) != 0) {
  773. sfs_block_free(sfs, ent);
  774. }
  775. }
  776. kfree(sin->din);
  777. vop_kill(node);
  778. return 0;
  779. failed_unlock:
  780. unlock_sfs_fs(sfs);
  781. return ret;
  782. }
  783. /*
  784. * sfs_gettype - Return type of file. The values for file types are in sfs.h.
  785. */
  786. static int
  787. sfs_gettype(struct inode *node, uint32_t *type_store) {
  788. struct sfs_disk_inode *din = vop_info(node, sfs_inode)->din;
  789. switch (din->type) {
  790. case SFS_TYPE_DIR:
  791. *type_store = S_IFDIR;
  792. return 0;
  793. case SFS_TYPE_FILE:
  794. *type_store = S_IFREG;
  795. return 0;
  796. case SFS_TYPE_LINK:
  797. *type_store = S_IFLNK;
  798. return 0;
  799. }
  800. panic("invalid file type %d.\n", din->type);
  801. }
  802. /*
  803. * sfs_tryseek - Check if seeking to the specified position within the file is legal.
  804. */
  805. static int
  806. sfs_tryseek(struct inode *node, off_t pos) {
  807. if (pos < 0 || pos >= SFS_MAX_FILE_SIZE) {
  808. return -E_INVAL;
  809. }
  810. struct sfs_inode *sin = vop_info(node, sfs_inode);
  811. if (pos > sin->din->size) {
  812. return vop_truncate(node, pos);
  813. }
  814. return 0;
  815. }
  816. /*
  817. * sfs_truncfile : reszie the file with new length
  818. */
  819. static int
  820. sfs_truncfile(struct inode *node, off_t len) {
  821. if (len < 0 || len > SFS_MAX_FILE_SIZE) {
  822. return -E_INVAL;
  823. }
  824. struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs);
  825. struct sfs_inode *sin = vop_info(node, sfs_inode);
  826. struct sfs_disk_inode *din = sin->din;
  827. int ret = 0;
  828. //new number of disk blocks of file
  829. uint32_t nblks, tblks = ROUNDUP_DIV(len, SFS_BLKSIZE);
  830. if (din->size == len) {
  831. assert(tblks == din->blocks);
  832. return 0;
  833. }
  834. lock_sin(sin);
  835. // old number of disk blocks of file
  836. nblks = din->blocks;
  837. if (nblks < tblks) {
  838. // try to enlarge the file size by add new disk block at the end of file
  839. while (nblks != tblks) {
  840. if ((ret = sfs_bmap_load_nolock(sfs, sin, nblks, NULL)) != 0) {
  841. goto out_unlock;
  842. }
  843. nblks ++;
  844. }
  845. }
  846. else if (tblks < nblks) {
  847. // try to reduce the file size
  848. while (tblks != nblks) {
  849. if ((ret = sfs_bmap_truncate_nolock(sfs, sin)) != 0) {
  850. goto out_unlock;
  851. }
  852. nblks --;
  853. }
  854. }
  855. assert(din->blocks == tblks);
  856. din->size = len;
  857. sin->dirty = 1;
  858. out_unlock:
  859. unlock_sin(sin);
  860. return ret;
  861. }
  862. /*
  863. * sfs_lookup - Parse path relative to the passed directory
  864. * DIR, and hand back the inode for the file it
  865. * refers to.
  866. */
  867. static int
  868. sfs_lookup(struct inode *node, char *path, struct inode **node_store) {
  869. struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs);
  870. assert(*path != '\0' && *path != '/');
  871. vop_ref_inc(node);
  872. struct sfs_inode *sin = vop_info(node, sfs_inode);
  873. if (sin->din->type != SFS_TYPE_DIR) {
  874. vop_ref_dec(node);
  875. return -E_NOTDIR;
  876. }
  877. struct inode *subnode;
  878. int ret = sfs_lookup_once(sfs, sin, path, &subnode, NULL);
  879. vop_ref_dec(node);
  880. if (ret != 0) {
  881. return ret;
  882. }
  883. *node_store = subnode;
  884. return 0;
  885. }
  886. // The sfs specific DIR operations correspond to the abstract operations on a inode.
  887. static const struct inode_ops sfs_node_dirops = {
  888. .vop_magic = VOP_MAGIC,
  889. .vop_open = sfs_opendir,
  890. .vop_close = sfs_close,
  891. .vop_fstat = sfs_fstat,
  892. .vop_fsync = sfs_fsync,
  893. .vop_namefile = sfs_namefile,
  894. .vop_getdirentry = sfs_getdirentry,
  895. .vop_reclaim = sfs_reclaim,
  896. .vop_gettype = sfs_gettype,
  897. .vop_lookup = sfs_lookup,
  898. };
  899. /// The sfs specific FILE operations correspond to the abstract operations on a inode.
  900. static const struct inode_ops sfs_node_fileops = {
  901. .vop_magic = VOP_MAGIC,
  902. .vop_open = sfs_openfile,
  903. .vop_close = sfs_close,
  904. .vop_read = sfs_read,
  905. .vop_write = sfs_write,
  906. .vop_fstat = sfs_fstat,
  907. .vop_fsync = sfs_fsync,
  908. .vop_reclaim = sfs_reclaim,
  909. .vop_gettype = sfs_gettype,
  910. .vop_tryseek = sfs_tryseek,
  911. .vop_truncate = sfs_truncfile,
  912. };