/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- sfs_clearblock
- sfs_sync_inode
- sfs_balloc
- sfs_bfree
- sfs_bused
- sfs_bmap
- sfs_partialio
- sfs_blockio
- sfs_io
- sfs_readdir
- sfs_writedir
- sfs_dir_nentries
- sfs_dir_findname
- sfs_dir_link
- sfs_dir_unlink
- sfs_lookonce
- sfs_makeobj
- sfs_open
- sfs_opendir
- sfs_close
- sfs_reclaim
- sfs_read
- sfs_write
- sfs_ioctl
- sfs_stat
- sfs_gettype
- sfs_tryseek
- sfs_fsync
- sfs_mmap
- sfs_truncate
- sfs_namefile
- sfs_creat
- sfs_link
- sfs_remove
- sfs_rename
- sfs_lookparent
- sfs_lookup
- sfs_notdir
- sfs_isdir
- sfs_unimp
- sfs_loadvnode
- sfs_getroot
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 }