提交 9f969fb4 创建 作者: Nickolai Zeldovich's avatar Nickolai Zeldovich

read-write lock for inodes

上级 107ec052
......@@ -297,7 +297,7 @@ consoleread(struct inode *ip, char *dst, int n)
while(input.r == input.w){
if(proc->killed){
release(&input.lock);
ilock(ip);
ilock(ip, 1);
return -1;
}
cv_sleep(&input.cv, &input.lock);
......@@ -317,7 +317,7 @@ consoleread(struct inode *ip, char *dst, int n)
break;
}
release(&input.lock);
ilock(ip);
ilock(ip, 1);
return target - n;
}
......@@ -332,7 +332,7 @@ consolewrite(struct inode *ip, char *buf, int n)
for(i = 0; i < n; i++)
consputc(buf[i] & 0xff);
release(&cons.lock);
ilock(ip);
ilock(ip, 1);
return n;
}
......
......@@ -50,7 +50,7 @@ struct inode* ialloc(uint, short);
struct inode* iget(uint dev, uint inum);
struct inode* idup(struct inode*);
void iinit(void);
void ilock(struct inode*);
void ilock(struct inode*, int writer);
void iput(struct inode*);
void iunlock(struct inode*);
void iunlockput(struct inode*);
......
......@@ -28,7 +28,7 @@ exec(char *path, char **argv)
if((ip = namei(path)) == 0)
return -1;
ilock(ip);
ilock(ip, 0);
// Check ELF header
if(ip->type != T_FILE)
......
......@@ -51,7 +51,7 @@ int
filestat(struct file *f, struct stat *st)
{
if(f->type == FD_INODE){
ilock(f->ip);
ilock(f->ip, 0);
if(f->ip->type == 0)
panic("filestat");
stati(f->ip, st);
......@@ -72,7 +72,7 @@ fileread(struct file *f, char *addr, int n)
if(f->type == FD_PIPE)
return piperead(f->pipe, addr, n);
if(f->type == FD_INODE){
ilock(f->ip);
ilock(f->ip, 0);
if(f->ip->type == 0)
panic("fileread");
if((r = readi(f->ip, addr, f->off, n)) > 0)
......@@ -94,7 +94,7 @@ filewrite(struct file *f, char *addr, int n)
if(f->type == FD_PIPE)
return pipewrite(f->pipe, addr, n);
if(f->type == FD_INODE){
ilock(f->ip);
ilock(f->ip, 1);
if(f->ip->type == 0 || f->ip->type == T_DIR)
panic("filewrite but 0 or T_DIR");
if((r = writei(f->ip, addr, f->off, n)) > 0)
......
......@@ -17,6 +17,7 @@ struct inode {
uint gen; // Generation number
int ref; // Reference count
int flags; // I_BUSY, I_VALID
int readbusy;
struct condvar cv;
struct spinlock lock;
char lockname[16];
......@@ -29,9 +30,10 @@ struct inode {
uint addrs[NDIRECT+1];
};
#define I_BUSY 0x1
#define I_VALID 0x2
#define I_FREE 0x4
#define I_BUSYR 0x1
#define I_BUSYW 0x2
#define I_VALID 0x4
#define I_FREE 0x8
// device implementations
......
......@@ -168,7 +168,7 @@ ialloc(uint dev, short type)
// maybe this inode is free. look at it via the
// inode cache to make sure.
struct inode *ip = iget(dev, inum);
ilock(ip);
ilock(ip, 1);
if(ip->type == 0){
ip->type = type;
ip->gen += 1;
......@@ -258,7 +258,8 @@ iget(uint dev, uint inum)
ip->dev = dev;
ip->inum = inum;
ip->ref = 1;
ip->flags = I_BUSY;
ip->flags = I_BUSYR | I_BUSYW;
ip->readbusy = 1;
snprintf(ip->lockname, sizeof(ip->lockname), "cv:ino:%d", ip->inum);
initlock(&ip->lock, ip->lockname+3);
initcondvar(&ip->cv, ip->lockname);
......@@ -298,15 +299,16 @@ idup(struct inode *ip)
// why doesn't the iget() that allocated the inode cache entry
// read the inode from disk?
void
ilock(struct inode *ip)
ilock(struct inode *ip, int writer)
{
if(ip == 0 || ip->ref < 1)
panic("ilock");
acquire(&ip->lock);
while(ip->flags & I_BUSY)
while(ip->flags & (I_BUSYW | (writer ? I_BUSYR : 0)))
cv_sleep(&ip->cv, &ip->lock);
ip->flags |= I_BUSY;
ip->flags |= I_BUSYR | (writer ? I_BUSYW : 0);
__sync_fetch_and_add(&ip->readbusy, 1);
release(&ip->lock);
if((ip->flags & I_VALID) == 0)
......@@ -317,11 +319,12 @@ ilock(struct inode *ip)
void
iunlock(struct inode *ip)
{
if(ip == 0 || !(ip->flags & I_BUSY) || ip->ref < 1)
if(ip == 0 || !(ip->flags & (I_BUSYR | I_BUSYW)) || ip->ref < 1)
panic("iunlock");
acquire(&ip->lock);
ip->flags &= ~I_BUSY;
int lastreader = __sync_sub_and_fetch(&ip->readbusy, 1);
ip->flags &= ~(I_BUSYW | ((lastreader==0) ? I_BUSYR : 0));
cv_wakeup(&ip->cv);
release(&ip->lock);
}
......@@ -334,11 +337,12 @@ iput(struct inode *ip)
acquire(&ip->lock);
if (ip->ref == 0 && ip->nlink == 0) {
// inode is no longer used: truncate and free inode.
if(ip->flags & I_BUSY)
if(ip->flags & (I_BUSYR | I_BUSYW))
panic("iput busy");
if((ip->flags & I_VALID) == 0)
panic("iput not valid");
ip->flags |= I_BUSY;
ip->flags |= I_BUSYR | I_BUSYW;
__sync_fetch_and_add(&ip->readbusy, 1);
release(&ip->lock);
itrunc(ip);
ip->type = 0;
......@@ -347,7 +351,8 @@ iput(struct inode *ip)
ip->gen += 1;
iupdate(ip);
acquire(&ip->lock);
ip->flags &= ~I_BUSY;
ip->flags &= ~(I_BUSYR | I_BUSYW);
__sync_sub_and_fetch(&ip->readbusy, 1);
cv_wakeup(&ip->cv);
}
release(&ip->lock);
......@@ -639,7 +644,7 @@ namex(char *path, int nameiparent, char *name)
if(nameiparent == 0)
next = nc_lookup(ip, name);
if(next == 0){
ilock(ip);
ilock(ip, 0);
if(ip->type == 0)
panic("namex");
if(ip->type != T_DIR){
......
......@@ -119,7 +119,7 @@ sys_link(void)
return -1;
if((ip = namei(old)) == 0)
return -1;
ilock(ip);
ilock(ip, 1);
if(ip->type == T_DIR){
iunlockput(ip);
return -1;
......@@ -130,7 +130,7 @@ sys_link(void)
if((dp = nameiparent(new, name)) == 0)
goto bad;
ilock(dp);
ilock(dp, 1);
if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){
iunlockput(dp);
goto bad;
......@@ -140,7 +140,7 @@ sys_link(void)
return 0;
bad:
ilock(ip);
ilock(ip, 1);
ip->nlink--;
iupdate(ip);
iunlockput(ip);
......@@ -176,7 +176,7 @@ sys_unlink(void)
return -1;
if((dp = nameiparent(path, name)) == 0)
return -1;
ilock(dp);
ilock(dp, 1);
if(dp->type != T_DIR)
panic("sys_unlink");
......@@ -190,7 +190,7 @@ sys_unlink(void)
iunlockput(dp);
return -1;
}
ilock(ip);
ilock(ip, 1);
if(ip->nlink < 1)
panic("unlink: nlink < 1");
......@@ -226,13 +226,13 @@ create(char *path, short type, short major, short minor)
if((dp = nameiparent(path, name)) == 0)
return 0;
ilock(dp);
ilock(dp, 1);
if(dp->type != T_DIR)
panic("create");
if((ip = dirlookup(dp, name, &off)) != 0){
iunlockput(dp);
ilock(ip);
ilock(ip, 1);
if(type == T_FILE && ip->type == T_FILE)
return ip;
iunlockput(ip);
......@@ -278,7 +278,7 @@ sys_open(void)
} else {
if((ip = namei(path)) == 0)
return -1;
ilock(ip);
ilock(ip, 0);
if(ip->type == 0)
panic("open");
if(ip->type == T_DIR && omode != O_RDONLY){
......@@ -340,7 +340,7 @@ sys_chdir(void)
if(argstr(0, &path) < 0 || (ip = namei(path)) == 0)
return -1;
ilock(ip);
ilock(ip, 0);
if(ip->type != T_DIR){
iunlockput(ip);
return -1;
......
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论