00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #define VFSINLINE
00036
00037 #include <types.h>
00038 #include <kern/errno.h>
00039 #include <lib.h>
00040 #include <array.h>
00041 #include <synch.h>
00042 #include <vfs.h>
00043 #include <fs.h>
00044 #include <vnode.h>
00045 #include <device.h>
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077 struct knowndev {
00078 char *kd_name;
00079 char *kd_rawname;
00080 struct device *kd_device;
00081 struct vnode *kd_vnode;
00082 struct fs *kd_fs;
00083 };
00084
00085 DECLARRAY(knowndev);
00086 DEFARRAY(knowndev, );
00087
00088 static struct knowndevarray *knowndevs;
00089
00090
00091 static struct lock *vfs_biglock;
00092 static unsigned vfs_biglock_depth;
00093
00094
00095
00096
00097
00098 void
00099 vfs_bootstrap(void)
00100 {
00101 knowndevs = knowndevarray_create();
00102 if (knowndevs==NULL) {
00103 panic("vfs: Could not create knowndevs array\n");
00104 }
00105
00106 vfs_biglock = lock_create("vfs_biglock");
00107 if (vfs_biglock==NULL) {
00108 panic("vfs: Could not create vfs big lock\n");
00109 }
00110 vfs_biglock_depth = 0;
00111
00112 devnull_create();
00113 }
00114
00115
00116
00117
00118
00119
00120
00121
00122 void
00123 vfs_biglock_acquire(void)
00124 {
00125 if (!lock_do_i_hold(vfs_biglock)) {
00126 lock_acquire(vfs_biglock);
00127 }
00128 vfs_biglock_depth++;
00129 }
00130
00131 void
00132 vfs_biglock_release(void)
00133 {
00134 KASSERT(lock_do_i_hold(vfs_biglock));
00135 KASSERT(vfs_biglock_depth > 0);
00136 vfs_biglock_depth--;
00137 if (vfs_biglock_depth == 0) {
00138 lock_release(vfs_biglock);
00139 }
00140 }
00141
00142 bool
00143 vfs_biglock_do_i_hold(void)
00144 {
00145 return lock_do_i_hold(vfs_biglock);
00146 }
00147
00148
00149
00150
00151 int
00152 vfs_sync(void)
00153 {
00154 struct knowndev *dev;
00155 unsigned i, num;
00156
00157 vfs_biglock_acquire();
00158
00159 num = knowndevarray_num(knowndevs);
00160 for (i=0; i<num; i++) {
00161 dev = knowndevarray_get(knowndevs, i);
00162 if (dev->kd_fs != NULL) {
00163 FSOP_SYNC(dev->kd_fs);
00164 }
00165 }
00166
00167 vfs_biglock_release();
00168
00169 return 0;
00170 }
00171
00172
00173
00174
00175
00176 int
00177 vfs_getroot(const char *devname, struct vnode **result)
00178 {
00179 struct knowndev *kd;
00180 unsigned i, num;
00181
00182 KASSERT(vfs_biglock_do_i_hold());
00183
00184 num = knowndevarray_num(knowndevs);
00185 for (i=0; i<num; i++) {
00186 kd = knowndevarray_get(knowndevs, i);
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197 if (kd->kd_fs!=NULL) {
00198 const char *volname;
00199 volname = FSOP_GETVOLNAME(kd->kd_fs);
00200
00201 if (!strcmp(kd->kd_name, devname) ||
00202 (volname!=NULL && !strcmp(volname, devname))) {
00203 *result = FSOP_GETROOT(kd->kd_fs);
00204 return 0;
00205 }
00206 }
00207 else {
00208 if (kd->kd_rawname!=NULL &&
00209 !strcmp(kd->kd_name, devname)) {
00210 return ENXIO;
00211 }
00212 }
00213
00214
00215
00216
00217
00218
00219 if (!strcmp(kd->kd_name, devname)) {
00220 KASSERT(kd->kd_fs==NULL);
00221 KASSERT(kd->kd_rawname==NULL);
00222 KASSERT(kd->kd_device != NULL);
00223 VOP_INCREF(kd->kd_vnode);
00224 *result = kd->kd_vnode;
00225 return 0;
00226 }
00227
00228
00229
00230
00231
00232 if (kd->kd_rawname!=NULL && !strcmp(kd->kd_rawname, devname)) {
00233 KASSERT(kd->kd_device != NULL);
00234 VOP_INCREF(kd->kd_vnode);
00235 *result = kd->kd_vnode;
00236 return 0;
00237 }
00238
00239
00240
00241
00242
00243
00244 }
00245
00246
00247
00248
00249
00250 return ENODEV;
00251 }
00252
00253
00254
00255
00256 const char *
00257 vfs_getdevname(struct fs *fs)
00258 {
00259 struct knowndev *kd;
00260 unsigned i, num;
00261
00262 KASSERT(fs != NULL);
00263
00264 KASSERT(vfs_biglock_do_i_hold());
00265
00266 num = knowndevarray_num(knowndevs);
00267 for (i=0; i<num; i++) {
00268 kd = knowndevarray_get(knowndevs, i);
00269
00270 if (kd->kd_fs == fs) {
00271
00272
00273
00274
00275
00276
00277 return kd->kd_name;
00278 }
00279 }
00280
00281 return NULL;
00282 }
00283
00284
00285
00286
00287 static
00288 char *
00289 mkrawname(const char *name)
00290 {
00291 char *s = kmalloc(strlen(name)+3+1);
00292 if (!s) {
00293 return NULL;
00294 }
00295 strcpy(s, name);
00296 strcat(s, "raw");
00297 return s;
00298 }
00299
00300
00301
00302
00303
00304
00305 static
00306 inline
00307 int
00308 samestring(const char *a, const char *b)
00309 {
00310 if (a==NULL || b==NULL) {
00311 return 0;
00312 }
00313 return !strcmp(a, b);
00314 }
00315
00316
00317
00318
00319
00320 static
00321 inline
00322 int
00323 samestring3(const char *a, const char *b, const char *c, const char *d)
00324 {
00325 return samestring(a,b) || samestring(a,c) || samestring(a,d);
00326 }
00327
00328
00329
00330
00331
00332
00333 static
00334 int
00335 badnames(const char *n1, const char *n2, const char *n3)
00336 {
00337 const char *volname;
00338 unsigned i, num;
00339 struct knowndev *kd;
00340
00341 KASSERT(vfs_biglock_do_i_hold());
00342
00343 num = knowndevarray_num(knowndevs);
00344 for (i=0; i<num; i++) {
00345 kd = knowndevarray_get(knowndevs, i);
00346
00347 if (kd->kd_fs) {
00348 volname = FSOP_GETVOLNAME(kd->kd_fs);
00349 if (samestring3(volname, n1, n2, n3)) {
00350 return 1;
00351 }
00352 }
00353
00354 if (samestring3(kd->kd_rawname, n1, n2, n3) ||
00355 samestring3(kd->kd_name, n1, n2, n3)) {
00356 return 1;
00357 }
00358 }
00359
00360 return 0;
00361 }
00362
00363
00364
00365
00366
00367
00368
00369
00370 static
00371 int
00372 vfs_doadd(const char *dname, int mountable, struct device *dev, struct fs *fs)
00373 {
00374 char *name=NULL, *rawname=NULL;
00375 struct knowndev *kd=NULL;
00376 struct vnode *vnode=NULL;
00377 const char *volname=NULL;
00378 unsigned index;
00379 int result;
00380
00381 vfs_biglock_acquire();
00382
00383 name = kstrdup(dname);
00384 if (name==NULL) {
00385 goto nomem;
00386 }
00387 if (mountable) {
00388 rawname = mkrawname(name);
00389 if (rawname==NULL) {
00390 goto nomem;
00391 }
00392 }
00393
00394 vnode = dev_create_vnode(dev);
00395 if (vnode==NULL) {
00396 goto nomem;
00397 }
00398
00399 kd = kmalloc(sizeof(struct knowndev));
00400 if (kd==NULL) {
00401 goto nomem;
00402 }
00403
00404 kd->kd_name = name;
00405 kd->kd_rawname = rawname;
00406 kd->kd_device = dev;
00407 kd->kd_vnode = vnode;
00408 kd->kd_fs = fs;
00409
00410 if (fs!=NULL) {
00411 volname = FSOP_GETVOLNAME(fs);
00412 }
00413
00414 if (badnames(name, rawname, volname)) {
00415 vfs_biglock_release();
00416 return EEXIST;
00417 }
00418
00419 result = knowndevarray_add(knowndevs, kd, &index);
00420
00421 if (result == 0 && dev != NULL) {
00422
00423 dev->d_devnumber = index+1;
00424 }
00425
00426 vfs_biglock_release();
00427 return result;
00428
00429 nomem:
00430
00431 if (name) {
00432 kfree(name);
00433 }
00434 if (rawname) {
00435 kfree(rawname);
00436 }
00437 if (vnode) {
00438 kfree(vnode);
00439 }
00440 if (kd) {
00441 kfree(kd);
00442 }
00443
00444 vfs_biglock_release();
00445 return ENOMEM;
00446 }
00447
00448
00449
00450
00451
00452 int
00453 vfs_adddev(const char *devname, struct device *dev, int mountable)
00454 {
00455 return vfs_doadd(devname, mountable, dev, NULL);
00456 }
00457
00458
00459
00460
00461
00462
00463 int
00464 vfs_addfs(const char *devname, struct fs *fs)
00465 {
00466 return vfs_doadd(devname, 0, NULL, fs);
00467 }
00468
00469
00470
00471
00472
00473
00474
00475 static
00476 int
00477 findmount(const char *devname, struct knowndev **result)
00478 {
00479 struct knowndev *dev;
00480 unsigned i, num;
00481 bool found = false;
00482
00483 KASSERT(vfs_biglock_do_i_hold());
00484
00485 num = knowndevarray_num(knowndevs);
00486 for (i=0; !found && i<num; i++) {
00487 dev = knowndevarray_get(knowndevs, i);
00488 if (dev->kd_rawname==NULL) {
00489
00490 continue;
00491 }
00492
00493 if (!strcmp(devname, dev->kd_name)) {
00494 *result = dev;
00495 found = true;
00496 }
00497 }
00498
00499 return found ? 0 : ENODEV;
00500 }
00501
00502
00503
00504
00505
00506
00507
00508 int
00509 vfs_mount(const char *devname, void *data,
00510 int (*mountfunc)(void *data, struct device *, struct fs **ret))
00511 {
00512 const char *volname;
00513 struct knowndev *kd;
00514 struct fs *fs;
00515 int result;
00516
00517 vfs_biglock_acquire();
00518
00519 result = findmount(devname, &kd);
00520 if (result) {
00521 vfs_biglock_release();
00522 return result;
00523 }
00524
00525 if (kd->kd_fs != NULL) {
00526 vfs_biglock_release();
00527 return EBUSY;
00528 }
00529 KASSERT(kd->kd_rawname != NULL);
00530 KASSERT(kd->kd_device != NULL);
00531
00532 result = mountfunc(data, kd->kd_device, &fs);
00533 if (result) {
00534 vfs_biglock_release();
00535 return result;
00536 }
00537
00538 KASSERT(fs != NULL);
00539
00540 kd->kd_fs = fs;
00541
00542 volname = FSOP_GETVOLNAME(fs);
00543 kprintf("vfs: Mounted %s: on %s\n",
00544 volname ? volname : kd->kd_name, kd->kd_name);
00545
00546 vfs_biglock_release();
00547 return 0;
00548 }
00549
00550
00551
00552
00553
00554 int
00555 vfs_unmount(const char *devname)
00556 {
00557 struct knowndev *kd;
00558 int result;
00559
00560 vfs_biglock_acquire();
00561
00562 result = findmount(devname, &kd);
00563 if (result) {
00564 goto fail;
00565 }
00566
00567 if (kd->kd_fs == NULL) {
00568 result = EINVAL;
00569 goto fail;
00570 }
00571 KASSERT(kd->kd_rawname != NULL);
00572 KASSERT(kd->kd_device != NULL);
00573
00574 result = FSOP_SYNC(kd->kd_fs);
00575 if (result) {
00576 goto fail;
00577 }
00578
00579 result = FSOP_UNMOUNT(kd->kd_fs);
00580 if (result) {
00581 goto fail;
00582 }
00583
00584 kprintf("vfs: Unmounted %s:\n", kd->kd_name);
00585
00586
00587 kd->kd_fs = NULL;
00588
00589 KASSERT(result==0);
00590
00591 fail:
00592 vfs_biglock_release();
00593 return result;
00594 }
00595
00596
00597
00598
00599 int
00600 vfs_unmountall(void)
00601 {
00602 struct knowndev *dev;
00603 unsigned i, num;
00604 int result;
00605
00606 vfs_biglock_acquire();
00607
00608 num = knowndevarray_num(knowndevs);
00609 for (i=0; i<num; i++) {
00610 dev = knowndevarray_get(knowndevs, i);
00611 if (dev->kd_rawname == NULL) {
00612
00613 continue;
00614 }
00615 if (dev->kd_fs == NULL) {
00616
00617 continue;
00618 }
00619
00620 kprintf("vfs: Unmounting %s:\n", dev->kd_name);
00621
00622 result = FSOP_SYNC(dev->kd_fs);
00623 if (result) {
00624 kprintf("vfs: Warning: sync failed for %s: %s, trying "
00625 "again\n", dev->kd_name, strerror(result));
00626
00627 result = FSOP_SYNC(dev->kd_fs);
00628 if (result) {
00629 kprintf("vfs: Warning: sync failed second time"
00630 " for %s: %s, giving up...\n",
00631 dev->kd_name, strerror(result));
00632 continue;
00633 }
00634 }
00635
00636 result = FSOP_UNMOUNT(dev->kd_fs);
00637 if (result == EBUSY) {
00638 kprintf("vfs: Cannot unmount %s: (busy)\n",
00639 dev->kd_name);
00640 continue;
00641 }
00642 if (result) {
00643 kprintf("vfs: Warning: unmount failed for %s:"
00644 " %s, already synced, dropping...\n",
00645 dev->kd_name, strerror(result));
00646 continue;
00647 }
00648
00649
00650 dev->kd_fs = NULL;
00651 }
00652
00653 vfs_biglock_release();
00654
00655 return 0;
00656 }