xv6, line by line
kernel/fs.c

kernel/fs.c

C · 741 lines · annotated 100% · kernel · upstream

About this file

The heart of xv6’s file system: everything between “a numbered disk block” and “a file named /README”. System calls in kernel/sysfile.c and the file-table code in kernel/file.c call into it; it calls down into the buffer cache (kernel/bio.c) and the write-ahead log (kernel/log.c).

The file is organized bottom-up, and you can read it in that order:

  1. Super block and blocks (lines 24–107): read the superblock at boot, then allocate and free data blocks with the free bitmap.
  2. Inodes (lines 109–408): the on-disk inodes, the in-memory itable, and the functions that reference, lock, update and free them.
  3. Inode content (lines 410–579): map a file offset to a disk block (bmap), read and write file data (readi, writei), discard it (itrunc).
  4. Directories (lines 581–646): a directory is a file of name/number pairs.
  5. Path names (lines 648–741): turn /a/b/c into an inode by walking directories.

Two counts run through the whole file: ref, the number of in-memory references to an inode, and nlink, the number of directory entries that name it (link count (nlink)). An inode’s disk space is freed only when both reach zero.

Read before: kernel/fs.h (the on-disk format), kernel/bio.c, kernel/log.c. Read next: kernel/file.c, then kernel/sysfile.c.

