shuffle fs.c in bottom-up order

This commit is contained in:
rsc 2007-08-20 18:23:52 +00:00
parent 0655445ba9
commit bcca6c6bde
5 changed files with 324 additions and 328 deletions

2
defs.h
View file

@ -120,7 +120,6 @@ void bwrite(struct buf*, uint);
void brelse(struct buf*); void brelse(struct buf*);
// fs.c // fs.c
extern uint rootdev;
void iinit(void); void iinit(void);
struct inode* iget(uint, uint); struct inode* iget(uint, uint);
void ilock(struct inode*); void ilock(struct inode*);
@ -138,6 +137,7 @@ struct inode* mknod1(struct inode*, char*, short, short, short);
int unlink(char*); int unlink(char*);
void iupdate(struct inode*); void iupdate(struct inode*);
int link(char*, char*); int link(char*, char*);
struct inode* igetroot(void);
// number of elements in fixed-size array // number of elements in fixed-size array
#define NELEM(x) (sizeof(x)/sizeof((x)[0])) #define NELEM(x) (sizeof(x)/sizeof((x)[0]))

640
fs.c
View file

@ -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 "types.h"
#include "stat.h" #include "stat.h"
#include "param.h" #include "param.h"
@ -11,31 +23,11 @@
#include "fsvar.h" #include "fsvar.h"
#include "dev.h" #include "dev.h"
// Inode table. The inode table is an in-memory cache of the #define min(a, b) ((a) < (b) ? (a) : (b))
// 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; static void ifree(struct inode*);
void // Blocks.
iinit(void)
{
initlock(&inode_table_lock, "inode_table");
}
// Allocate a disk block. // Allocate a disk block.
static uint static uint
@ -93,86 +85,166 @@ bfree(int dev, uint b)
brelse(bp); 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 // Find the inode with number inum on device dev
// and return an in-memory copy. Loads the inode // and return an in-memory copy. Loads the inode
// from disk into the in-core table if necessary. // 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. // Caller must iput the return value when done with it.
struct inode* struct inode*
iget(uint dev, uint inum) iget(uint dev, uint inum)
{ {
struct inode *ip, *nip; struct inode *ip, *empty;
struct dinode *dip; struct dinode *dip;
struct buf *bp; struct buf *bp;
acquire(&inode_table_lock); acquire(&icache.lock);
loop: loop:
nip = 0; // Try for cached inode.
for(ip = &inode[0]; ip < &inode[NINODE]; ip++){ empty = 0;
for(ip = &icache.inode[0]; ip < &icache.inode[NINODE]; ip++){
if(ip->ref > 0 && ip->dev == dev && ip->inum == inum){ if(ip->ref > 0 && ip->dev == dev && ip->inum == inum){
if(ip->busy){ if(ip->busy){
sleep(ip, &inode_table_lock); sleep(ip, &icache.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.
goto loop; goto loop;
} }
ip->ref++; ip->ref++;
ip->busy = 1; ip->busy = 1;
release(&inode_table_lock); release(&icache.lock);
return ip; return ip;
} }
if(nip == 0 && ip->ref == 0) if(empty == 0 && ip->ref == 0) // Remember empty slot.
nip = ip; empty = ip;
} }
if(nip == 0) // Allocate fresh inode.
if(empty == 0)
panic("iget: no inodes"); panic("iget: no inodes");
nip->dev = dev; ip = empty;
nip->inum = inum; ip->dev = dev;
nip->ref = 1; ip->inum = inum;
nip->busy = 1; ip->ref = 1;
ip->busy = 1;
release(&inode_table_lock); release(&icache.lock);
bp = bread(dev, IBLOCK(inum)); bp = bread(dev, IBLOCK(inum));
dip = &((struct dinode*)(bp->data))[inum % IPB]; dip = &((struct dinode*)(bp->data))[inum % IPB];
nip->type = dip->type; ip->type = dip->type;
nip->major = dip->major; ip->major = dip->major;
nip->minor = dip->minor; ip->minor = dip->minor;
nip->nlink = dip->nlink; ip->nlink = dip->nlink;
nip->size = dip->size; ip->size = dip->size;
memmove(nip->addrs, dip->addrs, sizeof(nip->addrs)); memmove(ip->addrs, dip->addrs, sizeof(ip->addrs));
brelse(bp); brelse(bp);
return nip; return ip;
} }
// Copy inode in memory, which has changed, to disk. // Iget the inode for the file system root (/).
// Caller must have locked ip. struct inode*
void igetroot(void)
iupdate(struct inode *ip)
{ {
struct buf *bp; return iget(ROOTDEV, 1);
struct dinode *dip;
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);
} }
// Allocate a new inode with the given type // Lock the given inode.
// from the file system on device dev. void
ilock(struct inode *ip)
{
if(ip->ref < 1)
panic("ilock");
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 on device dev.
struct inode* struct inode*
ialloc(uint dev, short type) ialloc(uint dev, short type)
{ {
@ -204,7 +276,27 @@ ialloc(uint dev, short type)
panic("ialloc: no inodes"); panic("ialloc: no inodes");
} }
// Free the given inode from its file system. // Copy inode, which has changed, from memory to disk.
void
iupdate(struct inode *ip)
{
struct buf *bp;
struct dinode *dip;
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);
}
// Free (delete) the given inode.
// Caller must have ip locked.
static void static void
ifree(struct inode *ip) ifree(struct inode *ip)
{ {
@ -212,141 +304,86 @@ ifree(struct inode *ip)
iupdate(ip); iupdate(ip);
} }
// Lock the given inode (wait for it to be not busy, // Inode contents
// and then ip->busy). //
// Caller must already hold a reference to ip. // The contents (data) associated with each inode is stored
// Otherwise, if all the references to ip go away, // in a sequence of blocks on the disk. The first NDIRECT blocks
// it might be reused underfoot. // are stored in ip->addrs[]. The next NINDIRECT blocks are
void // listed in the block ip->addrs[INDIRECT].
ilock(struct inode *ip)
{
if(ip->ref < 1)
panic("ilock");
acquire(&inode_table_lock);
while(ip->busy)
sleep(ip, &inode_table_lock);
ip->busy = 1;
release(&inode_table_lock);
}
// 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)
{
if(ip->busy != 1 || ip->ref < 1)
panic("iunlock");
acquire(&inode_table_lock);
ip->busy = 0;
wakeup(ip);
release(&inode_table_lock);
}
// Return the disk block address of the nth block in inode ip. // 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 uint
bmap(struct inode *ip, uint bn) bmap(struct inode *ip, uint bn, int alloc)
{ {
uint *a, x; uint addr, *a;
struct buf *inbp; struct buf *bp;
if(bn >= MAXFILE)
panic("bmap 1");
if(bn < NDIRECT) { if(bn < NDIRECT) {
x = ip->addrs[bn]; if((addr = ip->addrs[bn]) == 0) {
if(x == 0) if(!alloc)
panic("bmap 2"); return -1;
} else { ip->addrs[bn] = addr = balloc(ip->dev);
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");
} }
return x; return addr;
}
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;
} }
// Truncate the inode ip, discarding all its data blocks. panic("bmap: out of range");
}
// Truncate inode (discard contents).
void void
itrunc(struct inode *ip) itrunc(struct inode *ip)
{ {
int i, j; int i, j;
struct buf *inbp; struct buf *bp;
uint *a; uint *a;
for(i = 0; i < NADDRS; i++) { for(i = 0; i < NDIRECT; i++) {
if(ip->addrs[i] != 0) { if(ip->addrs[i]) {
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);
}
bfree(ip->dev, ip->addrs[i]); bfree(ip->dev, ip->addrs[i]);
ip->addrs[i] = 0; ip->addrs[i] = 0;
} }
} }
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;
}
ip->size = 0; ip->size = 0;
iupdate(ip); 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);
}
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;
}
// Copy stat information from inode. // Copy stat information from inode.
void void
stati(struct inode *ip, struct stat *st) stati(struct inode *ip, struct stat *st)
@ -358,13 +395,11 @@ stati(struct inode *ip, struct stat *st)
st->size = ip->size; st->size = ip->size;
} }
#define min(a, b) ((a) < (b) ? (a) : (b))
// Read data from inode. // Read data from inode.
int int
readi(struct inode *ip, char *dst, uint off, uint n) readi(struct inode *ip, char *dst, uint off, uint n)
{ {
uint target, n1; uint tot, m;
struct buf *bp; struct buf *bp;
if(ip->type == T_DEV) { if(ip->type == T_DEV) {
@ -373,96 +408,122 @@ readi(struct inode *ip, char *dst, uint off, uint n)
return devsw[ip->major].read(ip->minor, dst, n); return devsw[ip->major].read(ip->minor, dst, n);
} }
target = n; if(off + n < off)
while(n > 0 && off < ip->size){ return -1;
bp = bread(ip->dev, bmap(ip, off / BSIZE)); if(off + n > ip->size)
n1 = min(n, ip->size - off); n = ip->size - off;
n1 = min(n1, BSIZE - (off % BSIZE));
memmove(dst, bp->data + (off % BSIZE), n1); for(tot=0; tot<n; tot+=m, off+=m, dst+=m) {
n -= n1; bp = bread(ip->dev, bmap(ip, off/BSIZE, 0));
off += n1; m = min(n - tot, BSIZE - off%BSIZE);
dst += n1; memmove(dst, bp->data + off%BSIZE, m);
brelse(bp); brelse(bp);
} }
return n;
return target - n;
}
// 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);
}
return 0;
} }
// Write data to inode. // Write data to inode.
int 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; struct buf *bp;
int r, m, lbn;
if(ip->type == T_DEV) { if(ip->type == T_DEV) {
if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].write) if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].write)
return -1; 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; ) { if(off + n < off)
lbn = off / BSIZE; return -1;
if(lbn >= MAXFILE) if(off + n > MAXFILE*BSIZE)
return r; n = MAXFILE*BSIZE - off;
if(newblock(ip, lbn) < 0) {
cprintf("newblock failed\n"); for(tot=0; tot<n; tot+=m, off+=m, src+=m) {
return r; bp = bread(ip->dev, bmap(ip, off/BSIZE, 1));
} m = min(n - tot, BSIZE - off%BSIZE);
m = min(BSIZE - off % BSIZE, n-r); memmove(bp->data + off%BSIZE, src, m);
bp = bread(ip->dev, bmap(ip, lbn)); bwrite(bp, bmap(ip, off/BSIZE, 0));
memmove(bp->data + off % BSIZE, addr, m);
bwrite(bp, bmap(ip, lbn));
brelse(bp); brelse(bp);
r += m;
off += m;
} }
if(r > 0 && off > ip->size) {
if(ip->type == T_DIR) if(n > 0 && off > ip->size) {
ip->size = ((off / BSIZE) + 1) * BSIZE;
else
ip->size = off; ip->size = off;
iupdate(ip); iupdate(ip);
} }
return r; return n;
} }
// Directories
//
// Directories are just inodes (files) filled with dirent structures.
// Look for a directory entry in a directory.
// If not found, return -1.
// If found:
// set *poff to the byte offset of the directory entry
// set *pinum to the inode number
// return 0.
static int
dirlookup(struct inode *dp, char *name, int namelen, uint *poff, uint *pinum)
{
uint off;
struct buf *bp;
struct dirent *de;
if(dp->type != T_DIR)
return -1;
for(off = 0; off < dp->size; off += BSIZE){
bp = bread(dp->dev, bmap(dp, off / BSIZE, 0));
for(de = (struct dirent*) bp->data;
de < (struct dirent*) (bp->data + BSIZE);
de++){
if(de->inum == 0)
continue;
if(memcmp(name, de->name, namelen) == 0 &&
(namelen == DIRSIZ || de->name[namelen]== 0)){
// entry matches path element
*poff = off + (uchar*)de - bp->data;
*pinum = de->inum;
brelse(bp);
return 0;
}
}
brelse(bp);
}
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, // Skip over the next path element in path,
// saving it in *name and its length in *len. // saving it in *name and its length in *len.
// Return a pointer to the element after that // Return a pointer to the element after that
@ -493,43 +554,6 @@ skipelem(char *path, char **name, int *len)
return path; return path;
} }
// Look for a directory entry in a directory.
// If not found, return -1.
// If found:
// set *poff to the byte offset of the directory entry
// set *pinum to the inode number
// return 0.
static int
lookup(struct inode *dp, char *name, int namelen, uint *poff, uint *pinum)
{
uint off;
struct buf *bp;
struct dirent *de;
if(dp->type != T_DIR)
return -1;
for(off = 0; off < dp->size; off += BSIZE){
bp = bread(dp->dev, bmap(dp, off / BSIZE));
for(de = (struct dirent*) bp->data;
de < (struct dirent*) (bp->data + BSIZE);
de++){
if(de->inum == 0)
continue;
if(memcmp(name, de->name, namelen) == 0 &&
(namelen == DIRSIZ || de->name[namelen]== 0)){
// entry matches path element
*poff = off + (uchar*)de - bp->data;
*pinum = de->inum;
brelse(bp);
return 0;
}
}
brelse(bp);
}
return -1;
}
// look up a path name, in one of three modes. // look up a path name, in one of three modes.
// NAMEI_LOOKUP: return locked target inode. // NAMEI_LOOKUP: return locked target inode.
// NAMEI_CREATE: return locked parent inode. // NAMEI_CREATE: return locked parent inode.
@ -556,7 +580,7 @@ namei(char *path, int mode, uint *ret_off,
*ret_ip = 0; *ret_ip = 0;
if(*path == '/') if(*path == '/')
dp = iget(rootdev, 1); dp = igetroot();
else { else {
dp = iincref(cp->cwd); dp = iincref(cp->cwd);
ilock(dp); ilock(dp);
@ -570,7 +594,7 @@ namei(char *path, int mode, uint *ret_off,
if(dp->type != T_DIR) if(dp->type != T_DIR)
goto fail; goto fail;
if(lookup(dp, name, namelen, &off, &inum) < 0){ if(dirlookup(dp, name, namelen, &off, &inum) < 0){
if(mode == NAMEI_CREATE && *path == '\0'){ if(mode == NAMEI_CREATE && *path == '\0'){
*ret_last = name; *ret_last = name;
return dp; return dp;
@ -608,32 +632,6 @@ fail:
return 0; 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. // Create the path and return its locked inode structure.
// If cp already exists, return 0. // If cp already exists, return 0.
struct inode* 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 iupdate(ip); // write new inode to disk
wdir(dp, name, ip->inum); dirwrite(dp, name, ip->inum);
return ip; return ip;
} }
@ -750,7 +748,7 @@ link(char *name1, char *name2)
ip->nlink++; ip->nlink++;
iupdate(ip); iupdate(ip);
wdir(dp, last, ip->inum); dirwrite(dp, last, ip->inum);
iput(dp); iput(dp);
iput(ip); iput(ip);

2
fs.h
View file

@ -55,5 +55,3 @@ struct dirent {
char name[DIRSIZ]; char name[DIRSIZ];
}; };
extern uint rootdev; // Device number of root file system

View file

@ -14,7 +14,7 @@ struct inode {
uint addrs[NADDRS]; uint addrs[NADDRS];
}; };
extern uint rootdev; #define ROOTDEV 1 // Device number of root file system
#define NAMEI_LOOKUP 1 #define NAMEI_LOOKUP 1
#define NAMEI_CREATE 2 #define NAMEI_CREATE 2

2
main.c
View file

@ -125,7 +125,7 @@ process0(void)
release(&proc_table_lock); release(&proc_table_lock);
p0 = &proc[0]; p0 = &proc[0];
p0->cwd = iget(rootdev, 1); p0->cwd = igetroot();
iunlock(p0->cwd); iunlock(p0->cwd);
// Dummy user memory to make copyproc() happy. // Dummy user memory to make copyproc() happy.