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