1// File system implementation. Five layers:
2// + Blocks: allocator for raw disk blocks.
3// + Log: crash recovery for multi-step updates.
4// + Files: inode allocator, reading, writing, metadata.
5// + Directories: inode with special contents (list of other inodes!)
6// + Names: paths like /usr/rtm/xv6/fs.c for convenient naming.
7//
8// This file contains the low-level file system manipulation
9// routines. The (higher-level) system call implementations
10// are in sysfile.c.
12#include "types.h"
13#include "riscv.h"
14#include "defs.h"
15#include "param.h"
16#include "stat.h"
18#include "proc.h"
20#include "fs.h"
21#include "buf.h"
22#include "file.h"
24#define min(a, b) ((a) < (b) ? (a) : (b))
25// there should be one superblock per disk device, but we run with
26// only one device
29// Read the super block.
30static void
31readsb(int dev, struct superblock *sb)
33 struct buf *bp;
35 bp = bread(dev, 1);
36 memmove(sb, bp->data, sizeof(*sb));
40// Init fs
41void
45 if (sb.magic != FSMAGIC)
46 panic("invalid file system");
51// Zero a block.
52static void
53bzero(int dev, int bno)
55 struct buf *bp;
63// Blocks.
65// Allocate a zeroed disk block.
66// returns 0 if out of disk space.
67static uint
70 int b, bi, m;
71 struct buf *bp;
73 bp = 0;
74 for (b = 0; b < sb.size; b += BPB) {
76 for (bi = 0; bi < BPB && b + bi < sb.size; bi++) {
77 m = 1 << (bi % 8);
78 if ((bp->data[bi / 8] & m) == 0) { // Is block free?
79 bp->data[bi / 8] |= m; // Mark block in use.
82 bzero(dev, b + bi);
83 return b + bi;
84 }
85 }
87 }
88 printk("balloc: out of blocks\n");
89 return 0;
92// Free a disk block.
93static void
96 struct buf *bp;
97 int bi, m;
100 bi = b % BPB;
101 m = 1 << (bi % 8);
102 if ((bp->data[bi / 8] & m) == 0)
103 panic("freeing free block");
104 bp->data[bi / 8] &= ~m;
109// Inodes.
110//
111// An inode describes a single unnamed file.
112// The inode disk structure holds metadata: the file's type,
113// its size, the number of links referring to it, and the
114// list of blocks holding the file's content.
115//
116// The inodes are laid out sequentially on disk at block
117// sb.inodestart. Each inode has a number, indicating its
118// position on the disk.
119//
120// The kernel keeps a table of in-use inodes in memory
121// to provide a place for synchronizing access
122// to inodes used by multiple processes. The in-memory
123// inodes include book-keeping information that is
124// not stored on disk: ip->ref and ip->valid.
125//
126// An inode and its in-memory representation go through a
127// sequence of states before they can be used by the
128// rest of the file system code.
129//
130// * Allocation: an inode is allocated if its type (on disk)
131// is non-zero. ialloc() allocates, and iput() frees if
132// the reference and link counts have fallen to zero.
133//
134// * Referencing in table: an entry in the inode table
135// is free if ip->ref is zero. Otherwise ip->ref tracks
136// the number of in-memory pointers to the entry (open
137// files and current directories). iget() finds or
138// creates a table entry and increments its ref; iput()
139// decrements ref.
140//
141// * Valid: the information (type, size, &c) in an inode
142// table entry is only correct when ip->valid is 1.
143// ilock() reads the inode from
144// the disk and sets ip->valid, while iput() clears
145// ip->valid if ip->ref has fallen to zero.
146//
147// * Locked: file system code may only examine and modify
148// the information in an inode and its content if it
149// has first locked the inode.
150//
151// Thus a typical sequence is:
152// ip = iget(dev, inum)
153// ilock(ip)
154// ... examine and modify ip->xxx ...
155// iunlock(ip)
156// iput(ip)
157//
158// ilock() is separate from iget() so that system calls can
159// get a long-term reference to an inode (as for an open file)
160// and only lock it for short periods (e.g., in read()).
161// The separation also helps avoid deadlock and races during
162// pathname lookup. iget() increments ip->ref so that the inode
163// stays in the table and pointers to it remain valid.
164//
165// Many internal file system functions expect the caller to
166// have locked the inodes involved; this lets callers create
167// multi-step atomic operations.
168//
169// The itable.lock spin-lock protects the allocation of itable
170// entries. Since ip->ref indicates whether an entry is free,
171// and ip->dev and ip->inum indicate which i-node an entry
172// holds, one must hold itable.lock while using any of those fields.
173//
174// An ip->lock sleep-lock protects all ip-> fields other than ref,
175// dev, and inum. One must hold ip->lock in order to
176// read or write that inode's ip->valid, ip->size, ip->type, &c.
178struct {
179 struct spinlock lock;
183void
186 int i = 0;
188 initlock(&itable.lock, "itable");
189 for (i = 0; i < NINODE; i++) {
191 }
194static struct inode *iget(uint dev, uint inum);
196// Allocate an inode on device dev.
197// Mark it as allocated by giving it type type.
198// Returns an unlocked but allocated and referenced inode,
199// or NULL if there is no free inode.
200struct inode *
203 int inum;
204 struct buf *bp;
205 struct dinode *dip;
207 for (inum = 1; inum < sb.ninodes; inum++) {
209 dip = (struct dinode *)bp->data + inum % IPB;
210 if (dip->type == 0) { // a free inode
211 memset(dip, 0, sizeof(*dip));
213 log_write(bp); // mark it allocated on the disk
215 return iget(dev, inum);
216 }
218 }
219 printk("ialloc: no inodes\n");
220 return 0;
223// Copy a modified in-memory inode to disk.
224// Must be called after every change to an ip->xxx field
225// that lives on disk.
226// Caller must hold ip->lock.
227void
230 struct buf *bp;
231 struct dinode *dip;
233 bp = bread(ip->dev, IBLOCK(ip->inum, sb));
234 dip = (struct dinode *)bp->data + ip->inum % IPB;
240 memmove(dip->addrs, ip->addrs, sizeof(ip->addrs));
245// Find the inode with number inum on device dev
246// and return the in-memory copy. Does not lock
247// the inode and does not read it from disk.
248static struct inode *
251 struct inode *ip, *empty;
255 // Is the inode already in the table?
256 empty = 0;
257 for (ip = &itable.inode[0]; ip < &itable.inode[NINODE]; ip++) {
258 if (ip->ref > 0 && ip->dev == dev && ip->inum == inum) {
259 ip->ref++;
261 return ip;
262 }
263 if (empty == 0 && ip->ref == 0) // Remember empty slot.
265 }
267 // Recycle an inode entry.
268 if (empty == 0)
269 panic("iget: no inodes");
274 ip->ref = 1;
275 ip->valid = 0;
278 return ip;
281// Increment reference count for ip.
282// Returns ip to enable ip = idup(ip1) idiom.
283struct inode *
284idup(struct inode *ip)
287 ip->ref++;
289 return ip;
292// Lock the given inode.
293// Reads the inode from disk if necessary.
294void
295ilock(struct inode *ip)
297 struct buf *bp;
298 struct dinode *dip;
300 if (ip == 0 || ip->ref < 1)
301 panic("ilock");
305 if (ip->valid == 0) {
306 bp = bread(ip->dev, IBLOCK(ip->inum, sb));
307 dip = (struct dinode *)bp->data + ip->inum % IPB;
313 memmove(ip->addrs, dip->addrs, sizeof(ip->addrs));
315 ip->valid = 1;
316 if (ip->type == 0)
317 panic("ilock: no type");
318 }
321// Unlock the given inode.
322void
325 if (ip == 0 || !holdingsleep(&ip->lock) || ip->ref < 1)
326 panic("iunlock");
331// Mark the on-disk inode free.
332static void
335 struct buf *bp = bread(dev, IBLOCK(inum, sb));
336 struct dinode *dip = (struct dinode *)bp->data + inum % IPB;
337 dip->type = 0;
342// Drop a reference to an in-memory inode.
343// If that was the last reference, the inode table entry can
344// be recycled.
345// If that was the last reference and the inode has no links
346// to it, free the inode (and its content) on disk.
347// All calls to iput() must be inside a transaction in
348// case it has to free the inode.
349void
350iput(struct inode *ip)
354 // Last reference of an unlinked inode? Capture dev/inum before ref--,
355 // since once ref hits 0, ip may be recycled by a concurrent iget()
356 // for a different inum.
357 int last = (ip->ref == 1 && ip->valid && ip->nlink == 0);
360 if (last) {
361 // ip->ref == 1 means no other process can have ip locked.
365 itrunc(ip); // free the data blocks (type stays nonzero on disk)
366 ip->valid = 0;
371 }
373 ip->ref--;
376 if (last)
377 ifree(dev, inum); // now clear type on disk: inum becomes allocatable
380// Common idiom: unlock, then put.
381void
388void
391 for (int inum = 1; inum < sb.ninodes; inum++) {
392 struct inode *ip = 0;
393 struct buf *bp = bread(dev, IBLOCK(inum, sb));
394 struct dinode *dip = (struct dinode *)bp->data + inum % IPB;
395 if (dip->type != 0 && dip->nlink == 0) { // is an orphaned inode
396 printk("ireclaim: orphaned inode %d\n", inum);
398 }
400 if (ip) {
406 }
407 }
410// Inode content
411//
412// The content (data) associated with each inode is stored
413// in blocks on the disk. The first NDIRECT block numbers
414// are listed in ip->addrs[]. The next NINDIRECT blocks are
415// listed in block ip->addrs[NDIRECT].
417// Return the disk block address of the nth block in inode ip.
418// If there is no such block, bmap allocates one.
419// returns 0 if out of disk space.
420static uint
421bmap(struct inode *ip, uint bn)
424 struct buf *bp;
426 if (bn < NDIRECT) {
427 if ((addr = ip->addrs[bn]) == 0) {
429 if (addr == 0)
430 return 0;
432 }
433 return addr;
434 }
437 if (bn < NINDIRECT) {
438 // Load indirect block, allocating if necessary.
439 if ((addr = ip->addrs[NDIRECT]) == 0) {
441 if (addr == 0)
442 return 0;
444 }
446 a = (uint *)bp->data;
447 if ((addr = a[bn]) == 0) {
449 if (addr) {
450 a[bn] = addr;
452 }
453 }
455 return addr;
456 }
458 panic("bmap: out of range");
461// Truncate inode (discard contents).
462// Caller must hold ip->lock.
463void
464itrunc(struct inode *ip)
466 int i, j;
467 struct buf *bp;
470 for (i = 0; i < NDIRECT; i++) {
471 if (ip->addrs[i]) {
473 ip->addrs[i] = 0;
474 }
475 }
477 if (ip->addrs[NDIRECT]) {
479 a = (uint *)bp->data;
480 for (j = 0; j < NINDIRECT; j++) {
481 if (a[j])
482 bfree(ip->dev, a[j]);
483 }
487 }
489 ip->size = 0;
493// Copy stat information from inode.
494// Caller must hold ip->lock.
495void
496stati(struct inode *ip, struct stat *st)
498 st->dev = ip->dev;
505// Read data from inode.
506// Caller must hold ip->lock.
507// If user_dst==1, then dst is a user virtual address;
508// otherwise, dst is a kernel address.
509int
513 struct buf *bp;
515 if (off > ip->size || off + n < off)
516 return 0;
517 if (off + n > ip->size)
518 n = ip->size - off;
520 for (tot = 0; tot < n; tot += m, off += m, dst += m) {
522 if (addr == 0)
523 break;
525 m = min(n - tot, BSIZE - off % BSIZE);
526 if (either_copyout(user_dst, dst, bp->data + (off % BSIZE), m) == -1) {
528 tot = -1;
529 break;
530 }
532 }
533 return tot;
536// Write data to inode.
537// Caller must hold ip->lock.
538// If user_src==1, then src is a user virtual address;
539// otherwise, src is a kernel address.
540// Returns the number of bytes successfully written.
541// If the return value is less than the requested n,
542// there was an error of some kind.
543int
547 struct buf *bp;
549 if (off > ip->size || off + n < off)
550 return -1;
551 if (off + n > MAXFILE * BSIZE)
552 return -1;
554 for (tot = 0; tot < n; tot += m, off += m, src += m) {
556 if (addr == 0)
557 break;
559 m = min(n - tot, BSIZE - off % BSIZE);
560 if (either_copyin(bp->data + (off % BSIZE), user_src, src, m) == -1) {
561 // Might have partially updated the block, so we need to log it.
564 break;
565 }
568 }
570 if (off > ip->size)
573 // write the i-node back to disk even if the size didn't change
574 // because the loop above might have called bmap() and added a new
575 // block to ip->addrs[].
578 return tot;
581// Directories
583int
584namecmp(const char *s, const char *t)
586 return strncmp(s, t, DIRSIZ);
589// Look for a directory entry in a directory.
590// If found, set *poff to byte offset of entry.
591struct inode *
592dirlookup(struct inode *dp, char *name, uint *poff)
595 struct dirent de;
597 if (dp->type != T_DIR)
598 panic("dirlookup not DIR");
600 for (off = 0; off < dp->size; off += sizeof(de)) {
601 if (readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
602 panic("dirlookup read");
603 if (de.inum == 0)
604 continue;
605 if (namecmp(name, de.name) == 0) {
606 // entry matches path element
607 if (poff)
610 return iget(dp->dev, inum);
611 }
612 }
614 return 0;
617// Write a new directory entry (name, inum) into the directory dp.
618// Returns 0 on success, -1 on failure (e.g. out of disk blocks).
619int
620dirlink(struct inode *dp, char *name, uint inum)
622 int off;
623 struct dirent de;
624 struct inode *ip;
626 // Check that name is not present.
627 if ((ip = dirlookup(dp, name, 0)) != 0) {
629 return -1;
630 }
632 // Look for an empty dirent.
633 for (off = 0; off < dp->size; off += sizeof(de)) {
634 if (readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
635 panic("dirlink read");
636 if (de.inum == 0)
637 break;
638 }
642 if (writei(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
643 return -1;
645 return 0;
648// Paths
650// Copy the next path element from path into name.
651// Return a pointer to the element following the copied one.
652// The returned path has no leading slashes,
653// so the caller can check *path=='\0' to see if the name is the last one.
654// If no name to remove, return 0.
655//
656// Examples:
657// skipelem("a/bb/c", name) = "bb/c", setting name = "a"
658// skipelem("///a//bb", name) = "bb", setting name = "a"
659// skipelem("a", name) = "", setting name = "a"
660// skipelem("", name) = skipelem("////", name) = 0
661//
662static char *
663skipelem(char *path, char *name)
665 char *s;
666 int len;
668 while (*path == '/')
670 if (*path == 0)
671 return 0;
673 while (*path != '/' && *path != 0)
675 len = path - s;
676 if (len >= DIRSIZ)
678 else {
680 name[len] = 0;
681 }
682 while (*path == '/')
684 return path;
687// Look up and return the inode for a path name.
688// If parent != 0, return the inode for the parent and copy the final
689// path element into name, which must have room for DIRSIZ bytes.
690// Must be called inside a transaction since it calls iput().
691static struct inode *
692namex(char *path, int nameiparent, char *name)
694 struct inode *ip, *next;
696 if (*path == '/')
698 else
701 while ((path = skipelem(path, name)) != 0) {
703 if (ip->type != T_DIR) {
705 return 0;
706 }
707 if (ip->nlink == 0) {
709 return 0;
710 }
711 if (nameiparent && *path == '\0') {
712 // Stop one level early.
714 return ip;
715 }
716 if ((next = dirlookup(ip, name, 0)) == 0) {
718 return 0;
719 }
722 }
725 return 0;
726 }
727 return ip;
730struct inode *
731namei(char *path)
733 char name[DIRSIZ];
734 return namex(path, 0, name);
737struct inode *
738nameiparent(char *path, char *name)
740 return namex(path, 1, name);