vfslist.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. /*
  2. * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
  3. * The President and Fellows of Harvard College.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the University nor the names of its contributors
  14. * may be used to endorse or promote products derived from this software
  15. * without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. */
  29. /*
  30. * VFS operations that involve the list of VFS (named) devices
  31. * (the "dev" in "dev:path" syntax).
  32. */
  33. #define VFSINLINE
  34. #include <types.h>
  35. #include <kern/errno.h>
  36. #include <lib.h>
  37. #include <array.h>
  38. #include <synch.h>
  39. #include <vfs.h>
  40. #include <fs.h>
  41. #include <vnode.h>
  42. #include <device.h>
  43. /*
  44. * Structure for a single named device.
  45. *
  46. * kd_name - Name of device (eg, "lhd0"). Should always be set to
  47. * a valid string.
  48. *
  49. * kd_rawname - Name of raw device (eg, "lhd0raw"). Is non-NULL if and
  50. * only if this device can have a filesystem mounted on
  51. * it.
  52. *
  53. * kd_device - Device object this name refers to. May be NULL if kd_fs
  54. * is hardwired.
  55. *
  56. * kd_fs - Filesystem object mounted on, or associated with, this
  57. * device. NULL if there is no filesystem.
  58. *
  59. * A filesystem can be associated with a device without having been
  60. * mounted if the device was created that way. In this case,
  61. * kd_rawname is NULL (prohibiting mount/unmount), and, as there is
  62. * then no way to access kd_device, it will be NULL as well. This is
  63. * intended for devices that are inherently filesystems, like emu0.
  64. *
  65. * Referencing kd_name, or the filesystem volume name, on a device
  66. * with a filesystem mounted returns the root of the filesystem.
  67. * Referencing kd_name on a mountable device with no filesystem
  68. * returns ENXIO. Referencing kd_name on a device that is not
  69. * mountable and has no filesystem, or kd_rawname on a mountable
  70. * device, returns the device itself.
  71. */
  72. struct knowndev {
  73. char *kd_name;
  74. char *kd_rawname;
  75. struct device *kd_device;
  76. struct vnode *kd_vnode;
  77. struct fs *kd_fs;
  78. };
  79. DECLARRAY(knowndev);
  80. DEFARRAY(knowndev, /*no inline*/);
  81. static struct knowndevarray *knowndevs;
  82. /* The big lock for all FS ops. Remove for filesystem assignment. */
  83. static struct lock *vfs_biglock;
  84. static unsigned vfs_biglock_depth;
  85. /*
  86. * Setup function
  87. */
  88. void
  89. vfs_bootstrap(void)
  90. {
  91. knowndevs = knowndevarray_create();
  92. if (knowndevs==NULL) {
  93. panic("vfs: Could not create knowndevs array\n");
  94. }
  95. vfs_biglock = lock_create("vfs_biglock");
  96. if (vfs_biglock==NULL) {
  97. panic("vfs: Could not create vfs big lock\n");
  98. }
  99. vfs_biglock_depth = 0;
  100. devnull_create();
  101. }
  102. /*
  103. * Operations on vfs_biglock. We make it recursive to avoid having to
  104. * think about where we do and don't already hold it. This is an
  105. * undesirable hack that's frequently necessary when a lock covers too
  106. * much material. Your solution scheme for FS and VFS locking should
  107. * not require recursive locks.
  108. */
  109. void
  110. vfs_biglock_acquire(void)
  111. {
  112. if (!lock_do_i_hold(vfs_biglock)) {
  113. lock_acquire(vfs_biglock);
  114. }
  115. vfs_biglock_depth++;
  116. }
  117. void
  118. vfs_biglock_release(void)
  119. {
  120. KASSERT(lock_do_i_hold(vfs_biglock));
  121. KASSERT(vfs_biglock_depth > 0);
  122. vfs_biglock_depth--;
  123. if (vfs_biglock_depth == 0) {
  124. lock_release(vfs_biglock);
  125. }
  126. }
  127. bool
  128. vfs_biglock_do_i_hold(void)
  129. {
  130. return lock_do_i_hold(vfs_biglock);
  131. }
  132. /*
  133. * Global sync function - call FSOP_SYNC on all devices.
  134. */
  135. int
  136. vfs_sync(void)
  137. {
  138. struct knowndev *dev;
  139. unsigned i, num;
  140. vfs_biglock_acquire();
  141. num = knowndevarray_num(knowndevs);
  142. for (i=0; i<num; i++) {
  143. dev = knowndevarray_get(knowndevs, i);
  144. if (dev->kd_fs != NULL) {
  145. /*result =*/ FSOP_SYNC(dev->kd_fs);
  146. }
  147. }
  148. vfs_biglock_release();
  149. return 0;
  150. }
  151. /*
  152. * Given a device name (lhd0, emu0, somevolname, null, etc.), hand
  153. * back an appropriate vnode.
  154. */
  155. int
  156. vfs_getroot(const char *devname, struct vnode **result)
  157. {
  158. struct knowndev *kd;
  159. unsigned i, num;
  160. KASSERT(vfs_biglock_do_i_hold());
  161. num = knowndevarray_num(knowndevs);
  162. for (i=0; i<num; i++) {
  163. kd = knowndevarray_get(knowndevs, i);
  164. /*
  165. * If this device has a mounted filesystem, and
  166. * DEVNAME names either the filesystem or the device,
  167. * return the root of the filesystem.
  168. *
  169. * If it has no mounted filesystem, it's mountable,
  170. * and DEVNAME names the device, return ENXIO.
  171. */
  172. if (kd->kd_fs!=NULL) {
  173. const char *volname;
  174. volname = FSOP_GETVOLNAME(kd->kd_fs);
  175. if (!strcmp(kd->kd_name, devname) ||
  176. (volname!=NULL && !strcmp(volname, devname))) {
  177. *result = FSOP_GETROOT(kd->kd_fs);
  178. return 0;
  179. }
  180. }
  181. else {
  182. if (kd->kd_rawname!=NULL &&
  183. !strcmp(kd->kd_name, devname)) {
  184. return ENXIO;
  185. }
  186. }
  187. /*
  188. * If DEVNAME names the device, and we get here, it
  189. * must have no fs and not be mountable. In this case,
  190. * we return the device itself.
  191. */
  192. if (!strcmp(kd->kd_name, devname)) {
  193. KASSERT(kd->kd_fs==NULL);
  194. KASSERT(kd->kd_rawname==NULL);
  195. KASSERT(kd->kd_device != NULL);
  196. VOP_INCREF(kd->kd_vnode);
  197. *result = kd->kd_vnode;
  198. return 0;
  199. }
  200. /*
  201. * If the device has a rawname and DEVNAME names that,
  202. * return the device itself.
  203. */
  204. if (kd->kd_rawname!=NULL && !strcmp(kd->kd_rawname, devname)) {
  205. KASSERT(kd->kd_device != NULL);
  206. VOP_INCREF(kd->kd_vnode);
  207. *result = kd->kd_vnode;
  208. return 0;
  209. }
  210. /*
  211. * If none of the above tests matched, we didn't name
  212. * any of the names of this device, so go on to the
  213. * next one.
  214. */
  215. }
  216. /*
  217. * If we got here, the device specified by devname doesn't exist.
  218. */
  219. return ENODEV;
  220. }
  221. /*
  222. * Given a filesystem, hand back the name of the device it's mounted on.
  223. */
  224. const char *
  225. vfs_getdevname(struct fs *fs)
  226. {
  227. struct knowndev *kd;
  228. unsigned i, num;
  229. KASSERT(fs != NULL);
  230. KASSERT(vfs_biglock_do_i_hold());
  231. num = knowndevarray_num(knowndevs);
  232. for (i=0; i<num; i++) {
  233. kd = knowndevarray_get(knowndevs, i);
  234. if (kd->kd_fs == fs) {
  235. /*
  236. * This is not a race condition: as long as the
  237. * guy calling us holds a reference to the fs,
  238. * the fs cannot go away, and the device can't
  239. * go away until the fs goes away.
  240. */
  241. return kd->kd_name;
  242. }
  243. }
  244. return NULL;
  245. }
  246. /*
  247. * Assemble the name for a raw device from the name for the regular device.
  248. */
  249. static
  250. char *
  251. mkrawname(const char *name)
  252. {
  253. char *s = kmalloc(strlen(name)+3+1);
  254. if (!s) {
  255. return NULL;
  256. }
  257. strcpy(s, name);
  258. strcat(s, "raw");
  259. return s;
  260. }
  261. /*
  262. * Check if the two strings passed in are the same, if they're both
  263. * not NULL (the latter part being significant).
  264. */
  265. static
  266. inline
  267. int
  268. samestring(const char *a, const char *b)
  269. {
  270. if (a==NULL || b==NULL) {
  271. return 0;
  272. }
  273. return !strcmp(a, b);
  274. }
  275. /*
  276. * Check if the first string passed is the same as any of the three others,
  277. * if they're not NULL.
  278. */
  279. static
  280. inline
  281. int
  282. samestring3(const char *a, const char *b, const char *c, const char *d)
  283. {
  284. return samestring(a,b) || samestring(a,c) || samestring(a,d);
  285. }
  286. /*
  287. * Check if any of the three names passed in already exists as a device
  288. * name.
  289. */
  290. static
  291. int
  292. badnames(const char *n1, const char *n2, const char *n3)
  293. {
  294. const char *volname;
  295. unsigned i, num;
  296. struct knowndev *kd;
  297. KASSERT(vfs_biglock_do_i_hold());
  298. num = knowndevarray_num(knowndevs);
  299. for (i=0; i<num; i++) {
  300. kd = knowndevarray_get(knowndevs, i);
  301. if (kd->kd_fs) {
  302. volname = FSOP_GETVOLNAME(kd->kd_fs);
  303. if (samestring3(volname, n1, n2, n3)) {
  304. return 1;
  305. }
  306. }
  307. if (samestring3(kd->kd_rawname, n1, n2, n3) ||
  308. samestring3(kd->kd_name, n1, n2, n3)) {
  309. return 1;
  310. }
  311. }
  312. return 0;
  313. }
  314. /*
  315. * Add a new device to the VFS layer's device table.
  316. *
  317. * If "mountable" is set, the device will be treated as one that expects
  318. * to have a filesystem mounted on it, and a raw device will be created
  319. * for direct access.
  320. */
  321. static
  322. int
  323. vfs_doadd(const char *dname, int mountable, struct device *dev, struct fs *fs)
  324. {
  325. char *name=NULL, *rawname=NULL;
  326. struct knowndev *kd=NULL;
  327. struct vnode *vnode=NULL;
  328. const char *volname=NULL;
  329. unsigned index;
  330. int result;
  331. vfs_biglock_acquire();
  332. name = kstrdup(dname);
  333. if (name==NULL) {
  334. goto nomem;
  335. }
  336. if (mountable) {
  337. rawname = mkrawname(name);
  338. if (rawname==NULL) {
  339. goto nomem;
  340. }
  341. }
  342. vnode = dev_create_vnode(dev);
  343. if (vnode==NULL) {
  344. goto nomem;
  345. }
  346. kd = kmalloc(sizeof(struct knowndev));
  347. if (kd==NULL) {
  348. goto nomem;
  349. }
  350. kd->kd_name = name;
  351. kd->kd_rawname = rawname;
  352. kd->kd_device = dev;
  353. kd->kd_vnode = vnode;
  354. kd->kd_fs = fs;
  355. if (fs!=NULL) {
  356. volname = FSOP_GETVOLNAME(fs);
  357. }
  358. if (badnames(name, rawname, volname)) {
  359. vfs_biglock_release();
  360. return EEXIST;
  361. }
  362. result = knowndevarray_add(knowndevs, kd, &index);
  363. if (result == 0 && dev != NULL) {
  364. /* use index+1 as the device number, so 0 is reserved */
  365. dev->d_devnumber = index+1;
  366. }
  367. vfs_biglock_release();
  368. return result;
  369. nomem:
  370. if (name) {
  371. kfree(name);
  372. }
  373. if (rawname) {
  374. kfree(rawname);
  375. }
  376. if (vnode) {
  377. kfree(vnode);
  378. }
  379. if (kd) {
  380. kfree(kd);
  381. }
  382. vfs_biglock_release();
  383. return ENOMEM;
  384. }
  385. /*
  386. * Add a new device, by name. See above for the description of
  387. * mountable.
  388. */
  389. int
  390. vfs_adddev(const char *devname, struct device *dev, int mountable)
  391. {
  392. return vfs_doadd(devname, mountable, dev, NULL);
  393. }
  394. /*
  395. * Add a filesystem that does not have an underlying device.
  396. * This is used for emufs, but might also be used for network
  397. * filesystems and the like.
  398. */
  399. int
  400. vfs_addfs(const char *devname, struct fs *fs)
  401. {
  402. return vfs_doadd(devname, 0, NULL, fs);
  403. }
  404. //////////////////////////////////////////////////
  405. /*
  406. * Look for a mountable device named DEVNAME.
  407. * Should already hold knowndevs_lock.
  408. */
  409. static
  410. int
  411. findmount(const char *devname, struct knowndev **result)
  412. {
  413. struct knowndev *dev;
  414. unsigned i, num;
  415. bool found = false;
  416. KASSERT(vfs_biglock_do_i_hold());
  417. num = knowndevarray_num(knowndevs);
  418. for (i=0; !found && i<num; i++) {
  419. dev = knowndevarray_get(knowndevs, i);
  420. if (dev->kd_rawname==NULL) {
  421. /* not mountable/unmountable */
  422. continue;
  423. }
  424. if (!strcmp(devname, dev->kd_name)) {
  425. *result = dev;
  426. found = true;
  427. }
  428. }
  429. return found ? 0 : ENODEV;
  430. }
  431. /*
  432. * Mount a filesystem. Once we've found the device, call MOUNTFUNC to
  433. * set up the filesystem and hand back a struct fs.
  434. *
  435. * The DATA argument is passed through unchanged to MOUNTFUNC.
  436. */
  437. int
  438. vfs_mount(const char *devname, void *data,
  439. int (*mountfunc)(void *data, struct device *, struct fs **ret))
  440. {
  441. const char *volname;
  442. struct knowndev *kd;
  443. struct fs *fs;
  444. int result;
  445. vfs_biglock_acquire();
  446. result = findmount(devname, &kd);
  447. if (result) {
  448. vfs_biglock_release();
  449. return result;
  450. }
  451. if (kd->kd_fs != NULL) {
  452. vfs_biglock_release();
  453. return EBUSY;
  454. }
  455. KASSERT(kd->kd_rawname != NULL);
  456. KASSERT(kd->kd_device != NULL);
  457. result = mountfunc(data, kd->kd_device, &fs);
  458. if (result) {
  459. vfs_biglock_release();
  460. return result;
  461. }
  462. KASSERT(fs != NULL);
  463. kd->kd_fs = fs;
  464. volname = FSOP_GETVOLNAME(fs);
  465. kprintf("vfs: Mounted %s: on %s\n",
  466. volname ? volname : kd->kd_name, kd->kd_name);
  467. vfs_biglock_release();
  468. return 0;
  469. }
  470. /*
  471. * Unmount a filesystem/device by name.
  472. * First calls FSOP_SYNC on the filesystem; then calls FSOP_UNMOUNT.
  473. */
  474. int
  475. vfs_unmount(const char *devname)
  476. {
  477. struct knowndev *kd;
  478. int result;
  479. vfs_biglock_acquire();
  480. result = findmount(devname, &kd);
  481. if (result) {
  482. goto fail;
  483. }
  484. if (kd->kd_fs == NULL) {
  485. result = EINVAL;
  486. goto fail;
  487. }
  488. KASSERT(kd->kd_rawname != NULL);
  489. KASSERT(kd->kd_device != NULL);
  490. result = FSOP_SYNC(kd->kd_fs);
  491. if (result) {
  492. goto fail;
  493. }
  494. result = FSOP_UNMOUNT(kd->kd_fs);
  495. if (result) {
  496. goto fail;
  497. }
  498. kprintf("vfs: Unmounted %s:\n", kd->kd_name);
  499. /* now drop the filesystem */
  500. kd->kd_fs = NULL;
  501. KASSERT(result==0);
  502. fail:
  503. vfs_biglock_release();
  504. return result;
  505. }
  506. /*
  507. * Global unmount function.
  508. */
  509. int
  510. vfs_unmountall(void)
  511. {
  512. struct knowndev *dev;
  513. unsigned i, num;
  514. int result;
  515. vfs_biglock_acquire();
  516. num = knowndevarray_num(knowndevs);
  517. for (i=0; i<num; i++) {
  518. dev = knowndevarray_get(knowndevs, i);
  519. if (dev->kd_rawname == NULL) {
  520. /* not mountable/unmountable */
  521. continue;
  522. }
  523. if (dev->kd_fs == NULL) {
  524. /* not mounted */
  525. continue;
  526. }
  527. kprintf("vfs: Unmounting %s:\n", dev->kd_name);
  528. result = FSOP_SYNC(dev->kd_fs);
  529. if (result) {
  530. kprintf("vfs: Warning: sync failed for %s: %s, trying "
  531. "again\n", dev->kd_name, strerror(result));
  532. result = FSOP_SYNC(dev->kd_fs);
  533. if (result) {
  534. kprintf("vfs: Warning: sync failed second time"
  535. " for %s: %s, giving up...\n",
  536. dev->kd_name, strerror(result));
  537. continue;
  538. }
  539. }
  540. result = FSOP_UNMOUNT(dev->kd_fs);
  541. if (result == EBUSY) {
  542. kprintf("vfs: Cannot unmount %s: (busy)\n",
  543. dev->kd_name);
  544. continue;
  545. }
  546. if (result) {
  547. kprintf("vfs: Warning: unmount failed for %s:"
  548. " %s, already synced, dropping...\n",
  549. dev->kd_name, strerror(result));
  550. continue;
  551. }
  552. /* now drop the filesystem */
  553. dev->kd_fs = NULL;
  554. }
  555. vfs_biglock_release();
  556. return 0;
  557. }