summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--defs.h2
-rw-r--r--fs.c628
-rw-r--r--fs.h2
-rw-r--r--fsvar.h2
-rw-r--r--main.c2
5 files changed, 316 insertions, 320 deletions
diff --git a/defs.h b/defs.h
index 7de2fe1..074ad84 100644
--- a/defs.h
+++ b/defs.h
@@ -120,7 +120,6 @@ void bwrite(struct buf*, uint);
void brelse(struct buf*);
// fs.c
-extern uint rootdev;
void iinit(void);
struct inode* iget(uint, uint);
void ilock(struct inode*);
@@ -138,6 +137,7 @@ struct inode* mknod1(struct inode*, char*, short, short, short);
int unlink(char*);
void iupdate(struct inode*);
int link(char*, char*);
+struct inode* igetroot(void);
// number of elements in fixed-size array
#define NELEM(x) (sizeof(x)/sizeof((x)[0]))
diff --git a/fs.c b/fs.c
index c6f38b4..d8e6484 100644
--- a/fs.c
+++ b/fs.c
@@ -1,3 +1,15 @@
+// File system implementation.
+//
+// Four layers:
+// + Blocks: allocator for raw disk blocks.
+// + Files: inode allocator, reading, writing, metadata.
+// + Directories: inode with special contents (list of other inodes!)
+// + Names: paths like /usr/rtm/xv6/fs.c for convenient naming.
+//
+// Disk layout is: superblock, inodes, disk bitmap, data blocks.
+
+// TODO: Check locking!
+
#include "types.h"
#include "stat.h"
#include "param.h"
@@ -11,31 +23,11 @@
#include "fsvar.h"
#include "dev.h"
-// Inode table. The inode table is an in-memory cache of the
-// on-disk inode structures. If an inode in the table has a non-zero
-// reference count, then some open files refer to it and it must stay
-// in memory. If an inode has a zero reference count, it is only in
-// memory as a cache in hopes of being used again (avoiding a disk read).
-// Any inode with reference count zero can be evicted from the table.
-//
-// In addition to having a reference count, inodes can be marked busy
-// (just like bufs), meaning that some code has logically locked the
-// inode, and others are not allowed to look at it.
-// This locking can last for a long
-// time (for example, if the inode is busy during a disk access),
-// so we don't use spin locks. Instead, if a process wants to use
-// a particular inode, it must sleep(ip) to wait for it to be not busy.
-// See iget below.
-struct inode inode[NINODE];
-struct spinlock inode_table_lock;
-
-uint rootdev = 1;
+#define min(a, b) ((a) < (b) ? (a) : (b))
-void
-iinit(void)
-{
- initlock(&inode_table_lock, "inode_table");
-}
+static void ifree(struct inode*);
+
+// Blocks.
// Allocate a disk block.
static uint
@@ -93,86 +85,166 @@ bfree(int dev, uint b)
brelse(bp);
}
+// Inodes
+//
+// The inodes are laid out sequentially on disk immediately after
+// the superblock. The kernel keeps a cache of the in-use
+// on-disk structures to provide a place for synchronizing access
+// to inodes shared between multiple processes.
+//
+// ip->ref counts the number of references to this
+// inode; references are typically kept in struct file and in cp->cwd.
+// When ip->ref falls to zero, the inode is no longer cached.
+// It is an error to use an inode without holding a reference to it.
+//
+// Inodes can be marked busy, just like bufs, meaning
+// that some process has logically locked the inode, and other processes
+// are not allowed to look at it. Because the locking can last for
+// a long time (for example, during a disk access), we use a flag
+// like in buffer cache, not spin locks. The inode should always be
+// locked during modifications to it.
+
+struct {
+ struct spinlock lock;
+ struct inode inode[NINODE];
+} icache;
+
+void
+iinit(void)
+{
+ initlock(&icache.lock, "icache.lock");
+}
+
// Find the inode with number inum on device dev
// and return an in-memory copy. Loads the inode
// from disk into the in-core table if necessary.
-// The returned inode has busy set and has its ref count incremented.
+// The returned inode is locked and has its ref count incremented.
// Caller must iput the return value when done with it.
struct inode*
iget(uint dev, uint inum)
{
- struct inode *ip, *nip;
+ struct inode *ip, *empty;
struct dinode *dip;
struct buf *bp;
- acquire(&inode_table_lock);
+ acquire(&icache.lock);
loop:
- nip = 0;
- for(ip = &inode[0]; ip < &inode[NINODE]; ip++){
+ // Try for cached inode.
+ empty = 0;
+ for(ip = &icache.inode[0]; ip < &icache.inode[NINODE]; ip++){
if(ip->ref > 0 && ip->dev == dev && ip->inum == inum){
if(ip->busy){
- sleep(ip, &inode_table_lock);
- // Since we droped inode_table_lock, ip might have been reused
- // for some other inode entirely. Must start the scan over,
- // and hopefully this time we will find the inode we want
- // and it will not be busy.
+ sleep(ip, &icache.lock);
goto loop;
}
ip->ref++;
ip->busy = 1;
- release(&inode_table_lock);
+ release(&icache.lock);
return ip;
}
- if(nip == 0 && ip->ref == 0)
- nip = ip;
+ if(empty == 0 && ip->ref == 0) // Remember empty slot.
+ empty = ip;
}
- if(nip == 0)
+ // Allocate fresh inode.
+ if(empty == 0)
panic("iget: no inodes");
- nip->dev = dev;
- nip->inum = inum;
- nip->ref = 1;
- nip->busy = 1;
-
- release(&inode_table_lock);
+ ip = empty;
+ ip->dev = dev;
+ ip->inum = inum;
+ ip->ref = 1;
+ ip->busy = 1;
+ release(&icache.lock);
bp = bread(dev, IBLOCK(inum));
dip = &((struct dinode*)(bp->data))[inum % IPB];
- nip->type = dip->type;
- nip->major = dip->major;
- nip->minor = dip->minor;
- nip->nlink = dip->nlink;
- nip->size = dip->size;
- memmove(nip->addrs, dip->addrs, sizeof(nip->addrs));
+ ip->type = dip->type;
+ ip->major = dip->major;
+ ip->minor = dip->minor;
+ ip->nlink = dip->nlink;
+ ip->size = dip->size;
+ memmove(ip->addrs, dip->addrs, sizeof(ip->addrs));
brelse(bp);
- return nip;
+ return ip;
+}
+
+// Iget the inode for the file system root (/).
+struct inode*
+igetroot(void)
+{
+ return iget(ROOTDEV, 1);
}
-// Copy inode in memory, which has changed, to disk.
-// Caller must have locked ip.
+// Lock the given inode.
void
-iupdate(struct inode *ip)
+ilock(struct inode *ip)
{
- struct buf *bp;
- struct dinode *dip;
+ if(ip->ref < 1)
+ panic("ilock");
- bp = bread(ip->dev, IBLOCK(ip->inum));
- dip = &((struct dinode*)(bp->data))[ip->inum % IPB];
- dip->type = ip->type;
- dip->major = ip->major;
- dip->minor = ip->minor;
- dip->nlink = ip->nlink;
- dip->size = ip->size;
- memmove(dip->addrs, ip->addrs, sizeof(ip->addrs));
- bwrite(bp, IBLOCK(ip->inum));
- brelse(bp);
+ acquire(&icache.lock);
+ while(ip->busy)
+ sleep(ip, &icache.lock);
+ ip->busy = 1;
+ release(&icache.lock);
+}
+
+// Unlock the given inode.
+void
+iunlock(struct inode *ip)
+{
+ if(ip->busy != 1 || ip->ref < 1)
+ panic("iunlock");
+
+ acquire(&icache.lock);
+ ip->busy = 0;
+ wakeup(ip);
+ release(&icache.lock);
+}
+
+// Unlock inode and drop reference.
+void
+iput(struct inode *ip)
+{
+ if(ip->ref < 1 || ip->busy != 1)
+ panic("iput");
+
+ if((ip->ref == 1) && (ip->nlink == 0)) {
+ itrunc(ip);
+ ifree(ip);
+ }
+
+ acquire(&icache.lock);
+ ip->ref -= 1;
+ ip->busy = 0;
+ wakeup(ip);
+ release(&icache.lock);
+}
+
+// Increment reference count for ip.
+// Returns ip to enable ip = iincref(ip1) idiom.
+struct inode*
+iincref(struct inode *ip)
+{
+ ilock(ip);
+ ip->ref++;
+ iunlock(ip);
+ return ip;
+}
+
+// Caller holds reference to unlocked ip.
+// Drop reference.
+void
+idecref(struct inode *ip)
+{
+ ilock(ip);
+ iput(ip);
}
-// Allocate a new inode with the given type
-// from the file system on device dev.
+// Allocate a new inode with the given type on device dev.
struct inode*
ialloc(uint dev, short type)
{
@@ -184,7 +256,7 @@ ialloc(uint dev, short type)
struct buf *bp;
bp = bread(dev, 1);
- sb = (struct superblock*) bp->data;
+ sb = (struct superblock*)bp->data;
ninodes = sb->ninodes;
brelse(bp);
@@ -204,147 +276,112 @@ ialloc(uint dev, short type)
panic("ialloc: no inodes");
}
-// Free the given inode from its file system.
-static void
-ifree(struct inode *ip)
-{
- ip->type = 0;
- iupdate(ip);
-}
-
-// Lock the given inode (wait for it to be not busy,
-// and then ip->busy).
-// Caller must already hold a reference to ip.
-// Otherwise, if all the references to ip go away,
-// it might be reused underfoot.
+// Copy inode, which has changed, from memory to disk.
void
-ilock(struct inode *ip)
+iupdate(struct inode *ip)
{
- if(ip->ref < 1)
- panic("ilock");
-
- acquire(&inode_table_lock);
-
- while(ip->busy)
- sleep(ip, &inode_table_lock);
- ip->busy = 1;
+ struct buf *bp;
+ struct dinode *dip;
- release(&inode_table_lock);
+ bp = bread(ip->dev, IBLOCK(ip->inum));
+ dip = &((struct dinode*)(bp->data))[ip->inum % IPB];
+ dip->type = ip->type;
+ dip->major = ip->major;
+ dip->minor = ip->minor;
+ dip->nlink = ip->nlink;
+ dip->size = ip->size;
+ memmove(dip->addrs, ip->addrs, sizeof(ip->addrs));
+ bwrite(bp, IBLOCK(ip->inum));
+ brelse(bp);
}
-// Caller holds reference to ip and has locked it.
-// Caller no longer needs to examine / change it.
-// Unlock it, but keep the reference.
-void
-iunlock(struct inode *ip)
+// Free (delete) the given inode.
+// Caller must have ip locked.
+static void
+ifree(struct inode *ip)
{
- if(ip->busy != 1 || ip->ref < 1)
- panic("iunlock");
-
- acquire(&inode_table_lock);
-
- ip->busy = 0;
- wakeup(ip);
-
- release(&inode_table_lock);
+ ip->type = 0;
+ iupdate(ip);
}
+// Inode contents
+//
+// The contents (data) associated with each inode is stored
+// in a sequence of blocks on the disk. The first NDIRECT blocks
+// are stored in ip->addrs[]. The next NINDIRECT blocks are
+// listed in the block ip->addrs[INDIRECT].
+
// Return the disk block address of the nth block in inode ip.
+// If there is no such block: if alloc is set, allocate one, else return -1.
uint
-bmap(struct inode *ip, uint bn)
+bmap(struct inode *ip, uint bn, int alloc)
{
- uint *a, x;
- struct buf *inbp;
+ uint addr, *a;
+ struct buf *bp;
- if(bn >= MAXFILE)
- panic("bmap 1");
if(bn < NDIRECT) {
- x = ip->addrs[bn];
- if(x == 0)
- panic("bmap 2");
- } else {
- if(ip->addrs[INDIRECT] == 0)
- panic("bmap 3");
- inbp = bread(ip->dev, ip->addrs[INDIRECT]);
- a = (uint*) inbp->data;
- x = a[bn - NDIRECT];
- brelse(inbp);
- if(x == 0)
- panic("bmap 4");
+ if((addr = ip->addrs[bn]) == 0) {
+ if(!alloc)
+ return -1;
+ ip->addrs[bn] = addr = balloc(ip->dev);
+ }
+ return addr;
}
- return x;
+ bn -= NDIRECT;
+
+ if(bn < NINDIRECT) {
+ // Load indirect block, allocating if necessary.
+ if((addr = ip->addrs[INDIRECT]) == 0) {
+ if(!alloc)
+ return -1;
+ ip->addrs[INDIRECT] = addr = balloc(ip->dev);
+ }
+ bp = bread(ip->dev, addr);
+ a = (uint*)bp->data;
+
+ if((addr = a[bn]) == 0) {
+ if(!alloc) {
+ brelse(bp);
+ return -1;
+ }
+ a[bn] = addr = balloc(ip->dev);
+ bwrite(bp, ip->addrs[INDIRECT]);
+ }
+ brelse(bp);
+ return addr;
+ }
+
+ panic("bmap: out of range");
}
-// Truncate the inode ip, discarding all its data blocks.
+// Truncate inode (discard contents).
void
itrunc(struct inode *ip)
{
int i, j;
- struct buf *inbp;
+ struct buf *bp;
uint *a;
- for(i = 0; i < NADDRS; i++) {
- if(ip->addrs[i] != 0) {
- if(i == INDIRECT) {
- inbp = bread(ip->dev, ip->addrs[INDIRECT]);
- a = (uint*)inbp->data;
- for(j = 0; j < NINDIRECT; j++) {
- if(a[j] != 0) {
- bfree(ip->dev, a[j]);
- a[j] = 0;
- }
- }
- brelse(inbp);
- }
+ for(i = 0; i < NDIRECT; i++) {
+ if(ip->addrs[i]) {
bfree(ip->dev, ip->addrs[i]);
ip->addrs[i] = 0;
}
}
- ip->size = 0;
- iupdate(ip);
-}
-
-// Caller holds reference to ip and has locked it,
-// possibly editing it.
-// Release lock and drop the reference.
-void
-iput(struct inode *ip)
-{
- if(ip->ref < 1 || ip->busy != 1)
- panic("iput");
-
- if((ip->ref == 1) && (ip->nlink == 0)) {
- itrunc(ip);
- ifree(ip);
+
+ if(ip->addrs[INDIRECT]) {
+ bp = bread(ip->dev, ip->addrs[INDIRECT]);
+ a = (uint*)bp->data;
+ for(j = 0; j < NINDIRECT; j++) {
+ if(a[j])
+ bfree(ip->dev, a[j]);
+ }
+ brelse(bp);
+ ip->addrs[INDIRECT] = 0;
}
- acquire(&inode_table_lock);
-
- ip->ref -= 1;
- ip->busy = 0;
- wakeup(ip);
-
- release(&inode_table_lock);
-}
-
-// Caller holds reference to ip but not lock.
-// Drop reference.
-void
-idecref(struct inode *ip)
-{
- ilock(ip);
- iput(ip);
-}
-
-// Increment reference count for ip.
-// Returns ip to enable ip = iincref(ip1) idiom.
-struct inode*
-iincref(struct inode *ip)
-{
- ilock(ip);
- ip->ref++;
- iunlock(ip);
- return ip;
+ ip->size = 0;
+ iupdate(ip);
}
// Copy stat information from inode.
@@ -358,13 +395,11 @@ stati(struct inode *ip, struct stat *st)
st->size = ip->size;
}
-#define min(a, b) ((a) < (b) ? (a) : (b))
-
// Read data from inode.
int
readi(struct inode *ip, char *dst, uint off, uint n)
{
- uint target, n1;
+ uint tot, m;
struct buf *bp;
if(ip->type == T_DEV) {
@@ -373,125 +408,56 @@ readi(struct inode *ip, char *dst, uint off, uint n)
return devsw[ip->major].read(ip->minor, dst, n);
}
- target = n;
- while(n > 0 && off < ip->size){
- bp = bread(ip->dev, bmap(ip, off / BSIZE));
- n1 = min(n, ip->size - off);
- n1 = min(n1, BSIZE - (off % BSIZE));
- memmove(dst, bp->data + (off % BSIZE), n1);
- n -= n1;
- off += n1;
- dst += n1;
- brelse(bp);
- }
-
- return target - n;
-}
+ if(off + n < off)
+ return -1;
+ if(off + n > ip->size)
+ n = ip->size - off;
-// Allocate the nth block in inode ip if necessary.
-static int
-newblock(struct inode *ip, uint lbn)
-{
- struct buf *inbp;
- uint *inaddrs;
- uint b;
-
- if(lbn < NDIRECT) {
- if(ip->addrs[lbn] == 0) {
- b = balloc(ip->dev);
- if(b <= 0)
- return -1;
- ip->addrs[lbn] = b;
- }
- } else {
- if(ip->addrs[INDIRECT] == 0) {
- b = balloc(ip->dev);
- if(b <= 0)
- return -1;
- ip->addrs[INDIRECT] = b;
- }
- inbp = bread(ip->dev, ip->addrs[INDIRECT]);
- inaddrs = (uint*) inbp->data;
- if(inaddrs[lbn - NDIRECT] == 0) {
- b = balloc(ip->dev);
- if(b <= 0)
- return -1;
- inaddrs[lbn - NDIRECT] = b;
- bwrite(inbp, ip->addrs[INDIRECT]);
- }
- brelse(inbp);
+ for(tot=0; tot<n; tot+=m, off+=m, dst+=m) {
+ bp = bread(ip->dev, bmap(ip, off/BSIZE, 0));
+ m = min(n - tot, BSIZE - off%BSIZE);
+ memmove(dst, bp->data + off%BSIZE, m);
+ brelse(bp);
}
- return 0;
+ return n;
}
// Write data to inode.
int
-writei(struct inode *ip, char *addr, uint off, uint n)
+writei(struct inode *ip, char *src, uint off, uint n)
{
+ uint tot, m;
struct buf *bp;
- int r, m, lbn;
if(ip->type == T_DEV) {
if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].write)
return -1;
- return devsw[ip->major].write(ip->minor, addr, n);
+ return devsw[ip->major].write(ip->minor, src, n);
}
- for(r=0; r<n; ) {
- lbn = off / BSIZE;
- if(lbn >= MAXFILE)
- return r;
- if(newblock(ip, lbn) < 0) {
- cprintf("newblock failed\n");
- return r;
- }
- m = min(BSIZE - off % BSIZE, n-r);
- bp = bread(ip->dev, bmap(ip, lbn));
- memmove(bp->data + off % BSIZE, addr, m);
- bwrite(bp, bmap(ip, lbn));
+ if(off + n < off)
+ return -1;
+ if(off + n > MAXFILE*BSIZE)
+ n = MAXFILE*BSIZE - off;
+
+ for(tot=0; tot<n; tot+=m, off+=m, src+=m) {
+ bp = bread(ip->dev, bmap(ip, off/BSIZE, 1));
+ m = min(n - tot, BSIZE - off%BSIZE);
+ memmove(bp->data + off%BSIZE, src, m);
+ bwrite(bp, bmap(ip, off/BSIZE, 0));
brelse(bp);
- r += m;
- off += m;
}
- if(r > 0 && off > ip->size) {
- if(ip->type == T_DIR)
- ip->size = ((off / BSIZE) + 1) * BSIZE;
- else
- ip->size = off;
+
+ if(n > 0 && off > ip->size) {
+ ip->size = off;
iupdate(ip);
}
- return r;
+ return n;
}
-// Skip over the next path element in path,
-// saving it in *name and its length in *len.
-// Return a pointer to the element after that
-// (after any trailing slashes).
-// Thus the caller can check whether *path=='\0'
-// to see whether the name just removed was
-// the last one.
-// If there is no name to remove, return 0.
+// Directories
//
-// Examples:
-// skipelem("a/bb/c") = "bb/c", with *name = "a/bb/c", len=1
-// skipelem("///a/bb") = "b", with *name="a/bb", len=1
-// skipelem("") = skipelem("////") = 0
-//
-static char*
-skipelem(char *path, char **name, int *len)
-{
- while(*path == '/')
- path++;
- if(*path == 0)
- return 0;
- *name = path;
- while(*path != '/' && *path != 0)
- path++;
- *len = path - *name;
- while(*path == '/')
- path++;
- return path;
-}
+// Directories are just inodes (files) filled with dirent structures.
// Look for a directory entry in a directory.
// If not found, return -1.
@@ -500,7 +466,7 @@ skipelem(char *path, char **name, int *len)
// set *pinum to the inode number
// return 0.
static int
-lookup(struct inode *dp, char *name, int namelen, uint *poff, uint *pinum)
+dirlookup(struct inode *dp, char *name, int namelen, uint *poff, uint *pinum)
{
uint off;
struct buf *bp;
@@ -510,7 +476,7 @@ lookup(struct inode *dp, char *name, int namelen, uint *poff, uint *pinum)
return -1;
for(off = 0; off < dp->size; off += BSIZE){
- bp = bread(dp->dev, bmap(dp, off / BSIZE));
+ bp = bread(dp->dev, bmap(dp, off / BSIZE, 0));
for(de = (struct dirent*) bp->data;
de < (struct dirent*) (bp->data + BSIZE);
de++){
@@ -530,6 +496,64 @@ lookup(struct inode *dp, char *name, int namelen, uint *poff, uint *pinum)
return -1;
}
+// Write a new directory entry (name, ino) into the directory dp.
+// Caller must have locked dp.
+void
+dirwrite(struct inode *dp, char *name, uint ino)
+{
+ int i, off;
+ struct dirent de;
+
+ // Look for an empty dirent.
+ for(off = 0; off < dp->size; off += sizeof(de)){
+ if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
+ panic("dirwrite read");
+ if(de.inum == 0)
+ break;
+ }
+
+ de.inum = ino;
+ for(i = 0; i < DIRSIZ && name[i]; i++)
+ de.name[i] = name[i];
+ for(; i < DIRSIZ; i++)
+ de.name[i] = '\0';
+
+ if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
+ panic("dirwrite");
+}
+
+// Paths
+
+// Skip over the next path element in path,
+// saving it in *name and its length in *len.
+// Return a pointer to the element after that
+// (after any trailing slashes).
+// Thus the caller can check whether *path=='\0'
+// to see whether the name just removed was
+// the last one.
+// If there is no name to remove, return 0.
+//
+// Examples:
+// skipelem("a/bb/c") = "bb/c", with *name = "a/bb/c", len=1
+// skipelem("///a/bb") = "b", with *name="a/bb", len=1
+// skipelem("") = skipelem("////") = 0
+//
+static char*
+skipelem(char *path, char **name, int *len)
+{
+ while(*path == '/')
+ path++;
+ if(*path == 0)
+ return 0;
+ *name = path;
+ while(*path != '/' && *path != 0)
+ path++;
+ *len = path - *name;
+ while(*path == '/')
+ path++;
+ return path;
+}
+
// look up a path name, in one of three modes.
// NAMEI_LOOKUP: return locked target inode.
// NAMEI_CREATE: return locked parent inode.
@@ -556,7 +580,7 @@ namei(char *path, int mode, uint *ret_off,
*ret_ip = 0;
if(*path == '/')
- dp = iget(rootdev, 1);
+ dp = igetroot();
else {
dp = iincref(cp->cwd);
ilock(dp);
@@ -570,7 +594,7 @@ namei(char *path, int mode, uint *ret_off,
if(dp->type != T_DIR)
goto fail;
- if(lookup(dp, name, namelen, &off, &inum) < 0){
+ if(dirlookup(dp, name, namelen, &off, &inum) < 0){
if(mode == NAMEI_CREATE && *path == '\0'){
*ret_last = name;
return dp;
@@ -608,32 +632,6 @@ fail:
return 0;
}
-// Write a new directory entry (name, ino) into the directory dp.
-// Caller must have locked dp.
-void
-wdir(struct inode *dp, char *name, uint ino)
-{
- uint off;
- struct dirent de;
- int i;
-
- for(off = 0; off < dp->size; off += sizeof(de)){
- if(readi(dp, (char*) &de, off, sizeof(de)) != sizeof(de))
- panic("wdir read");
- if(de.inum == 0)
- break;
- }
-
- de.inum = ino;
- for(i = 0; i < DIRSIZ && name[i]; i++)
- de.name[i] = name[i];
- for( ; i < DIRSIZ; i++)
- de.name[i] = '\0';
-
- if(writei(dp, (char*) &de, off, sizeof(de)) != sizeof(de))
- panic("wdir write");
-}
-
// Create the path and return its locked inode structure.
// If cp already exists, return 0.
struct inode*
@@ -670,7 +668,7 @@ mknod1(struct inode *dp, char *name, short type, short major, short minor)
iupdate(ip); // write new inode to disk
- wdir(dp, name, ip->inum);
+ dirwrite(dp, name, ip->inum);
return ip;
}
@@ -750,7 +748,7 @@ link(char *name1, char *name2)
ip->nlink++;
iupdate(ip);
- wdir(dp, last, ip->inum);
+ dirwrite(dp, last, ip->inum);
iput(dp);
iput(ip);
diff --git a/fs.h b/fs.h
index 89c200b..9517326 100644
--- a/fs.h
+++ b/fs.h
@@ -55,5 +55,3 @@ struct dirent {
char name[DIRSIZ];
};
-extern uint rootdev; // Device number of root file system
-
diff --git a/fsvar.h b/fsvar.h
index 015bda4..449bf3d 100644
--- a/fsvar.h
+++ b/fsvar.h
@@ -14,7 +14,7 @@ struct inode {
uint addrs[NADDRS];
};
-extern uint rootdev;
+#define ROOTDEV 1 // Device number of root file system
#define NAMEI_LOOKUP 1
#define NAMEI_CREATE 2
diff --git a/main.c b/main.c
index 3652461..fb7a69a 100644
--- a/main.c
+++ b/main.c
@@ -125,7 +125,7 @@ process0(void)
release(&proc_table_lock);
p0 = &proc[0];
- p0->cwd = iget(rootdev, 1);
+ p0->cwd = igetroot();
iunlock(p0->cwd);
// Dummy user memory to make copyproc() happy.