提交 643e2f31 创建 作者: Nickolai Zeldovich's avatar Nickolai Zeldovich

initial buggy ns-based directory impl

上级 cb1f03f7
...@@ -45,7 +45,7 @@ int filewrite(struct file*, char*, int n); ...@@ -45,7 +45,7 @@ int filewrite(struct file*, char*, int n);
// fs.c // fs.c
int dirlink(struct inode*, char*, uint); int dirlink(struct inode*, char*, uint);
struct inode* dirlookup(struct inode*, char*, uint*); struct inode* dirlookup(struct inode*, char*);
struct inode* ialloc(uint, short); struct inode* ialloc(uint, short);
struct inode* iget(uint dev, uint inum); struct inode* iget(uint dev, uint inum);
struct inode* idup(struct inode*); struct inode* idup(struct inode*);
...@@ -61,6 +61,7 @@ struct inode* nameiparent(char*, char*); ...@@ -61,6 +61,7 @@ struct inode* nameiparent(char*, char*);
int readi(struct inode*, char*, uint, uint); int readi(struct inode*, char*, uint, uint);
void stati(struct inode*, struct stat*); void stati(struct inode*, struct stat*);
int writei(struct inode*, char*, uint, uint); int writei(struct inode*, char*, uint, uint);
void dir_init(struct inode *dp);
// ide.c // ide.c
void ideinit(void); void ideinit(void);
...@@ -132,10 +133,11 @@ struct nskey { ...@@ -132,10 +133,11 @@ struct nskey {
void nsinit(void); void nsinit(void);
struct ns* nsalloc(int allowdup); struct ns* nsalloc(int allowdup);
void nsfree(struct ns*);
int ns_allockey(struct ns*); int ns_allockey(struct ns*);
int ns_insert(struct ns*, struct nskey key, void*); int ns_insert(struct ns*, struct nskey key, void*);
void* ns_lookup(struct ns*, struct nskey key); void* ns_lookup(struct ns*, struct nskey key);
int ns_remove(struct ns *ns, struct nskey key, void *val); void* ns_remove(struct ns *ns, struct nskey key, void *val); // removed val
void* ns_enumerate(struct ns *ns, void *(*f)(void *, void *)); void* ns_enumerate(struct ns *ns, void *(*f)(void *, void *));
void* ns_enumerate_key(struct ns *ns, struct nskey key, void *(*f)(void *)); void* ns_enumerate_key(struct ns *ns, struct nskey key, void *(*f)(void *));
......
...@@ -21,6 +21,7 @@ struct inode { ...@@ -21,6 +21,7 @@ struct inode {
struct condvar cv; struct condvar cv;
struct spinlock lock; struct spinlock lock;
char lockname[16]; char lockname[16];
struct ns *dir;
short type; // copy of disk inode short type; // copy of disk inode
short major; short major;
......
...@@ -208,7 +208,7 @@ static void * ...@@ -208,7 +208,7 @@ static void *
evict(void *vkey, void *p) evict(void *vkey, void *p)
{ {
struct inode *ip = p; struct inode *ip = p;
if (ip->ref) if (ip->ref || ip->type == T_DIR)
return 0; return 0;
acquire(&ip->lock); acquire(&ip->lock);
...@@ -359,6 +359,14 @@ iput(struct inode *ip) ...@@ -359,6 +359,14 @@ iput(struct inode *ip)
panic("iput not valid"); panic("iput not valid");
ip->flags |= I_BUSYR | I_BUSYW; ip->flags |= I_BUSYR | I_BUSYW;
__sync_fetch_and_add(&ip->readbusy, 1); __sync_fetch_and_add(&ip->readbusy, 1);
if (ip->dir) {
ns_remove(ip->dir, KS("."), 0);
ns_remove(ip->dir, KS(".."), 0);
nsfree(ip->dir);
ip->dir = 0;
}
release(&ip->lock); release(&ip->lock);
itrunc(ip); itrunc(ip);
ip->type = 0; ip->type = 0;
...@@ -538,68 +546,62 @@ namecmp(const char *s, const char *t) ...@@ -538,68 +546,62 @@ namecmp(const char *s, const char *t)
return strncmp(s, t, DIRSIZ); return strncmp(s, t, DIRSIZ);
} }
// Look for a directory entry in a directory. void
// If found, set *poff to byte offset of entry. dir_init(struct inode *dp)
// Caller must have already locked dp.
struct inode*
dirlookup(struct inode *dp, char *name, uint *poff)
{ {
uint off, inum; if (dp->dir)
struct buf *bp; return;
struct dirent *de; if (dp->type != T_DIR)
panic("dir_init not DIR");
if(dp->type != T_DIR)
panic("dirlookup not DIR"); ilock(dp, 1);
if (dp->dir)
for(off = 0; off < dp->size; off += BSIZE){ return;
bp = bread(dp->dev, bmap(dp, off / BSIZE), 0);
for(de = (struct dirent*)bp->data; struct ns *dir = nsalloc(0);
de < (struct dirent*)(bp->data + BSIZE); for (uint off = 0; off < dp->size; off += BSIZE) {
de++){ struct buf *bp = bread(dp->dev, bmap(dp, off / BSIZE), 0);
if(de->inum == 0) for (struct dirent *de = (struct dirent *) bp->data;
continue; de < (struct dirent *) (bp->data + BSIZE);
if(namecmp(name, de->name) == 0){ de++) {
// entry matches path element if (de->inum == 0)
if(poff) continue;
*poff = off + (uchar*)de - bp->data;
inum = de->inum; char namebuf[DIRSIZ+1];
brelse(bp, 0); strncpy(namebuf, de->name, DIRSIZ);
return iget(dp->dev, inum); namebuf[DIRSIZ] = '\0';
} ns_insert(dir, KS(namebuf), (void*) (uint) de->inum);
} }
brelse(bp, 0); brelse(bp, 0);
} }
return 0; dp->dir = dir;
iunlock(dp);
}
// Look for a directory entry in a directory.
struct inode*
dirlookup(struct inode *dp, char *name)
{
dir_init(dp);
void *vinum = ns_lookup(dp->dir, KS(name));
uint inum = (uint) vinum;
//cprintf("dirlookup: %x (%d): %s -> %d\n", dp, dp->inum, name, inum);
if (inum == 0)
return 0;
return iget(dp->dev, inum);
} }
// Write a new directory entry (name, inum) into the directory dp. // Write a new directory entry (name, inum) into the directory dp.
int int
dirlink(struct inode *dp, char *name, uint inum) dirlink(struct inode *dp, char *name, uint inum)
{ {
int off; dir_init(dp);
struct dirent de;
struct inode *ip;
// Check that name is not present.
if((ip = dirlookup(dp, name, 0)) != 0){
iput(ip);
return -1;
}
// Look for an empty dirent. //cprintf("dirlink: %x (%d): %s -> %d\n", dp, dp->inum, name, inum);
for(off = 0; off < dp->size; off += sizeof(de)){ return ns_insert(dp->dir, KS(name), (void*)inum);
if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
panic("dirlink read");
if(de.inum == 0)
break;
}
strncpy(de.name, name, DIRSIZ);
de.inum = inum;
if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
panic("dirlink");
return 0;
} }
//PAGEBREAK! //PAGEBREAK!
...@@ -650,6 +652,7 @@ namex(char *path, int nameiparent, char *name) ...@@ -650,6 +652,7 @@ namex(char *path, int nameiparent, char *name)
{ {
struct inode *ip, *next; struct inode *ip, *next;
rcu_begin_read();
if(*path == '/') if(*path == '/')
ip = iget(ROOTDEV, ROOTINO); ip = iget(ROOTDEV, ROOTINO);
else else
...@@ -660,31 +663,34 @@ namex(char *path, int nameiparent, char *name) ...@@ -660,31 +663,34 @@ namex(char *path, int nameiparent, char *name)
if(nameiparent == 0) if(nameiparent == 0)
next = nc_lookup(ip, name); next = nc_lookup(ip, name);
if(next == 0){ if(next == 0){
ilock(ip, 0);
if(ip->type == 0) if(ip->type == 0)
panic("namex"); panic("namex");
if(ip->type != T_DIR){ if(ip->type != T_DIR){
iunlockput(ip); iput(ip);
rcu_end_read();
return 0; return 0;
} }
if(nameiparent && *path == '\0'){ if(nameiparent && *path == '\0'){
// Stop one level early. // Stop one level early.
iunlock(ip); rcu_end_read();
return ip; return ip;
} }
if((next = dirlookup(ip, name, 0)) == 0){ if((next = dirlookup(ip, name)) == 0){
iunlockput(ip); iput(ip);
rcu_end_read();
return 0; return 0;
} }
nc_insert(ip, name, next); nc_insert(ip, name, next);
iunlockput(ip); iput(ip);
} }
ip = next; ip = next;
} }
if(nameiparent){ if(nameiparent){
iput(ip); iput(ip);
rcu_end_read();
return 0; return 0;
} }
rcu_end_read();
return ip; return ip;
} }
...@@ -692,7 +698,9 @@ struct inode* ...@@ -692,7 +698,9 @@ struct inode*
namei(char *path) namei(char *path)
{ {
char name[DIRSIZ]; char name[DIRSIZ];
return namex(path, 0, name); struct inode *r = namex(path, 0, name);
//cprintf("namei: %s -> %x (%d)\n", path, r, r?r->inum:0);
return r;
} }
struct inode* struct inode*
......
...@@ -62,6 +62,20 @@ nsalloc(int allowdup) ...@@ -62,6 +62,20 @@ nsalloc(int allowdup)
return ns; return ns;
} }
static void *
any(void *x, void *y)
{
return (void*) 1;
}
void
nsfree(struct ns *ns)
{
if (ns_enumerate(ns, &any))
panic("nsfree: not empty");
rcu_delayed(ns, kmfree);
}
static struct elem * static struct elem *
elemalloc(struct nskey *k) elemalloc(struct nskey *k)
{ {
...@@ -212,7 +226,7 @@ ns_lookup(struct ns *ns, struct nskey key) ...@@ -212,7 +226,7 @@ ns_lookup(struct ns *ns, struct nskey key)
return 0; return 0;
} }
int void*
ns_remove(struct ns *ns, struct nskey key, void *v) ns_remove(struct ns *ns, struct nskey key, void *v)
{ {
uint i = h(&key); uint i = h(&key);
...@@ -244,16 +258,17 @@ ns_remove(struct ns *ns, struct nskey key, void *v) ...@@ -244,16 +258,17 @@ ns_remove(struct ns *ns, struct nskey key, void *v)
} }
*pelock = 0; *pelock = 0;
void *v = e->val;
rcu_end_write(0); rcu_end_write(0);
rcu_delayed(e, kmfree); rcu_delayed(e, kmfree);
return 0; return v;
} }
pe = &e->next; pe = &e->next;
} }
rcu_end_write(0); rcu_end_write(0);
return -1; return 0;
} }
void * void *
......
...@@ -68,7 +68,7 @@ allocproc(void) ...@@ -68,7 +68,7 @@ allocproc(void)
// Allocate kernel stack if possible. // Allocate kernel stack if possible.
if((p->kstack = kalloc()) == 0){ if((p->kstack = kalloc()) == 0){
if (ns_remove(nspid, KI(p->pid), p) < 0) if (ns_remove(nspid, KI(p->pid), p) == 0)
panic("allocproc: ns_remove"); panic("allocproc: ns_remove");
rcu_delayed(p, kmfree); rcu_delayed(p, kmfree);
return 0; return 0;
...@@ -123,7 +123,7 @@ delrun(struct proc *p) ...@@ -123,7 +123,7 @@ delrun(struct proc *p)
if (p->on_runq < 0) if (p->on_runq < 0)
panic("delrun not on runq"); panic("delrun not on runq");
if (ns_remove(nsrunq, KI(p->on_runq), p) < 0) if (ns_remove(nsrunq, KI(p->on_runq), p) == 0)
panic("delrun: ns_remove"); panic("delrun: ns_remove");
p->on_runq = -1; p->on_runq = -1;
} }
...@@ -269,7 +269,7 @@ fork(int flags) ...@@ -269,7 +269,7 @@ fork(int flags)
kfree(np->kstack); kfree(np->kstack);
np->kstack = 0; np->kstack = 0;
np->state = UNUSED; np->state = UNUSED;
if (ns_remove(nspid, KI(np->pid), np) < 0) if (ns_remove(nspid, KI(np->pid), np) == 0)
panic("fork: ns_remove"); panic("fork: ns_remove");
rcu_delayed(np, kmfree); rcu_delayed(np, kmfree);
return -1; return -1;
...@@ -384,7 +384,7 @@ wait(void) ...@@ -384,7 +384,7 @@ wait(void)
p->kstack = 0; p->kstack = 0;
vmap_decref(p->vmap); vmap_decref(p->vmap);
p->state = UNUSED; p->state = UNUSED;
if (ns_remove(nspid, KI(p->pid), p) < 0) if (ns_remove(nspid, KI(p->pid), p) == 0)
panic("wait: ns_remove"); panic("wait: ns_remove");
p->pid = 0; p->pid = 0;
p->parent = 0; p->parent = 0;
......
...@@ -130,14 +130,10 @@ sys_link(void) ...@@ -130,14 +130,10 @@ sys_link(void)
if((dp = nameiparent(new, name)) == 0) if((dp = nameiparent(new, name)) == 0)
goto bad; goto bad;
ilock(dp, 1); if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0)
if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){
iunlockput(dp);
goto bad; goto bad;
}
nc_insert(dp, name, ip); nc_insert(dp, name, ip);
iunlockput(dp);
iput(ip); iput(ip);
return 0; return 0;
...@@ -150,18 +146,21 @@ bad: ...@@ -150,18 +146,21 @@ bad:
} }
// Is the directory dp empty except for "." and ".." ? // Is the directory dp empty except for "." and ".." ?
static void*
check_empty(void *k, void *v)
{
char *name = k;
if (strcmp(name, ".") && strcmp(name, ".."))
return (void*)1;
return 0;
}
static int static int
isdirempty(struct inode *dp) isdirempty(struct inode *dp)
{ {
int off; dir_init(dp);
struct dirent de; if (ns_enumerate(dp->dir, check_empty))
return 0;
for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){
if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
panic("isdirempty: readi");
if(de.inum != 0)
return 0;
}
return 1; return 1;
} }
...@@ -170,26 +169,24 @@ int ...@@ -170,26 +169,24 @@ int
sys_unlink(void) sys_unlink(void)
{ {
struct inode *ip, *dp; struct inode *ip, *dp;
struct dirent de; char name[DIRSIZ+1], *path;
char name[DIRSIZ], *path;
uint off;
if(argstr(0, &path) < 0) if(argstr(0, &path) < 0)
return -1; return -1;
if((dp = nameiparent(path, name)) == 0) if((dp = nameiparent(path, name)) == 0)
return -1; return -1;
ilock(dp, 1);
if(dp->type != T_DIR) if(dp->type != T_DIR)
panic("sys_unlink"); panic("sys_unlink");
// Cannot unlink "." or "..". // Cannot unlink "." or "..".
if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0){ if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0){
iunlockput(dp); iput(dp);
return -1; return -1;
} }
if((ip = dirlookup(dp, name, &off)) == 0){ retry:
iunlockput(dp); if((ip = dirlookup(dp, name)) == 0){
iput(dp);
return -1; return -1;
} }
ilock(ip, 1); ilock(ip, 1);
...@@ -198,20 +195,26 @@ sys_unlink(void) ...@@ -198,20 +195,26 @@ sys_unlink(void)
panic("unlink: nlink < 1"); panic("unlink: nlink < 1");
if(ip->type == T_DIR && !isdirempty(ip)){ if(ip->type == T_DIR && !isdirempty(ip)){
iunlockput(ip); iunlockput(ip);
iunlockput(dp); iput(dp);
return -1; return -1;
} }
memset(&de, 0, sizeof(de)); dir_init(dp);
if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) name[DIRSIZ] = '\0';
panic("unlink: writei"); if (ns_remove(dp->dir, KS(name), (void*)ip->inum) == 0) {
iunlockput(ip);
goto retry;
}
if(ip->type == T_DIR){ if(ip->type == T_DIR){
ilock(dp, 1);
dp->nlink--; dp->nlink--;
iupdate(dp); iupdate(dp);
iunlock(dp);
} }
nc_invalidate(dp, name); nc_invalidate(dp, name);
iunlockput(dp); iput(dp);
ip->nlink--; ip->nlink--;
iupdate(ip); iupdate(ip);
...@@ -222,18 +225,16 @@ sys_unlink(void) ...@@ -222,18 +225,16 @@ sys_unlink(void)
static struct inode* static struct inode*
create(char *path, short type, short major, short minor) create(char *path, short type, short major, short minor)
{ {
uint off;
struct inode *ip, *dp; struct inode *ip, *dp;
char name[DIRSIZ]; char name[DIRSIZ];
if((dp = nameiparent(path, name)) == 0) if((dp = nameiparent(path, name)) == 0)
return 0; return 0;
ilock(dp, 1);
if(dp->type != T_DIR) if(dp->type != T_DIR)
panic("create"); panic("create");
if((ip = dirlookup(dp, name, &off)) != 0){ if((ip = dirlookup(dp, name)) != 0){
iunlockput(dp); iput(dp);
ilock(ip, 1); ilock(ip, 1);
if(type == T_FILE && ip->type == T_FILE) if(type == T_FILE && ip->type == T_FILE)
return ip; return ip;
...@@ -261,7 +262,7 @@ create(char *path, short type, short major, short minor) ...@@ -261,7 +262,7 @@ create(char *path, short type, short major, short minor)
panic("create: dirlink"); panic("create: dirlink");
nc_insert(dp, name, ip); nc_insert(dp, name, ip);
iunlockput(dp); iput(dp);
return ip; return ip;
} }
......
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论