Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
script3r
GitHub Repository: script3r/os161
Path: blob/master/kern/fs/sfs/sfs_vnode.c
2096 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
* SFS filesystem
32
*
33
* File-level (vnode) interface routines.
34
*/
35
#include <types.h>
36
#include <kern/errno.h>
37
#include <kern/fcntl.h>
38
#include <stat.h>
39
#include <lib.h>
40
#include <array.h>
41
#include <bitmap.h>
42
#include <uio.h>
43
#include <synch.h>
44
#include <vfs.h>
45
#include <device.h>
46
#include <sfs.h>
47
48
/* At bottom of file */
49
static int sfs_loadvnode(struct sfs_fs *sfs, uint32_t ino, int type,
50
struct sfs_vnode **ret);
51
52
////////////////////////////////////////////////////////////
53
//
54
// Simple stuff
55
56
/* Zero out a disk block. */
57
static
58
int
59
sfs_clearblock(struct sfs_fs *sfs, uint32_t block)
60
{
61
/* static -> automatically initialized to zero */
62
static char zeros[SFS_BLOCKSIZE];
63
return sfs_wblock(sfs, zeros, block);
64
}
65
66
/* Write an on-disk inode structure back out to disk. */
67
static
68
int
69
sfs_sync_inode(struct sfs_vnode *sv)
70
{
71
if (sv->sv_dirty) {
72
struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
73
int result = sfs_wblock(sfs, &sv->sv_i, sv->sv_ino);
74
if (result) {
75
return result;
76
}
77
sv->sv_dirty = false;
78
}
79
return 0;
80
}
81
82
////////////////////////////////////////////////////////////
83
//
84
// Space allocation
85
86
/*
87
* Allocate a block.
88
*/
89
static
90
int
91
sfs_balloc(struct sfs_fs *sfs, uint32_t *diskblock)
92
{
93
int result;
94
95
result = bitmap_alloc(sfs->sfs_freemap, diskblock);
96
if (result) {
97
return result;
98
}
99
sfs->sfs_freemapdirty = true;
100
101
if (*diskblock >= sfs->sfs_super.sp_nblocks) {
102
panic("sfs: balloc: invalid block %u\n", *diskblock);
103
}
104
105
/* Clear block before returning it */
106
return sfs_clearblock(sfs, *diskblock);
107
}
108
109
/*
110
* Free a block.
111
*/
112
static
113
void
114
sfs_bfree(struct sfs_fs *sfs, uint32_t diskblock)
115
{
116
bitmap_unmark(sfs->sfs_freemap, diskblock);
117
sfs->sfs_freemapdirty = true;
118
}
119
120
/*
121
* Check if a block is in use.
122
*/
123
static
124
int
125
sfs_bused(struct sfs_fs *sfs, uint32_t diskblock)
126
{
127
if (diskblock >= sfs->sfs_super.sp_nblocks) {
128
panic("sfs: sfs_bused called on out of range block %u\n",
129
diskblock);
130
}
131
return bitmap_isset(sfs->sfs_freemap, diskblock);
132
}
133
134
////////////////////////////////////////////////////////////
135
//
136
// Block mapping/inode maintenance
137
138
/*
139
* Look up the disk block number (from 0 up to the number of blocks on
140
* the disk) given a file and the logical block number within that
141
* file. If DOALLOC is set, and no such block exists, one will be
142
* allocated.
143
*/
144
static
145
int
146
sfs_bmap(struct sfs_vnode *sv, uint32_t fileblock, int doalloc,
147
uint32_t *diskblock)
148
{
149
/*
150
* I/O buffer for handling indirect blocks.
151
*
152
* Note: in real life (and when you've done the fs assignment)
153
* you would get space from the disk buffer cache for this,
154
* not use a static area.
155
*/
156
static uint32_t idbuf[SFS_DBPERIDB];
157
158
struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
159
uint32_t block;
160
uint32_t idblock;
161
uint32_t idnum, idoff;
162
int result;
163
164
KASSERT(sizeof(idbuf)==SFS_BLOCKSIZE);
165
166
/*
167
* If the block we want is one of the direct blocks...
168
*/
169
if (fileblock < SFS_NDIRECT) {
170
/*
171
* Get the block number
172
*/
173
block = sv->sv_i.sfi_direct[fileblock];
174
175
/*
176
* Do we need to allocate?
177
*/
178
if (block==0 && doalloc) {
179
result = sfs_balloc(sfs, &block);
180
if (result) {
181
return result;
182
}
183
184
/* Remember what we allocated; mark inode dirty */
185
sv->sv_i.sfi_direct[fileblock] = block;
186
sv->sv_dirty = true;
187
}
188
189
/*
190
* Hand back the block
191
*/
192
if (block != 0 && !sfs_bused(sfs, block)) {
193
panic("sfs: Data block %u (block %u of file %u) "
194
"marked free\n", block, fileblock, sv->sv_ino);
195
}
196
*diskblock = block;
197
return 0;
198
}
199
200
/*
201
* It's not a direct block; it must be in the indirect block.
202
* Subtract off the number of direct blocks, so FILEBLOCK is
203
* now the offset into the indirect block space.
204
*/
205
206
fileblock -= SFS_NDIRECT;
207
208
/* Get the indirect block number and offset w/i that indirect block */
209
idnum = fileblock / SFS_DBPERIDB;
210
idoff = fileblock % SFS_DBPERIDB;
211
212
/*
213
* We only have one indirect block. If the offset we were asked for
214
* is too large, we can't handle it, so fail.
215
*/
216
if (idnum > 0) {
217
return EFBIG;
218
}
219
220
/* Get the disk block number of the indirect block. */
221
idblock = sv->sv_i.sfi_indirect;
222
223
if (idblock==0 && !doalloc) {
224
/*
225
* There's no indirect block allocated. We weren't
226
* asked to allocate anything, so pretend the indirect
227
* block was filled with all zeros.
228
*/
229
*diskblock = 0;
230
return 0;
231
}
232
else if (idblock==0) {
233
/*
234
* There's no indirect block allocated, but we need to
235
* allocate a block whose number needs to be stored in
236
* the indirect block. Thus, we need to allocate an
237
* indirect block.
238
*/
239
result = sfs_balloc(sfs, &idblock);
240
if (result) {
241
return result;
242
}
243
244
/* Remember the block we just allocated */
245
sv->sv_i.sfi_indirect = idblock;
246
247
/* Mark the inode dirty */
248
sv->sv_dirty = true;
249
250
/* Clear the indirect block buffer */
251
bzero(idbuf, sizeof(idbuf));
252
}
253
else {
254
/*
255
* We already have an indirect block allocated; load it.
256
*/
257
result = sfs_rblock(sfs, idbuf, idblock);
258
if (result) {
259
return result;
260
}
261
}
262
263
/* Get the block out of the indirect block buffer */
264
block = idbuf[idoff];
265
266
/* If there's no block there, allocate one */
267
if (block==0 && doalloc) {
268
result = sfs_balloc(sfs, &block);
269
if (result) {
270
return result;
271
}
272
273
/* Remember the block we allocated */
274
idbuf[idoff] = block;
275
276
/* The indirect block is now dirty; write it back */
277
result = sfs_wblock(sfs, idbuf, idblock);
278
if (result) {
279
return result;
280
}
281
}
282
283
/* Hand back the result and return. */
284
if (block != 0 && !sfs_bused(sfs, block)) {
285
panic("sfs: Data block %u (block %u of file %u) marked free\n",
286
block, fileblock, sv->sv_ino);
287
}
288
*diskblock = block;
289
return 0;
290
}
291
292
////////////////////////////////////////////////////////////
293
//
294
// File-level I/O
295
296
/*
297
* Do I/O to a block of a file that doesn't cover the whole block. We
298
* need to read in the original block first, even if we're writing, so
299
* we don't clobber the portion of the block we're not intending to
300
* write over.
301
*
302
* skipstart is the number of bytes to skip past at the beginning of
303
* the sector; len is the number of bytes to actually read or write.
304
* uio is the area to do the I/O into.
305
*/
306
static
307
int
308
sfs_partialio(struct sfs_vnode *sv, struct uio *uio,
309
uint32_t skipstart, uint32_t len)
310
{
311
/*
312
* I/O buffer for handling partial sectors.
313
*
314
* Note: in real life (and when you've done the fs assignment)
315
* you would get space from the disk buffer cache for this,
316
* not use a static area.
317
*/
318
static char iobuf[SFS_BLOCKSIZE];
319
320
struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
321
uint32_t diskblock;
322
uint32_t fileblock;
323
int result;
324
325
/* Allocate missing blocks if and only if we're writing */
326
int doalloc = (uio->uio_rw==UIO_WRITE);
327
328
KASSERT(skipstart + len <= SFS_BLOCKSIZE);
329
330
/* Compute the block offset of this block in the file */
331
fileblock = uio->uio_offset / SFS_BLOCKSIZE;
332
333
/* Get the disk block number */
334
result = sfs_bmap(sv, fileblock, doalloc, &diskblock);
335
if (result) {
336
return result;
337
}
338
339
if (diskblock == 0) {
340
/*
341
* There was no block mapped at this point in the file.
342
* Zero the buffer.
343
*/
344
KASSERT(uio->uio_rw == UIO_READ);
345
bzero(iobuf, sizeof(iobuf));
346
}
347
else {
348
/*
349
* Read the block.
350
*/
351
result = sfs_rblock(sfs, iobuf, diskblock);
352
if (result) {
353
return result;
354
}
355
}
356
357
/*
358
* Now perform the requested operation into/out of the buffer.
359
*/
360
result = uiomove(iobuf+skipstart, len, uio);
361
if (result) {
362
return result;
363
}
364
365
/*
366
* If it was a write, write back the modified block.
367
*/
368
if (uio->uio_rw == UIO_WRITE) {
369
result = sfs_wblock(sfs, iobuf, diskblock);
370
if (result) {
371
return result;
372
}
373
}
374
375
return 0;
376
}
377
378
/*
379
* Do I/O (either read or write) of a single whole block.
380
*/
381
static
382
int
383
sfs_blockio(struct sfs_vnode *sv, struct uio *uio)
384
{
385
struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
386
uint32_t diskblock;
387
uint32_t fileblock;
388
int result;
389
int doalloc = (uio->uio_rw==UIO_WRITE);
390
off_t saveoff;
391
off_t diskoff;
392
off_t saveres;
393
off_t diskres;
394
395
/* Get the block number within the file */
396
fileblock = uio->uio_offset / SFS_BLOCKSIZE;
397
398
/* Look up the disk block number */
399
result = sfs_bmap(sv, fileblock, doalloc, &diskblock);
400
if (result) {
401
return result;
402
}
403
404
if (diskblock == 0) {
405
/*
406
* No block - fill with zeros.
407
*
408
* We must be reading, or sfs_bmap would have
409
* allocated a block for us.
410
*/
411
KASSERT(uio->uio_rw == UIO_READ);
412
return uiomovezeros(SFS_BLOCKSIZE, uio);
413
}
414
415
/*
416
* Do the I/O directly to the uio region. Save the uio_offset,
417
* and substitute one that makes sense to the device.
418
*/
419
saveoff = uio->uio_offset;
420
diskoff = diskblock * SFS_BLOCKSIZE;
421
uio->uio_offset = diskoff;
422
423
/*
424
* Temporarily set the residue to be one block size.
425
*/
426
KASSERT(uio->uio_resid >= SFS_BLOCKSIZE);
427
saveres = uio->uio_resid;
428
diskres = SFS_BLOCKSIZE;
429
uio->uio_resid = diskres;
430
431
result = sfs_rwblock(sfs, uio);
432
433
/*
434
* Now, restore the original uio_offset and uio_resid and update
435
* them by the amount of I/O done.
436
*/
437
uio->uio_offset = (uio->uio_offset - diskoff) + saveoff;
438
uio->uio_resid = (uio->uio_resid - diskres) + saveres;
439
440
return result;
441
}
442
443
/*
444
* Do I/O of a whole region of data, whether or not it's block-aligned.
445
*/
446
static
447
int
448
sfs_io(struct sfs_vnode *sv, struct uio *uio)
449
{
450
uint32_t blkoff;
451
uint32_t nblocks, i;
452
int result = 0;
453
uint32_t extraresid = 0;
454
455
/*
456
* If reading, check for EOF. If we can read a partial area,
457
* remember how much extra there was in EXTRARESID so we can
458
* add it back to uio_resid at the end.
459
*/
460
if (uio->uio_rw == UIO_READ) {
461
off_t size = sv->sv_i.sfi_size;
462
off_t endpos = uio->uio_offset + uio->uio_resid;
463
464
if (uio->uio_offset >= size) {
465
/* At or past EOF - just return */
466
return 0;
467
}
468
469
if (endpos > size) {
470
extraresid = endpos - size;
471
KASSERT(uio->uio_resid > extraresid);
472
uio->uio_resid -= extraresid;
473
}
474
}
475
476
/*
477
* First, do any leading partial block.
478
*/
479
blkoff = uio->uio_offset % SFS_BLOCKSIZE;
480
if (blkoff != 0) {
481
/* Number of bytes at beginning of block to skip */
482
uint32_t skip = blkoff;
483
484
/* Number of bytes to read/write after that point */
485
uint32_t len = SFS_BLOCKSIZE - blkoff;
486
487
/* ...which might be less than the rest of the block */
488
if (len > uio->uio_resid) {
489
len = uio->uio_resid;
490
}
491
492
/* Call sfs_partialio() to do it. */
493
result = sfs_partialio(sv, uio, skip, len);
494
if (result) {
495
goto out;
496
}
497
}
498
499
/* If we're done, quit. */
500
if (uio->uio_resid==0) {
501
goto out;
502
}
503
504
/*
505
* Now we should be block-aligned. Do the remaining whole blocks.
506
*/
507
KASSERT(uio->uio_offset % SFS_BLOCKSIZE == 0);
508
nblocks = uio->uio_resid / SFS_BLOCKSIZE;
509
for (i=0; i<nblocks; i++) {
510
result = sfs_blockio(sv, uio);
511
if (result) {
512
goto out;
513
}
514
}
515
516
/*
517
* Now do any remaining partial block at the end.
518
*/
519
KASSERT(uio->uio_resid < SFS_BLOCKSIZE);
520
521
if (uio->uio_resid > 0) {
522
result = sfs_partialio(sv, uio, 0, uio->uio_resid);
523
if (result) {
524
goto out;
525
}
526
}
527
528
out:
529
530
/* If writing, adjust file length */
531
if (uio->uio_rw == UIO_WRITE &&
532
uio->uio_offset > (off_t)sv->sv_i.sfi_size) {
533
sv->sv_i.sfi_size = uio->uio_offset;
534
sv->sv_dirty = true;
535
}
536
537
/* Add in any extra amount we couldn't read because of EOF */
538
uio->uio_resid += extraresid;
539
540
/* Done */
541
return result;
542
}
543
544
////////////////////////////////////////////////////////////
545
//
546
// Directory I/O
547
548
/*
549
* Read the directory entry out of slot SLOT of a directory vnode.
550
* The "slot" is the index of the directory entry, starting at 0.
551
*/
552
static
553
int
554
sfs_readdir(struct sfs_vnode *sv, struct sfs_dir *sd, int slot)
555
{
556
struct iovec iov;
557
struct uio ku;
558
off_t actualpos;
559
int result;
560
561
/* Compute the actual position in the directory to read. */
562
actualpos = slot * sizeof(struct sfs_dir);
563
564
/* Set up a uio to do the read */
565
uio_kinit(&iov, &ku, sd, sizeof(struct sfs_dir), actualpos, UIO_READ);
566
567
/* do it */
568
result = sfs_io(sv, &ku);
569
if (result) {
570
return result;
571
}
572
573
/* We should not hit EOF in the middle of a directory entry */
574
if (ku.uio_resid > 0) {
575
panic("sfs: readdir: Short entry (inode %u)\n", sv->sv_ino);
576
}
577
578
/* Done */
579
return 0;
580
}
581
582
/*
583
* Write (overwrite) the directory entry in slot SLOT of a directory
584
* vnode.
585
*/
586
static
587
int
588
sfs_writedir(struct sfs_vnode *sv, struct sfs_dir *sd, int slot)
589
{
590
struct iovec iov;
591
struct uio ku;
592
off_t actualpos;
593
int result;
594
595
/* Compute the actual position in the directory. */
596
KASSERT(slot>=0);
597
actualpos = slot * sizeof(struct sfs_dir);
598
599
/* Set up a uio to do the write */
600
uio_kinit(&iov, &ku, sd, sizeof(struct sfs_dir), actualpos, UIO_WRITE);
601
602
/* do it */
603
result = sfs_io(sv, &ku);
604
if (result) {
605
return result;
606
}
607
608
/* Should not end up with a partial entry! */
609
if (ku.uio_resid > 0) {
610
panic("sfs: writedir: Short write (ino %u)\n", sv->sv_ino);
611
}
612
613
/* Done */
614
return 0;
615
}
616
617
/*
618
* Compute the number of entries in a directory.
619
* This actually computes the number of existing slots, and does not
620
* account for empty slots.
621
*/
622
static
623
int
624
sfs_dir_nentries(struct sfs_vnode *sv)
625
{
626
off_t size;
627
628
KASSERT(sv->sv_i.sfi_type == SFS_TYPE_DIR);
629
630
size = sv->sv_i.sfi_size;
631
if (size % sizeof(struct sfs_dir) != 0) {
632
panic("sfs: directory %u: Invalid size %llu\n",
633
sv->sv_ino, size);
634
}
635
636
return size / sizeof(struct sfs_dir);
637
}
638
639
/*
640
* Search a directory for a particular filename in a directory, and
641
* return its inode number, its slot, and/or the slot number of an
642
* empty directory slot if one is found.
643
*/
644
645
static
646
int
647
sfs_dir_findname(struct sfs_vnode *sv, const char *name,
648
uint32_t *ino, int *slot, int *emptyslot)
649
{
650
struct sfs_dir tsd;
651
int found = 0;
652
int nentries = sfs_dir_nentries(sv);
653
int i, result;
654
655
/* For each slot... */
656
for (i=0; i<nentries; i++) {
657
658
/* Read the entry from that slot */
659
result = sfs_readdir(sv, &tsd, i);
660
if (result) {
661
return result;
662
}
663
if (tsd.sfd_ino == SFS_NOINO) {
664
/* Free slot - report it back if one was requested */
665
if (emptyslot != NULL) {
666
*emptyslot = i;
667
}
668
}
669
else {
670
/* Ensure null termination, just in case */
671
tsd.sfd_name[sizeof(tsd.sfd_name)-1] = 0;
672
if (!strcmp(tsd.sfd_name, name)) {
673
674
/* Each name may legally appear only once... */
675
KASSERT(found==0);
676
677
found = 1;
678
if (slot != NULL) {
679
*slot = i;
680
}
681
if (ino != NULL) {
682
*ino = tsd.sfd_ino;
683
}
684
}
685
}
686
}
687
688
return found ? 0 : ENOENT;
689
}
690
691
/*
692
* Create a link in a directory to the specified inode by number, with
693
* the specified name, and optionally hand back the slot.
694
*/
695
static
696
int
697
sfs_dir_link(struct sfs_vnode *sv, const char *name, uint32_t ino, int *slot)
698
{
699
int emptyslot = -1;
700
int result;
701
struct sfs_dir sd;
702
703
/* Look up the name. We want to make sure it *doesn't* exist. */
704
result = sfs_dir_findname(sv, name, NULL, NULL, &emptyslot);
705
if (result!=0 && result!=ENOENT) {
706
return result;
707
}
708
if (result==0) {
709
return EEXIST;
710
}
711
712
if (strlen(name)+1 > sizeof(sd.sfd_name)) {
713
return ENAMETOOLONG;
714
}
715
716
/* If we didn't get an empty slot, add the entry at the end. */
717
if (emptyslot < 0) {
718
emptyslot = sfs_dir_nentries(sv);
719
}
720
721
/* Set up the entry. */
722
bzero(&sd, sizeof(sd));
723
sd.sfd_ino = ino;
724
strcpy(sd.sfd_name, name);
725
726
/* Hand back the slot, if so requested. */
727
if (slot) {
728
*slot = emptyslot;
729
}
730
731
/* Write the entry. */
732
return sfs_writedir(sv, &sd, emptyslot);
733
734
}
735
736
/*
737
* Unlink a name in a directory, by slot number.
738
*/
739
static
740
int
741
sfs_dir_unlink(struct sfs_vnode *sv, int slot)
742
{
743
struct sfs_dir sd;
744
745
/* Initialize a suitable directory entry... */
746
bzero(&sd, sizeof(sd));
747
sd.sfd_ino = SFS_NOINO;
748
749
/* ... and write it */
750
return sfs_writedir(sv, &sd, slot);
751
}
752
753
/*
754
* Look for a name in a directory and hand back a vnode for the
755
* file, if there is one.
756
*/
757
static
758
int
759
sfs_lookonce(struct sfs_vnode *sv, const char *name,
760
struct sfs_vnode **ret,
761
int *slot)
762
{
763
struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
764
uint32_t ino;
765
int result;
766
767
result = sfs_dir_findname(sv, name, &ino, slot, NULL);
768
if (result) {
769
return result;
770
}
771
772
result = sfs_loadvnode(sfs, ino, SFS_TYPE_INVAL, ret);
773
if (result) {
774
return result;
775
}
776
777
if ((*ret)->sv_i.sfi_linkcount == 0) {
778
panic("sfs: Link count of file %u found in dir %u is 0\n",
779
(*ret)->sv_ino, sv->sv_ino);
780
}
781
782
return 0;
783
}
784
785
////////////////////////////////////////////////////////////
786
//
787
// Object creation
788
789
/*
790
* Create a new filesystem object and hand back its vnode.
791
*/
792
static
793
int
794
sfs_makeobj(struct sfs_fs *sfs, int type, struct sfs_vnode **ret)
795
{
796
uint32_t ino;
797
int result;
798
799
/*
800
* First, get an inode. (Each inode is a block, and the inode
801
* number is the block number, so just get a block.)
802
*/
803
804
result = sfs_balloc(sfs, &ino);
805
if (result) {
806
return result;
807
}
808
809
/*
810
* Now load a vnode for it.
811
*/
812
813
return sfs_loadvnode(sfs, ino, type, ret);
814
}
815
816
////////////////////////////////////////////////////////////
817
//
818
// Vnode ops
819
820
/*
821
* This is called on *each* open().
822
*/
823
static
824
int
825
sfs_open(struct vnode *v, int openflags)
826
{
827
/*
828
* At this level we do not need to handle O_CREAT, O_EXCL, or O_TRUNC.
829
* We *would* need to handle O_APPEND, but we don't support it.
830
*
831
* Any of O_RDONLY, O_WRONLY, and O_RDWR are valid, so we don't need
832
* to check that either.
833
*/
834
835
if (openflags & O_APPEND) {
836
return EUNIMP;
837
}
838
839
(void)v;
840
841
return 0;
842
}
843
844
/*
845
* This is called on *each* open() of a directory.
846
* Directories may only be open for read.
847
*/
848
static
849
int
850
sfs_opendir(struct vnode *v, int openflags)
851
{
852
switch (openflags & O_ACCMODE) {
853
case O_RDONLY:
854
break;
855
case O_WRONLY:
856
case O_RDWR:
857
default:
858
return EISDIR;
859
}
860
if (openflags & O_APPEND) {
861
return EISDIR;
862
}
863
864
(void)v;
865
return 0;
866
}
867
868
/*
869
* Called on the *last* close().
870
*
871
* This function should attempt to avoid returning errors, as handling
872
* them usefully is often not possible.
873
*/
874
static
875
int
876
sfs_close(struct vnode *v)
877
{
878
/* Sync it. */
879
return VOP_FSYNC(v);
880
}
881
882
/*
883
* Called when the vnode refcount (in-memory usage count) hits zero.
884
*
885
* This function should try to avoid returning errors other than EBUSY.
886
*/
887
static
888
int
889
sfs_reclaim(struct vnode *v)
890
{
891
struct sfs_vnode *sv = v->vn_data;
892
struct sfs_fs *sfs = v->vn_fs->fs_data;
893
unsigned ix, i, num;
894
int result;
895
896
vfs_biglock_acquire();
897
898
/*
899
* Make sure someone else hasn't picked up the vnode since the
900
* decision was made to reclaim it. (You must also synchronize
901
* this with sfs_loadvnode.)
902
*/
903
if (v->vn_refcount != 1) {
904
905
/* consume the reference VOP_DECREF gave us */
906
KASSERT(v->vn_refcount>1);
907
v->vn_refcount--;
908
909
vfs_biglock_release();
910
return EBUSY;
911
}
912
913
/* If there are no on-disk references to the file either, erase it. */
914
if (sv->sv_i.sfi_linkcount==0) {
915
result = VOP_TRUNCATE(&sv->sv_v, 0);
916
if (result) {
917
vfs_biglock_release();
918
return result;
919
}
920
}
921
922
/* Sync the inode to disk */
923
result = sfs_sync_inode(sv);
924
if (result) {
925
vfs_biglock_release();
926
return result;
927
}
928
929
/* If there are no on-disk references, discard the inode */
930
if (sv->sv_i.sfi_linkcount==0) {
931
sfs_bfree(sfs, sv->sv_ino);
932
}
933
934
/* Remove the vnode structure from the table in the struct sfs_fs. */
935
num = vnodearray_num(sfs->sfs_vnodes);
936
ix = num;
937
for (i=0; i<num; i++) {
938
struct vnode *v2 = vnodearray_get(sfs->sfs_vnodes, i);
939
struct sfs_vnode *sv2 = v2->vn_data;
940
if (sv2 == sv) {
941
ix = i;
942
break;
943
}
944
}
945
if (ix == num) {
946
panic("sfs: reclaim vnode %u not in vnode pool\n",
947
sv->sv_ino);
948
}
949
vnodearray_remove(sfs->sfs_vnodes, ix);
950
951
VOP_CLEANUP(&sv->sv_v);
952
953
vfs_biglock_release();
954
955
/* Release the storage for the vnode structure itself. */
956
kfree(sv);
957
958
/* Done */
959
return 0;
960
}
961
962
/*
963
* Called for read(). sfs_io() does the work.
964
*/
965
static
966
int
967
sfs_read(struct vnode *v, struct uio *uio)
968
{
969
struct sfs_vnode *sv = v->vn_data;
970
int result;
971
972
KASSERT(uio->uio_rw==UIO_READ);
973
974
vfs_biglock_acquire();
975
result = sfs_io(sv, uio);
976
vfs_biglock_release();
977
978
return result;
979
}
980
981
/*
982
* Called for write(). sfs_io() does the work.
983
*/
984
static
985
int
986
sfs_write(struct vnode *v, struct uio *uio)
987
{
988
struct sfs_vnode *sv = v->vn_data;
989
int result;
990
991
KASSERT(uio->uio_rw==UIO_WRITE);
992
993
vfs_biglock_acquire();
994
result = sfs_io(sv, uio);
995
vfs_biglock_release();
996
997
return result;
998
}
999
1000
/*
1001
* Called for ioctl()
1002
*/
1003
static
1004
int
1005
sfs_ioctl(struct vnode *v, int op, userptr_t data)
1006
{
1007
/*
1008
* No ioctls.
1009
*/
1010
1011
(void)v;
1012
(void)op;
1013
(void)data;
1014
1015
return EINVAL;
1016
}
1017
1018
/*
1019
* Called for stat/fstat/lstat.
1020
*/
1021
static
1022
int
1023
sfs_stat(struct vnode *v, struct stat *statbuf)
1024
{
1025
struct sfs_vnode *sv = v->vn_data;
1026
int result;
1027
1028
/* Fill in the stat structure */
1029
bzero(statbuf, sizeof(struct stat));
1030
1031
result = VOP_GETTYPE(v, &statbuf->st_mode);
1032
if (result) {
1033
return result;
1034
}
1035
1036
statbuf->st_size = sv->sv_i.sfi_size;
1037
1038
/* We don't support these yet; you get to implement them */
1039
statbuf->st_nlink = 0;
1040
statbuf->st_blocks = 0;
1041
1042
/* Fill in other field as desired/possible... */
1043
1044
return 0;
1045
}
1046
1047
/*
1048
* Return the type of the file (types as per kern/stat.h)
1049
*/
1050
static
1051
int
1052
sfs_gettype(struct vnode *v, uint32_t *ret)
1053
{
1054
struct sfs_vnode *sv = v->vn_data;
1055
1056
vfs_biglock_acquire();
1057
1058
switch (sv->sv_i.sfi_type) {
1059
case SFS_TYPE_FILE:
1060
*ret = S_IFREG;
1061
vfs_biglock_release();
1062
return 0;
1063
case SFS_TYPE_DIR:
1064
*ret = S_IFDIR;
1065
vfs_biglock_release();
1066
return 0;
1067
}
1068
panic("sfs: gettype: Invalid inode type (inode %u, type %u)\n",
1069
sv->sv_ino, sv->sv_i.sfi_type);
1070
return EINVAL;
1071
}
1072
1073
/*
1074
* Check for legal seeks on files. Allow anything non-negative.
1075
* We could conceivably, here, prohibit seeking past the maximum
1076
* file size our inode structure can support, but we don't - few
1077
* people ever bother to check lseek() for failure and having
1078
* read() or write() fail is sufficient.
1079
*/
1080
static
1081
int
1082
sfs_tryseek(struct vnode *v, off_t pos)
1083
{
1084
if (pos<0) {
1085
return EINVAL;
1086
}
1087
1088
/* Allow anything else */
1089
(void)v;
1090
1091
return 0;
1092
}
1093
1094
/*
1095
* Called for fsync(), and also on filesystem unmount, global sync(),
1096
* and some other cases.
1097
*/
1098
static
1099
int
1100
sfs_fsync(struct vnode *v)
1101
{
1102
struct sfs_vnode *sv = v->vn_data;
1103
int result;
1104
1105
vfs_biglock_acquire();
1106
result = sfs_sync_inode(sv);
1107
vfs_biglock_release();
1108
1109
return result;
1110
}
1111
1112
/*
1113
* Called for mmap().
1114
*/
1115
static
1116
int
1117
sfs_mmap(struct vnode *v /* add stuff as needed */)
1118
{
1119
(void)v;
1120
return EUNIMP;
1121
}
1122
1123
/*
1124
* Called for ftruncate() and from sfs_reclaim.
1125
*/
1126
static
1127
int
1128
sfs_truncate(struct vnode *v, off_t len)
1129
{
1130
/*
1131
* I/O buffer for handling the indirect block.
1132
*
1133
* Note: in real life (and when you've done the fs assignment)
1134
* you would get space from the disk buffer cache for this,
1135
* not use a static area.
1136
*/
1137
static uint32_t idbuf[SFS_DBPERIDB];
1138
1139
struct sfs_vnode *sv = v->vn_data;
1140
struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
1141
1142
/* Length in blocks (divide rounding up) */
1143
uint32_t blocklen = DIVROUNDUP(len, SFS_BLOCKSIZE);
1144
1145
uint32_t i, j, block;
1146
uint32_t idblock, baseblock, highblock;
1147
int result;
1148
int hasnonzero, iddirty;
1149
1150
KASSERT(sizeof(idbuf)==SFS_BLOCKSIZE);
1151
1152
vfs_biglock_acquire();
1153
1154
/*
1155
* Go through the direct blocks. Discard any that are
1156
* past the limit we're truncating to.
1157
*/
1158
for (i=0; i<SFS_NDIRECT; i++) {
1159
block = sv->sv_i.sfi_direct[i];
1160
if (i >= blocklen && block != 0) {
1161
sfs_bfree(sfs, block);
1162
sv->sv_i.sfi_direct[i] = 0;
1163
sv->sv_dirty = true;
1164
}
1165
}
1166
1167
/* Indirect block number */
1168
idblock = sv->sv_i.sfi_indirect;
1169
1170
/* The lowest block in the indirect block */
1171
baseblock = SFS_NDIRECT;
1172
1173
/* The highest block in the indirect block */
1174
highblock = baseblock + SFS_DBPERIDB - 1;
1175
1176
if (blocklen < highblock && idblock != 0) {
1177
/* We're past the proposed EOF; may need to free stuff */
1178
1179
/* Read the indirect block */
1180
result = sfs_rblock(sfs, idbuf, idblock);
1181
if (result) {
1182
vfs_biglock_release();
1183
return result;
1184
}
1185
1186
hasnonzero = 0;
1187
iddirty = 0;
1188
for (j=0; j<SFS_DBPERIDB; j++) {
1189
/* Discard any blocks that are past the new EOF */
1190
if (blocklen < baseblock+j && idbuf[j] != 0) {
1191
sfs_bfree(sfs, idbuf[j]);
1192
idbuf[j] = 0;
1193
iddirty = 1;
1194
}
1195
/* Remember if we see any nonzero blocks in here */
1196
if (idbuf[j]!=0) {
1197
hasnonzero=1;
1198
}
1199
}
1200
1201
if (!hasnonzero) {
1202
/* The whole indirect block is empty now; free it */
1203
sfs_bfree(sfs, idblock);
1204
sv->sv_i.sfi_indirect = 0;
1205
sv->sv_dirty = true;
1206
}
1207
else if (iddirty) {
1208
/* The indirect block is dirty; write it back */
1209
result = sfs_wblock(sfs, idbuf, idblock);
1210
if (result) {
1211
vfs_biglock_release();
1212
return result;
1213
}
1214
}
1215
}
1216
1217
/* Set the file size */
1218
sv->sv_i.sfi_size = len;
1219
1220
/* Mark the inode dirty */
1221
sv->sv_dirty = true;
1222
1223
vfs_biglock_release();
1224
return 0;
1225
}
1226
1227
/*
1228
* Get the full pathname for a file. This only needs to work on directories.
1229
* Since we don't support subdirectories, assume it's the root directory
1230
* and hand back the empty string. (The VFS layer takes care of the
1231
* device name, leading slash, etc.)
1232
*/
1233
static
1234
int
1235
sfs_namefile(struct vnode *vv, struct uio *uio)
1236
{
1237
struct sfs_vnode *sv = vv->vn_data;
1238
KASSERT(sv->sv_ino == SFS_ROOT_LOCATION);
1239
1240
/* send back the empty string - just return */
1241
1242
(void)uio;
1243
1244
return 0;
1245
}
1246
1247
/*
1248
* Create a file. If EXCL is set, insist that the filename not already
1249
* exist; otherwise, if it already exists, just open it.
1250
*/
1251
static
1252
int
1253
sfs_creat(struct vnode *v, const char *name, bool excl, mode_t mode,
1254
struct vnode **ret)
1255
{
1256
struct sfs_fs *sfs = v->vn_fs->fs_data;
1257
struct sfs_vnode *sv = v->vn_data;
1258
struct sfs_vnode *newguy;
1259
uint32_t ino;
1260
int result;
1261
1262
vfs_biglock_acquire();
1263
1264
/* Look up the name */
1265
result = sfs_dir_findname(sv, name, &ino, NULL, NULL);
1266
if (result!=0 && result!=ENOENT) {
1267
vfs_biglock_release();
1268
return result;
1269
}
1270
1271
/* If it exists and we didn't want it to, fail */
1272
if (result==0 && excl) {
1273
vfs_biglock_release();
1274
return EEXIST;
1275
}
1276
1277
if (result==0) {
1278
/* We got a file; load its vnode and return */
1279
result = sfs_loadvnode(sfs, ino, SFS_TYPE_INVAL, &newguy);
1280
if (result) {
1281
vfs_biglock_release();
1282
return result;
1283
}
1284
*ret = &newguy->sv_v;
1285
vfs_biglock_release();
1286
return 0;
1287
}
1288
1289
/* Didn't exist - create it */
1290
result = sfs_makeobj(sfs, SFS_TYPE_FILE, &newguy);
1291
if (result) {
1292
vfs_biglock_release();
1293
return result;
1294
}
1295
1296
/* We don't currently support file permissions; ignore MODE */
1297
(void)mode;
1298
1299
/* Link it into the directory */
1300
result = sfs_dir_link(sv, name, newguy->sv_ino, NULL);
1301
if (result) {
1302
VOP_DECREF(&newguy->sv_v);
1303
vfs_biglock_release();
1304
return result;
1305
}
1306
1307
/* Update the linkcount of the new file */
1308
newguy->sv_i.sfi_linkcount++;
1309
1310
/* and consequently mark it dirty. */
1311
newguy->sv_dirty = true;
1312
1313
*ret = &newguy->sv_v;
1314
1315
vfs_biglock_release();
1316
return 0;
1317
}
1318
1319
/*
1320
* Make a hard link to a file.
1321
* The VFS layer should prevent this being called unless both
1322
* vnodes are ours.
1323
*/
1324
static
1325
int
1326
sfs_link(struct vnode *dir, const char *name, struct vnode *file)
1327
{
1328
struct sfs_vnode *sv = dir->vn_data;
1329
struct sfs_vnode *f = file->vn_data;
1330
int result;
1331
1332
KASSERT(file->vn_fs == dir->vn_fs);
1333
1334
vfs_biglock_acquire();
1335
1336
/* Just create a link */
1337
result = sfs_dir_link(sv, name, f->sv_ino, NULL);
1338
if (result) {
1339
vfs_biglock_release();
1340
return result;
1341
}
1342
1343
/* and update the link count, marking the inode dirty */
1344
f->sv_i.sfi_linkcount++;
1345
f->sv_dirty = true;
1346
1347
vfs_biglock_release();
1348
return 0;
1349
}
1350
1351
/*
1352
* Delete a file.
1353
*/
1354
static
1355
int
1356
sfs_remove(struct vnode *dir, const char *name)
1357
{
1358
struct sfs_vnode *sv = dir->vn_data;
1359
struct sfs_vnode *victim;
1360
int slot;
1361
int result;
1362
1363
vfs_biglock_acquire();
1364
1365
/* Look for the file and fetch a vnode for it. */
1366
result = sfs_lookonce(sv, name, &victim, &slot);
1367
if (result) {
1368
vfs_biglock_release();
1369
return result;
1370
}
1371
1372
/* Erase its directory entry. */
1373
result = sfs_dir_unlink(sv, slot);
1374
if (result==0) {
1375
/* If we succeeded, decrement the link count. */
1376
KASSERT(victim->sv_i.sfi_linkcount > 0);
1377
victim->sv_i.sfi_linkcount--;
1378
victim->sv_dirty = true;
1379
}
1380
1381
/* Discard the reference that sfs_lookonce got us */
1382
VOP_DECREF(&victim->sv_v);
1383
1384
vfs_biglock_release();
1385
return result;
1386
}
1387
1388
/*
1389
* Rename a file.
1390
*
1391
* Since we don't support subdirectories, assumes that the two
1392
* directories passed are the same.
1393
*/
1394
static
1395
int
1396
sfs_rename(struct vnode *d1, const char *n1,
1397
struct vnode *d2, const char *n2)
1398
{
1399
struct sfs_vnode *sv = d1->vn_data;
1400
struct sfs_vnode *g1;
1401
int slot1, slot2;
1402
int result, result2;
1403
1404
vfs_biglock_acquire();
1405
1406
KASSERT(d1==d2);
1407
KASSERT(sv->sv_ino == SFS_ROOT_LOCATION);
1408
1409
/* Look up the old name of the file and get its inode and slot number*/
1410
result = sfs_lookonce(sv, n1, &g1, &slot1);
1411
if (result) {
1412
vfs_biglock_release();
1413
return result;
1414
}
1415
1416
/* We don't support subdirectories */
1417
KASSERT(g1->sv_i.sfi_type == SFS_TYPE_FILE);
1418
1419
/*
1420
* Link it under the new name.
1421
*
1422
* We could theoretically just overwrite the original
1423
* directory entry, except that we need to check to make sure
1424
* the new name doesn't already exist; might as well use the
1425
* existing link routine.
1426
*/
1427
result = sfs_dir_link(sv, n2, g1->sv_ino, &slot2);
1428
if (result) {
1429
goto puke;
1430
}
1431
1432
/* Increment the link count, and mark inode dirty */
1433
g1->sv_i.sfi_linkcount++;
1434
g1->sv_dirty = true;
1435
1436
/* Unlink the old slot */
1437
result = sfs_dir_unlink(sv, slot1);
1438
if (result) {
1439
goto puke_harder;
1440
}
1441
1442
/*
1443
* Decrement the link count again, and mark the inode dirty again,
1444
* in case it's been synced behind our back.
1445
*/
1446
KASSERT(g1->sv_i.sfi_linkcount>0);
1447
g1->sv_i.sfi_linkcount--;
1448
g1->sv_dirty = true;
1449
1450
/* Let go of the reference to g1 */
1451
VOP_DECREF(&g1->sv_v);
1452
1453
vfs_biglock_release();
1454
return 0;
1455
1456
puke_harder:
1457
/*
1458
* Error recovery: try to undo what we already did
1459
*/
1460
result2 = sfs_dir_unlink(sv, slot2);
1461
if (result2) {
1462
kprintf("sfs: rename: %s\n", strerror(result));
1463
kprintf("sfs: rename: while cleaning up: %s\n",
1464
strerror(result2));
1465
panic("sfs: rename: Cannot recover\n");
1466
}
1467
g1->sv_i.sfi_linkcount--;
1468
puke:
1469
/* Let go of the reference to g1 */
1470
VOP_DECREF(&g1->sv_v);
1471
vfs_biglock_release();
1472
return result;
1473
}
1474
1475
/*
1476
* lookparent returns the last path component as a string and the
1477
* directory it's in as a vnode.
1478
*
1479
* Since we don't support subdirectories, this is very easy -
1480
* return the root dir and copy the path.
1481
*/
1482
static
1483
int
1484
sfs_lookparent(struct vnode *v, char *path, struct vnode **ret,
1485
char *buf, size_t buflen)
1486
{
1487
struct sfs_vnode *sv = v->vn_data;
1488
1489
vfs_biglock_acquire();
1490
1491
if (sv->sv_i.sfi_type != SFS_TYPE_DIR) {
1492
vfs_biglock_release();
1493
return ENOTDIR;
1494
}
1495
1496
if (strlen(path)+1 > buflen) {
1497
vfs_biglock_release();
1498
return ENAMETOOLONG;
1499
}
1500
strcpy(buf, path);
1501
1502
VOP_INCREF(&sv->sv_v);
1503
*ret = &sv->sv_v;
1504
1505
vfs_biglock_release();
1506
return 0;
1507
}
1508
1509
/*
1510
* Lookup gets a vnode for a pathname.
1511
*
1512
* Since we don't support subdirectories, it's easy - just look up the
1513
* name.
1514
*/
1515
static
1516
int
1517
sfs_lookup(struct vnode *v, char *path, struct vnode **ret)
1518
{
1519
struct sfs_vnode *sv = v->vn_data;
1520
struct sfs_vnode *final;
1521
int result;
1522
1523
vfs_biglock_acquire();
1524
1525
if (sv->sv_i.sfi_type != SFS_TYPE_DIR) {
1526
vfs_biglock_release();
1527
return ENOTDIR;
1528
}
1529
1530
result = sfs_lookonce(sv, path, &final, NULL);
1531
if (result) {
1532
vfs_biglock_release();
1533
return result;
1534
}
1535
1536
*ret = &final->sv_v;
1537
1538
vfs_biglock_release();
1539
return 0;
1540
}
1541
1542
//////////////////////////////////////////////////
1543
1544
static
1545
int
1546
sfs_notdir(void)
1547
{
1548
return ENOTDIR;
1549
}
1550
1551
static
1552
int
1553
sfs_isdir(void)
1554
{
1555
return EISDIR;
1556
}
1557
1558
static
1559
int
1560
sfs_unimp(void)
1561
{
1562
return EUNIMP;
1563
}
1564
1565
/*
1566
* Casting through void * prevents warnings.
1567
* All of the vnode ops return int, and it's ok to cast functions that
1568
* take args to functions that take no args.
1569
*/
1570
1571
#define ISDIR ((void *)sfs_isdir)
1572
#define NOTDIR ((void *)sfs_notdir)
1573
#define UNIMP ((void *)sfs_unimp)
1574
1575
/*
1576
* Function table for sfs files.
1577
*/
1578
static const struct vnode_ops sfs_fileops = {
1579
VOP_MAGIC, /* mark this a valid vnode ops table */
1580
1581
sfs_open,
1582
sfs_close,
1583
sfs_reclaim,
1584
1585
sfs_read,
1586
NOTDIR, /* readlink */
1587
NOTDIR, /* getdirentry */
1588
sfs_write,
1589
sfs_ioctl,
1590
sfs_stat,
1591
sfs_gettype,
1592
sfs_tryseek,
1593
sfs_fsync,
1594
sfs_mmap,
1595
sfs_truncate,
1596
NOTDIR, /* namefile */
1597
1598
NOTDIR, /* creat */
1599
NOTDIR, /* symlink */
1600
NOTDIR, /* mkdir */
1601
NOTDIR, /* link */
1602
NOTDIR, /* remove */
1603
NOTDIR, /* rmdir */
1604
NOTDIR, /* rename */
1605
1606
NOTDIR, /* lookup */
1607
NOTDIR, /* lookparent */
1608
};
1609
1610
/*
1611
* Function table for the sfs directory.
1612
*/
1613
static const struct vnode_ops sfs_dirops = {
1614
VOP_MAGIC, /* mark this a valid vnode ops table */
1615
1616
sfs_opendir,
1617
sfs_close,
1618
sfs_reclaim,
1619
1620
ISDIR, /* read */
1621
ISDIR, /* readlink */
1622
UNIMP, /* getdirentry */
1623
ISDIR, /* write */
1624
sfs_ioctl,
1625
sfs_stat,
1626
sfs_gettype,
1627
UNIMP, /* tryseek */
1628
sfs_fsync,
1629
ISDIR, /* mmap */
1630
ISDIR, /* truncate */
1631
sfs_namefile,
1632
1633
sfs_creat,
1634
UNIMP, /* symlink */
1635
UNIMP, /* mkdir */
1636
sfs_link,
1637
sfs_remove,
1638
UNIMP, /* rmdir */
1639
sfs_rename,
1640
1641
sfs_lookup,
1642
sfs_lookparent,
1643
};
1644
1645
/*
1646
* Function to load a inode into memory as a vnode, or dig up one
1647
* that's already resident.
1648
*/
1649
static
1650
int
1651
sfs_loadvnode(struct sfs_fs *sfs, uint32_t ino, int forcetype,
1652
struct sfs_vnode **ret)
1653
{
1654
struct vnode *v;
1655
struct sfs_vnode *sv;
1656
const struct vnode_ops *ops = NULL;
1657
unsigned i, num;
1658
int result;
1659
1660
/* Look in the vnodes table */
1661
num = vnodearray_num(sfs->sfs_vnodes);
1662
1663
/* Linear search. Is this too slow? You decide. */
1664
for (i=0; i<num; i++) {
1665
v = vnodearray_get(sfs->sfs_vnodes, i);
1666
sv = v->vn_data;
1667
1668
/* Every inode in memory must be in an allocated block */
1669
if (!sfs_bused(sfs, sv->sv_ino)) {
1670
panic("sfs: Found inode %u in unallocated block\n",
1671
sv->sv_ino);
1672
}
1673
1674
if (sv->sv_ino==ino) {
1675
/* Found */
1676
1677
/* May only be set when creating new objects */
1678
KASSERT(forcetype==SFS_TYPE_INVAL);
1679
1680
VOP_INCREF(&sv->sv_v);
1681
*ret = sv;
1682
return 0;
1683
}
1684
}
1685
1686
/* Didn't have it loaded; load it */
1687
1688
sv = kmalloc(sizeof(struct sfs_vnode));
1689
if (sv==NULL) {
1690
return ENOMEM;
1691
}
1692
1693
/* Must be in an allocated block */
1694
if (!sfs_bused(sfs, ino)) {
1695
panic("sfs: Tried to load inode %u from unallocated block\n",
1696
ino);
1697
}
1698
1699
/* Read the block the inode is in */
1700
result = sfs_rblock(sfs, &sv->sv_i, ino);
1701
if (result) {
1702
kfree(sv);
1703
return result;
1704
}
1705
1706
/* Not dirty yet */
1707
sv->sv_dirty = false;
1708
1709
/*
1710
* FORCETYPE is set if we're creating a new file, because the
1711
* block on disk will have been zeroed out and thus the type
1712
* recorded there will be SFS_TYPE_INVAL.
1713
*/
1714
if (forcetype != SFS_TYPE_INVAL) {
1715
KASSERT(sv->sv_i.sfi_type == SFS_TYPE_INVAL);
1716
sv->sv_i.sfi_type = forcetype;
1717
sv->sv_dirty = true;
1718
}
1719
1720
/*
1721
* Choose the function table based on the object type.
1722
*/
1723
switch (sv->sv_i.sfi_type) {
1724
case SFS_TYPE_FILE:
1725
ops = &sfs_fileops;
1726
break;
1727
case SFS_TYPE_DIR:
1728
ops = &sfs_dirops;
1729
break;
1730
default:
1731
panic("sfs: loadvnode: Invalid inode type "
1732
"(inode %u, type %u)\n",
1733
ino, sv->sv_i.sfi_type);
1734
}
1735
1736
/* Call the common vnode initializer */
1737
result = VOP_INIT(&sv->sv_v, ops, &sfs->sfs_absfs, sv);
1738
if (result) {
1739
kfree(sv);
1740
return result;
1741
}
1742
1743
/* Set the other fields in our vnode structure */
1744
sv->sv_ino = ino;
1745
1746
/* Add it to our table */
1747
result = vnodearray_add(sfs->sfs_vnodes, &sv->sv_v, NULL);
1748
if (result) {
1749
VOP_CLEANUP(&sv->sv_v);
1750
kfree(sv);
1751
return result;
1752
}
1753
1754
/* Hand it back */
1755
*ret = sv;
1756
return 0;
1757
}
1758
1759
/*
1760
* Get vnode for the root of the filesystem.
1761
* The root vnode is always found in block 1 (SFS_ROOT_LOCATION).
1762
*/
1763
struct vnode *
1764
sfs_getroot(struct fs *fs)
1765
{
1766
struct sfs_fs *sfs = fs->fs_data;
1767
struct sfs_vnode *sv;
1768
int result;
1769
1770
vfs_biglock_acquire();
1771
1772
result = sfs_loadvnode(sfs, SFS_ROOT_LOCATION, SFS_TYPE_INVAL, &sv);
1773
if (result) {
1774
panic("sfs: getroot: Cannot load root vnode\n");
1775
}
1776
1777
vfs_biglock_release();
1778
1779
return &sv->sv_v;
1780
}
1781
1782