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 }