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

309 lines
7.9 KiB

12 years ago
  1. #include <defs.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <vfs.h>
  5. #include <dev.h>
  6. #include <inode.h>
  7. #include <sem.h>
  8. #include <list.h>
  9. #include <kmalloc.h>
  10. #include <unistd.h>
  11. #include <error.h>
  12. #include <assert.h>
  13. // device info entry in vdev_list
  14. typedef struct {
  15. const char *devname;
  16. struct inode *devnode;
  17. struct fs *fs;
  18. bool mountable;
  19. list_entry_t vdev_link;
  20. } vfs_dev_t;
  21. #define le2vdev(le, member) \
  22. to_struct((le), vfs_dev_t, member)
  23. static list_entry_t vdev_list; // device info list in vfs layer
  24. static semaphore_t vdev_list_sem;
  25. static void
  26. lock_vdev_list(void) {
  27. down(&vdev_list_sem);
  28. }
  29. static void
  30. unlock_vdev_list(void) {
  31. up(&vdev_list_sem);
  32. }
  33. void
  34. vfs_devlist_init(void) {
  35. list_init(&vdev_list);
  36. sem_init(&vdev_list_sem, 1);
  37. }
  38. // vfs_cleanup - finally clean (or sync) fs
  39. void
  40. vfs_cleanup(void) {
  41. if (!list_empty(&vdev_list)) {
  42. lock_vdev_list();
  43. {
  44. list_entry_t *list = &vdev_list, *le = list;
  45. while ((le = list_next(le)) != list) {
  46. vfs_dev_t *vdev = le2vdev(le, vdev_link);
  47. if (vdev->fs != NULL) {
  48. fsop_cleanup(vdev->fs);
  49. }
  50. }
  51. }
  52. unlock_vdev_list();
  53. }
  54. }
  55. /*
  56. * vfs_get_root - Given a device name (stdin, stdout, etc.), hand
  57. * back an appropriate inode.
  58. */
  59. int
  60. vfs_get_root(const char *devname, struct inode **node_store) {
  61. assert(devname != NULL);
  62. int ret = -E_NO_DEV;
  63. if (!list_empty(&vdev_list)) {
  64. lock_vdev_list();
  65. {
  66. list_entry_t *list = &vdev_list, *le = list;
  67. while ((le = list_next(le)) != list) {
  68. vfs_dev_t *vdev = le2vdev(le, vdev_link);
  69. if (strcmp(devname, vdev->devname) == 0) {
  70. struct inode *found = NULL;
  71. if (vdev->fs != NULL) {
  72. found = fsop_get_root(vdev->fs);
  73. }
  74. else if (!vdev->mountable) {
  75. vop_ref_inc(vdev->devnode);
  76. found = vdev->devnode;
  77. }
  78. if (found != NULL) {
  79. ret = 0, *node_store = found;
  80. }
  81. else {
  82. ret = -E_NA_DEV;
  83. }
  84. break;
  85. }
  86. }
  87. }
  88. unlock_vdev_list();
  89. }
  90. return ret;
  91. }
  92. /*
  93. * vfs_get_devname - Given a filesystem, hand back the name of the device it's mounted on.
  94. */
  95. const char *
  96. vfs_get_devname(struct fs *fs) {
  97. assert(fs != NULL);
  98. list_entry_t *list = &vdev_list, *le = list;
  99. while ((le = list_next(le)) != list) {
  100. vfs_dev_t *vdev = le2vdev(le, vdev_link);
  101. if (vdev->fs == fs) {
  102. return vdev->devname;
  103. }
  104. }
  105. return NULL;
  106. }
  107. /*
  108. * check_devname_confilct - Is there alreadily device which has the same name?
  109. */
  110. static bool
  111. check_devname_conflict(const char *devname) {
  112. list_entry_t *list = &vdev_list, *le = list;
  113. while ((le = list_next(le)) != list) {
  114. vfs_dev_t *vdev = le2vdev(le, vdev_link);
  115. if (strcmp(vdev->devname, devname) == 0) {
  116. return 0;
  117. }
  118. }
  119. return 1;
  120. }
  121. /*
  122. * vfs_do_add - Add a new device to the VFS layer's device table.
  123. *
  124. * If "mountable" is set, the device will be treated as one that expects
  125. * to have a filesystem mounted on it, and a raw device will be created
  126. * for direct access.
  127. */
  128. static int
  129. vfs_do_add(const char *devname, struct inode *devnode, struct fs *fs, bool mountable) {
  130. assert(devname != NULL);
  131. assert((devnode == NULL && !mountable) || (devnode != NULL && check_inode_type(devnode, device)));
  132. if (strlen(devname) > FS_MAX_DNAME_LEN) {
  133. return -E_TOO_BIG;
  134. }
  135. int ret = -E_NO_MEM;
  136. char *s_devname;
  137. if ((s_devname = strdup(devname)) == NULL) {
  138. return ret;
  139. }
  140. vfs_dev_t *vdev;
  141. if ((vdev = kmalloc(sizeof(vfs_dev_t))) == NULL) {
  142. goto failed_cleanup_name;
  143. }
  144. ret = -E_EXISTS;
  145. lock_vdev_list();
  146. if (!check_devname_conflict(s_devname)) {
  147. unlock_vdev_list();
  148. goto failed_cleanup_vdev;
  149. }
  150. vdev->devname = s_devname;
  151. vdev->devnode = devnode;
  152. vdev->mountable = mountable;
  153. vdev->fs = fs;
  154. list_add(&vdev_list, &(vdev->vdev_link));
  155. unlock_vdev_list();
  156. return 0;
  157. failed_cleanup_vdev:
  158. kfree(vdev);
  159. failed_cleanup_name:
  160. kfree(s_devname);
  161. return ret;
  162. }
  163. /*
  164. * vfs_add_fs - Add a new fs, by name. See vfs_do_add information for the description of
  165. * mountable.
  166. */
  167. int
  168. vfs_add_fs(const char *devname, struct fs *fs) {
  169. return vfs_do_add(devname, NULL, fs, 0);
  170. }
  171. /*
  172. * vfs_add_dev - Add a new device, by name. See vfs_do_add information for the description of
  173. * mountable.
  174. */
  175. int
  176. vfs_add_dev(const char *devname, struct inode *devnode, bool mountable) {
  177. return vfs_do_add(devname, devnode, NULL, mountable);
  178. }
  179. /*
  180. * find_mount - Look for a mountable device named DEVNAME.
  181. * Should already hold vdev_list lock.
  182. */
  183. static int
  184. find_mount(const char *devname, vfs_dev_t **vdev_store) {
  185. assert(devname != NULL);
  186. list_entry_t *list = &vdev_list, *le = list;
  187. while ((le = list_next(le)) != list) {
  188. vfs_dev_t *vdev = le2vdev(le, vdev_link);
  189. if (vdev->mountable && strcmp(vdev->devname, devname) == 0) {
  190. *vdev_store = vdev;
  191. return 0;
  192. }
  193. }
  194. return -E_NO_DEV;
  195. }
  196. /*
  197. * vfs_mount - Mount a filesystem. Once we've found the device, call MOUNTFUNC to
  198. * set up the filesystem and hand back a struct fs.
  199. *
  200. * The DATA argument is passed through unchanged to MOUNTFUNC.
  201. */
  202. int
  203. vfs_mount(const char *devname, int (*mountfunc)(struct device *dev, struct fs **fs_store)) {
  204. int ret;
  205. lock_vdev_list();
  206. vfs_dev_t *vdev;
  207. if ((ret = find_mount(devname, &vdev)) != 0) {
  208. goto out;
  209. }
  210. if (vdev->fs != NULL) {
  211. ret = -E_BUSY;
  212. goto out;
  213. }
  214. assert(vdev->devname != NULL && vdev->mountable);
  215. struct device *dev = vop_info(vdev->devnode, device);
  216. if ((ret = mountfunc(dev, &(vdev->fs))) == 0) {
  217. assert(vdev->fs != NULL);
  218. cprintf("vfs: mount %s.\n", vdev->devname);
  219. }
  220. out:
  221. unlock_vdev_list();
  222. return ret;
  223. }
  224. /*
  225. * vfs_unmount - Unmount a filesystem/device by name.
  226. * First calls FSOP_SYNC on the filesystem; then calls FSOP_UNMOUNT.
  227. */
  228. int
  229. vfs_unmount(const char *devname) {
  230. int ret;
  231. lock_vdev_list();
  232. vfs_dev_t *vdev;
  233. if ((ret = find_mount(devname, &vdev)) != 0) {
  234. goto out;
  235. }
  236. if (vdev->fs == NULL) {
  237. ret = -E_INVAL;
  238. goto out;
  239. }
  240. assert(vdev->devname != NULL && vdev->mountable);
  241. if ((ret = fsop_sync(vdev->fs)) != 0) {
  242. goto out;
  243. }
  244. if ((ret = fsop_unmount(vdev->fs)) == 0) {
  245. vdev->fs = NULL;
  246. cprintf("vfs: unmount %s.\n", vdev->devname);
  247. }
  248. out:
  249. unlock_vdev_list();
  250. return ret;
  251. }
  252. /*
  253. * vfs_unmount_all - Global unmount function.
  254. */
  255. int
  256. vfs_unmount_all(void) {
  257. if (!list_empty(&vdev_list)) {
  258. lock_vdev_list();
  259. {
  260. list_entry_t *list = &vdev_list, *le = list;
  261. while ((le = list_next(le)) != list) {
  262. vfs_dev_t *vdev = le2vdev(le, vdev_link);
  263. if (vdev->mountable && vdev->fs != NULL) {
  264. int ret;
  265. if ((ret = fsop_sync(vdev->fs)) != 0) {
  266. cprintf("vfs: warning: sync failed for %s: %e.\n", vdev->devname, ret);
  267. continue ;
  268. }
  269. if ((ret = fsop_unmount(vdev->fs)) != 0) {
  270. cprintf("vfs: warning: unmount failed for %s: %e.\n", vdev->devname, ret);
  271. continue ;
  272. }
  273. vdev->fs = NULL;
  274. cprintf("vfs: unmount %s.\n", vdev->devname);
  275. }
  276. }
  277. }
  278. unlock_vdev_list();
  279. }
  280. return 0;
  281. }