Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
script3r
GitHub Repository: script3r/os161
Path: blob/master/kern/vfs/vfslist.c
2093 views
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
/*
31
* VFS operations that involve the list of VFS (named) devices
32
* (the "dev" in "dev:path" syntax).
33
*/
34
35
#define VFSINLINE
36
37
#include <types.h>
38
#include <kern/errno.h>
39
#include <lib.h>
40
#include <array.h>
41
#include <synch.h>
42
#include <vfs.h>
43
#include <fs.h>
44
#include <vnode.h>
45
#include <device.h>
46
47
/*
48
* Structure for a single named device.
49
*
50
* kd_name - Name of device (eg, "lhd0"). Should always be set to
51
* a valid string.
52
*
53
* kd_rawname - Name of raw device (eg, "lhd0raw"). Is non-NULL if and
54
* only if this device can have a filesystem mounted on
55
* it.
56
*
57
* kd_device - Device object this name refers to. May be NULL if kd_fs
58
* is hardwired.
59
*
60
* kd_fs - Filesystem object mounted on, or associated with, this
61
* device. NULL if there is no filesystem.
62
*
63
* A filesystem can be associated with a device without having been
64
* mounted if the device was created that way. In this case,
65
* kd_rawname is NULL (prohibiting mount/unmount), and, as there is
66
* then no way to access kd_device, it will be NULL as well. This is
67
* intended for devices that are inherently filesystems, like emu0.
68
*
69
* Referencing kd_name, or the filesystem volume name, on a device
70
* with a filesystem mounted returns the root of the filesystem.
71
* Referencing kd_name on a mountable device with no filesystem
72
* returns ENXIO. Referencing kd_name on a device that is not
73
* mountable and has no filesystem, or kd_rawname on a mountable
74
* device, returns the device itself.
75
*/
76
77
struct knowndev {
78
char *kd_name;
79
char *kd_rawname;
80
struct device *kd_device;
81
struct vnode *kd_vnode;
82
struct fs *kd_fs;
83
};
84
85
DECLARRAY(knowndev);
86
DEFARRAY(knowndev, /*no inline*/);
87
88
static struct knowndevarray *knowndevs;
89
90
/* The big lock for all FS ops. Remove for filesystem assignment. */
91
static struct lock *vfs_biglock;
92
static unsigned vfs_biglock_depth;
93
94
95
/*
96
* Setup function
97
*/
98
void
99
vfs_bootstrap(void)
100
{
101
knowndevs = knowndevarray_create();
102
if (knowndevs==NULL) {
103
panic("vfs: Could not create knowndevs array\n");
104
}
105
106
vfs_biglock = lock_create("vfs_biglock");
107
if (vfs_biglock==NULL) {
108
panic("vfs: Could not create vfs big lock\n");
109
}
110
vfs_biglock_depth = 0;
111
112
devnull_create();
113
}
114
115
/*
116
* Operations on vfs_biglock. We make it recursive to avoid having to
117
* think about where we do and don't already hold it. This is an
118
* undesirable hack that's frequently necessary when a lock covers too
119
* much material. Your solution scheme for FS and VFS locking should
120
* not require recursive locks.
121
*/
122
void
123
vfs_biglock_acquire(void)
124
{
125
if (!lock_do_i_hold(vfs_biglock)) {
126
lock_acquire(vfs_biglock);
127
}
128
vfs_biglock_depth++;
129
}
130
131
void
132
vfs_biglock_release(void)
133
{
134
KASSERT(lock_do_i_hold(vfs_biglock));
135
KASSERT(vfs_biglock_depth > 0);
136
vfs_biglock_depth--;
137
if (vfs_biglock_depth == 0) {
138
lock_release(vfs_biglock);
139
}
140
}
141
142
bool
143
vfs_biglock_do_i_hold(void)
144
{
145
return lock_do_i_hold(vfs_biglock);
146
}
147
148
/*
149
* Global sync function - call FSOP_SYNC on all devices.
150
*/
151
int
152
vfs_sync(void)
153
{
154
struct knowndev *dev;
155
unsigned i, num;
156
157
vfs_biglock_acquire();
158
159
num = knowndevarray_num(knowndevs);
160
for (i=0; i<num; i++) {
161
dev = knowndevarray_get(knowndevs, i);
162
if (dev->kd_fs != NULL) {
163
/*result =*/ FSOP_SYNC(dev->kd_fs);
164
}
165
}
166
167
vfs_biglock_release();
168
169
return 0;
170
}
171
172
/*
173
* Given a device name (lhd0, emu0, somevolname, null, etc.), hand
174
* back an appropriate vnode.
175
*/
176
int
177
vfs_getroot(const char *devname, struct vnode **result)
178
{
179
struct knowndev *kd;
180
unsigned i, num;
181
182
KASSERT(vfs_biglock_do_i_hold());
183
184
num = knowndevarray_num(knowndevs);
185
for (i=0; i<num; i++) {
186
kd = knowndevarray_get(knowndevs, i);
187
188
/*
189
* If this device has a mounted filesystem, and
190
* DEVNAME names either the filesystem or the device,
191
* return the root of the filesystem.
192
*
193
* If it has no mounted filesystem, it's mountable,
194
* and DEVNAME names the device, return ENXIO.
195
*/
196
197
if (kd->kd_fs!=NULL) {
198
const char *volname;
199
volname = FSOP_GETVOLNAME(kd->kd_fs);
200
201
if (!strcmp(kd->kd_name, devname) ||
202
(volname!=NULL && !strcmp(volname, devname))) {
203
*result = FSOP_GETROOT(kd->kd_fs);
204
return 0;
205
}
206
}
207
else {
208
if (kd->kd_rawname!=NULL &&
209
!strcmp(kd->kd_name, devname)) {
210
return ENXIO;
211
}
212
}
213
214
/*
215
* If DEVNAME names the device, and we get here, it
216
* must have no fs and not be mountable. In this case,
217
* we return the device itself.
218
*/
219
if (!strcmp(kd->kd_name, devname)) {
220
KASSERT(kd->kd_fs==NULL);
221
KASSERT(kd->kd_rawname==NULL);
222
KASSERT(kd->kd_device != NULL);
223
VOP_INCREF(kd->kd_vnode);
224
*result = kd->kd_vnode;
225
return 0;
226
}
227
228
/*
229
* If the device has a rawname and DEVNAME names that,
230
* return the device itself.
231
*/
232
if (kd->kd_rawname!=NULL && !strcmp(kd->kd_rawname, devname)) {
233
KASSERT(kd->kd_device != NULL);
234
VOP_INCREF(kd->kd_vnode);
235
*result = kd->kd_vnode;
236
return 0;
237
}
238
239
/*
240
* If none of the above tests matched, we didn't name
241
* any of the names of this device, so go on to the
242
* next one.
243
*/
244
}
245
246
/*
247
* If we got here, the device specified by devname doesn't exist.
248
*/
249
250
return ENODEV;
251
}
252
253
/*
254
* Given a filesystem, hand back the name of the device it's mounted on.
255
*/
256
const char *
257
vfs_getdevname(struct fs *fs)
258
{
259
struct knowndev *kd;
260
unsigned i, num;
261
262
KASSERT(fs != NULL);
263
264
KASSERT(vfs_biglock_do_i_hold());
265
266
num = knowndevarray_num(knowndevs);
267
for (i=0; i<num; i++) {
268
kd = knowndevarray_get(knowndevs, i);
269
270
if (kd->kd_fs == fs) {
271
/*
272
* This is not a race condition: as long as the
273
* guy calling us holds a reference to the fs,
274
* the fs cannot go away, and the device can't
275
* go away until the fs goes away.
276
*/
277
return kd->kd_name;
278
}
279
}
280
281
return NULL;
282
}
283
284
/*
285
* Assemble the name for a raw device from the name for the regular device.
286
*/
287
static
288
char *
289
mkrawname(const char *name)
290
{
291
char *s = kmalloc(strlen(name)+3+1);
292
if (!s) {
293
return NULL;
294
}
295
strcpy(s, name);
296
strcat(s, "raw");
297
return s;
298
}
299
300
301
/*
302
* Check if the two strings passed in are the same, if they're both
303
* not NULL (the latter part being significant).
304
*/
305
static
306
inline
307
int
308
samestring(const char *a, const char *b)
309
{
310
if (a==NULL || b==NULL) {
311
return 0;
312
}
313
return !strcmp(a, b);
314
}
315
316
/*
317
* Check if the first string passed is the same as any of the three others,
318
* if they're not NULL.
319
*/
320
static
321
inline
322
int
323
samestring3(const char *a, const char *b, const char *c, const char *d)
324
{
325
return samestring(a,b) || samestring(a,c) || samestring(a,d);
326
}
327
328
/*
329
* Check if any of the three names passed in already exists as a device
330
* name.
331
*/
332
333
static
334
int
335
badnames(const char *n1, const char *n2, const char *n3)
336
{
337
const char *volname;
338
unsigned i, num;
339
struct knowndev *kd;
340
341
KASSERT(vfs_biglock_do_i_hold());
342
343
num = knowndevarray_num(knowndevs);
344
for (i=0; i<num; i++) {
345
kd = knowndevarray_get(knowndevs, i);
346
347
if (kd->kd_fs) {
348
volname = FSOP_GETVOLNAME(kd->kd_fs);
349
if (samestring3(volname, n1, n2, n3)) {
350
return 1;
351
}
352
}
353
354
if (samestring3(kd->kd_rawname, n1, n2, n3) ||
355
samestring3(kd->kd_name, n1, n2, n3)) {
356
return 1;
357
}
358
}
359
360
return 0;
361
}
362
363
/*
364
* Add a new device to the VFS layer's device table.
365
*
366
* If "mountable" is set, the device will be treated as one that expects
367
* to have a filesystem mounted on it, and a raw device will be created
368
* for direct access.
369
*/
370
static
371
int
372
vfs_doadd(const char *dname, int mountable, struct device *dev, struct fs *fs)
373
{
374
char *name=NULL, *rawname=NULL;
375
struct knowndev *kd=NULL;
376
struct vnode *vnode=NULL;
377
const char *volname=NULL;
378
unsigned index;
379
int result;
380
381
vfs_biglock_acquire();
382
383
name = kstrdup(dname);
384
if (name==NULL) {
385
goto nomem;
386
}
387
if (mountable) {
388
rawname = mkrawname(name);
389
if (rawname==NULL) {
390
goto nomem;
391
}
392
}
393
394
vnode = dev_create_vnode(dev);
395
if (vnode==NULL) {
396
goto nomem;
397
}
398
399
kd = kmalloc(sizeof(struct knowndev));
400
if (kd==NULL) {
401
goto nomem;
402
}
403
404
kd->kd_name = name;
405
kd->kd_rawname = rawname;
406
kd->kd_device = dev;
407
kd->kd_vnode = vnode;
408
kd->kd_fs = fs;
409
410
if (fs!=NULL) {
411
volname = FSOP_GETVOLNAME(fs);
412
}
413
414
if (badnames(name, rawname, volname)) {
415
vfs_biglock_release();
416
return EEXIST;
417
}
418
419
result = knowndevarray_add(knowndevs, kd, &index);
420
421
if (result == 0 && dev != NULL) {
422
/* use index+1 as the device number, so 0 is reserved */
423
dev->d_devnumber = index+1;
424
}
425
426
vfs_biglock_release();
427
return result;
428
429
nomem:
430
431
if (name) {
432
kfree(name);
433
}
434
if (rawname) {
435
kfree(rawname);
436
}
437
if (vnode) {
438
kfree(vnode);
439
}
440
if (kd) {
441
kfree(kd);
442
}
443
444
vfs_biglock_release();
445
return ENOMEM;
446
}
447
448
/*
449
* Add a new device, by name. See above for the description of
450
* mountable.
451
*/
452
int
453
vfs_adddev(const char *devname, struct device *dev, int mountable)
454
{
455
return vfs_doadd(devname, mountable, dev, NULL);
456
}
457
458
/*
459
* Add a filesystem that does not have an underlying device.
460
* This is used for emufs, but might also be used for network
461
* filesystems and the like.
462
*/
463
int
464
vfs_addfs(const char *devname, struct fs *fs)
465
{
466
return vfs_doadd(devname, 0, NULL, fs);
467
}
468
469
//////////////////////////////////////////////////
470
471
/*
472
* Look for a mountable device named DEVNAME.
473
* Should already hold knowndevs_lock.
474
*/
475
static
476
int
477
findmount(const char *devname, struct knowndev **result)
478
{
479
struct knowndev *dev;
480
unsigned i, num;
481
bool found = false;
482
483
KASSERT(vfs_biglock_do_i_hold());
484
485
num = knowndevarray_num(knowndevs);
486
for (i=0; !found && i<num; i++) {
487
dev = knowndevarray_get(knowndevs, i);
488
if (dev->kd_rawname==NULL) {
489
/* not mountable/unmountable */
490
continue;
491
}
492
493
if (!strcmp(devname, dev->kd_name)) {
494
*result = dev;
495
found = true;
496
}
497
}
498
499
return found ? 0 : ENODEV;
500
}
501
502
/*
503
* Mount a filesystem. Once we've found the device, call MOUNTFUNC to
504
* set up the filesystem and hand back a struct fs.
505
*
506
* The DATA argument is passed through unchanged to MOUNTFUNC.
507
*/
508
int
509
vfs_mount(const char *devname, void *data,
510
int (*mountfunc)(void *data, struct device *, struct fs **ret))
511
{
512
const char *volname;
513
struct knowndev *kd;
514
struct fs *fs;
515
int result;
516
517
vfs_biglock_acquire();
518
519
result = findmount(devname, &kd);
520
if (result) {
521
vfs_biglock_release();
522
return result;
523
}
524
525
if (kd->kd_fs != NULL) {
526
vfs_biglock_release();
527
return EBUSY;
528
}
529
KASSERT(kd->kd_rawname != NULL);
530
KASSERT(kd->kd_device != NULL);
531
532
result = mountfunc(data, kd->kd_device, &fs);
533
if (result) {
534
vfs_biglock_release();
535
return result;
536
}
537
538
KASSERT(fs != NULL);
539
540
kd->kd_fs = fs;
541
542
volname = FSOP_GETVOLNAME(fs);
543
kprintf("vfs: Mounted %s: on %s\n",
544
volname ? volname : kd->kd_name, kd->kd_name);
545
546
vfs_biglock_release();
547
return 0;
548
}
549
550
/*
551
* Unmount a filesystem/device by name.
552
* First calls FSOP_SYNC on the filesystem; then calls FSOP_UNMOUNT.
553
*/
554
int
555
vfs_unmount(const char *devname)
556
{
557
struct knowndev *kd;
558
int result;
559
560
vfs_biglock_acquire();
561
562
result = findmount(devname, &kd);
563
if (result) {
564
goto fail;
565
}
566
567
if (kd->kd_fs == NULL) {
568
result = EINVAL;
569
goto fail;
570
}
571
KASSERT(kd->kd_rawname != NULL);
572
KASSERT(kd->kd_device != NULL);
573
574
result = FSOP_SYNC(kd->kd_fs);
575
if (result) {
576
goto fail;
577
}
578
579
result = FSOP_UNMOUNT(kd->kd_fs);
580
if (result) {
581
goto fail;
582
}
583
584
kprintf("vfs: Unmounted %s:\n", kd->kd_name);
585
586
/* now drop the filesystem */
587
kd->kd_fs = NULL;
588
589
KASSERT(result==0);
590
591
fail:
592
vfs_biglock_release();
593
return result;
594
}
595
596
/*
597
* Global unmount function.
598
*/
599
int
600
vfs_unmountall(void)
601
{
602
struct knowndev *dev;
603
unsigned i, num;
604
int result;
605
606
vfs_biglock_acquire();
607
608
num = knowndevarray_num(knowndevs);
609
for (i=0; i<num; i++) {
610
dev = knowndevarray_get(knowndevs, i);
611
if (dev->kd_rawname == NULL) {
612
/* not mountable/unmountable */
613
continue;
614
}
615
if (dev->kd_fs == NULL) {
616
/* not mounted */
617
continue;
618
}
619
620
kprintf("vfs: Unmounting %s:\n", dev->kd_name);
621
622
result = FSOP_SYNC(dev->kd_fs);
623
if (result) {
624
kprintf("vfs: Warning: sync failed for %s: %s, trying "
625
"again\n", dev->kd_name, strerror(result));
626
627
result = FSOP_SYNC(dev->kd_fs);
628
if (result) {
629
kprintf("vfs: Warning: sync failed second time"
630
" for %s: %s, giving up...\n",
631
dev->kd_name, strerror(result));
632
continue;
633
}
634
}
635
636
result = FSOP_UNMOUNT(dev->kd_fs);
637
if (result == EBUSY) {
638
kprintf("vfs: Cannot unmount %s: (busy)\n",
639
dev->kd_name);
640
continue;
641
}
642
if (result) {
643
kprintf("vfs: Warning: unmount failed for %s:"
644
" %s, already synced, dropping...\n",
645
dev->kd_name, strerror(result));
646
continue;
647
}
648
649
/* now drop the filesystem */
650
dev->kd_fs = NULL;
651
}
652
653
vfs_biglock_release();
654
655
return 0;
656
}
657
658