avoid deadlock by calling begin_trans() before locking any inodes
This commit is contained in:
parent
c95ce31c59
commit
5053dd6a6d
5 changed files with 66 additions and 15 deletions
6
file.c
6
file.c
|
@ -118,7 +118,6 @@ 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);
|
|
||||||
// write a few blocks at a time to avoid exceeding
|
// write a few blocks at a time to avoid exceeding
|
||||||
// the maximum log transaction size, including
|
// the maximum log transaction size, including
|
||||||
// i-node, indirect block, allocation blocks,
|
// i-node, indirect block, allocation blocks,
|
||||||
|
@ -131,9 +130,13 @@ filewrite(struct file *f, char *addr, int n)
|
||||||
int n1 = n - i;
|
int n1 = n - i;
|
||||||
if(n1 > max)
|
if(n1 > max)
|
||||||
n1 = max;
|
n1 = max;
|
||||||
|
|
||||||
begin_trans();
|
begin_trans();
|
||||||
|
ilock(f->ip);
|
||||||
r = writei(f->ip, addr + i, f->off, n1);
|
r = writei(f->ip, addr + i, f->off, n1);
|
||||||
|
iunlock(f->ip);
|
||||||
commit_trans();
|
commit_trans();
|
||||||
|
|
||||||
if(r < 0)
|
if(r < 0)
|
||||||
break;
|
break;
|
||||||
if(r != n1)
|
if(r != n1)
|
||||||
|
@ -141,7 +144,6 @@ filewrite(struct file *f, char *addr, int n)
|
||||||
f->off += r;
|
f->off += r;
|
||||||
i += r;
|
i += r;
|
||||||
}
|
}
|
||||||
iunlock(f->ip);
|
|
||||||
return i == n ? n : -1;
|
return i == n ? n : -1;
|
||||||
}
|
}
|
||||||
panic("filewrite");
|
panic("filewrite");
|
||||||
|
|
7
fs.c
7
fs.c
|
@ -43,13 +43,13 @@ bzero(int dev, int bno)
|
||||||
|
|
||||||
bp = bread(dev, bno);
|
bp = bread(dev, bno);
|
||||||
memset(bp->data, 0, BSIZE);
|
memset(bp->data, 0, BSIZE);
|
||||||
bwrite(bp);
|
log_write(bp);
|
||||||
brelse(bp);
|
brelse(bp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blocks.
|
// Blocks.
|
||||||
|
|
||||||
// Allocate a disk block.
|
// Allocate a zeroed disk block.
|
||||||
static uint
|
static uint
|
||||||
balloc(uint dev)
|
balloc(uint dev)
|
||||||
{
|
{
|
||||||
|
@ -67,6 +67,7 @@ balloc(uint dev)
|
||||||
bp->data[bi/8] |= m; // Mark block in use on disk.
|
bp->data[bi/8] |= m; // Mark block in use on disk.
|
||||||
log_write(bp);
|
log_write(bp);
|
||||||
brelse(bp);
|
brelse(bp);
|
||||||
|
bzero(dev, b + bi);
|
||||||
return b + bi;
|
return b + bi;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,8 +84,6 @@ bfree(int dev, uint b)
|
||||||
struct superblock sb;
|
struct superblock sb;
|
||||||
int bi, m;
|
int bi, m;
|
||||||
|
|
||||||
bzero(dev, b);
|
|
||||||
|
|
||||||
readsb(dev, &sb);
|
readsb(dev, &sb);
|
||||||
bp = bread(dev, BBLOCK(b, sb.ninodes));
|
bp = bread(dev, BBLOCK(b, sb.ninodes));
|
||||||
bi = b % BPB;
|
bi = b % BPB;
|
||||||
|
|
4
log.c
4
log.c
|
@ -124,9 +124,9 @@ static void
|
||||||
recover_from_log(void)
|
recover_from_log(void)
|
||||||
{
|
{
|
||||||
read_head();
|
read_head();
|
||||||
install_trans(); // Install all transactions till head
|
install_trans(); // if committed, copy from log to disk
|
||||||
log.lh.n = 0;
|
log.lh.n = 0;
|
||||||
write_head(); // Reclaim log
|
write_head(); // clear the log
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
14
sysfile.c
14
sysfile.c
|
@ -116,14 +116,16 @@ sys_link(void)
|
||||||
return -1;
|
return -1;
|
||||||
if((ip = namei(old)) == 0)
|
if((ip = namei(old)) == 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
begin_trans();
|
||||||
|
|
||||||
ilock(ip);
|
ilock(ip);
|
||||||
if(ip->type == T_DIR){
|
if(ip->type == T_DIR){
|
||||||
iunlockput(ip);
|
iunlockput(ip);
|
||||||
|
commit_trans();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
begin_trans();
|
|
||||||
|
|
||||||
ip->nlink++;
|
ip->nlink++;
|
||||||
iupdate(ip);
|
iupdate(ip);
|
||||||
iunlock(ip);
|
iunlock(ip);
|
||||||
|
@ -180,16 +182,21 @@ sys_unlink(void)
|
||||||
return -1;
|
return -1;
|
||||||
if((dp = nameiparent(path, name)) == 0)
|
if((dp = nameiparent(path, name)) == 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
begin_trans();
|
||||||
|
|
||||||
ilock(dp);
|
ilock(dp);
|
||||||
|
|
||||||
// Cannot unlink "." or "..".
|
// Cannot unlink "." or "..".
|
||||||
if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0){
|
if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0){
|
||||||
iunlockput(dp);
|
iunlockput(dp);
|
||||||
|
commit_trans();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((ip = dirlookup(dp, name, &off)) == 0){
|
if((ip = dirlookup(dp, name, &off)) == 0){
|
||||||
iunlockput(dp);
|
iunlockput(dp);
|
||||||
|
commit_trans();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
ilock(ip);
|
ilock(ip);
|
||||||
|
@ -199,11 +206,10 @@ sys_unlink(void)
|
||||||
if(ip->type == T_DIR && !isdirempty(ip)){
|
if(ip->type == T_DIR && !isdirempty(ip)){
|
||||||
iunlockput(ip);
|
iunlockput(ip);
|
||||||
iunlockput(dp);
|
iunlockput(dp);
|
||||||
|
commit_trans();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
begin_trans();
|
|
||||||
|
|
||||||
memset(&de, 0, sizeof(de));
|
memset(&de, 0, sizeof(de));
|
||||||
if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
|
if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
|
||||||
panic("unlink: writei");
|
panic("unlink: writei");
|
||||||
|
|
50
usertests.c
50
usertests.c
|
@ -364,6 +364,8 @@ sharedfd(void)
|
||||||
int fd, pid, i, n, nc, np;
|
int fd, pid, i, n, nc, np;
|
||||||
char buf[10];
|
char buf[10];
|
||||||
|
|
||||||
|
printf(1, "sharedfd test\n");
|
||||||
|
|
||||||
unlink("sharedfd");
|
unlink("sharedfd");
|
||||||
fd = open("sharedfd", O_CREATE|O_RDWR);
|
fd = open("sharedfd", O_CREATE|O_RDWR);
|
||||||
if(fd < 0){
|
if(fd < 0){
|
||||||
|
@ -655,7 +657,7 @@ linktest(void)
|
||||||
printf(1, "linktest ok\n");
|
printf(1, "linktest ok\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// test concurrent create and unlink of the same file
|
// test concurrent create/link/unlink of the same file
|
||||||
void
|
void
|
||||||
concreate(void)
|
concreate(void)
|
||||||
{
|
{
|
||||||
|
@ -728,10 +730,15 @@ concreate(void)
|
||||||
}
|
}
|
||||||
if(((i % 3) == 0 && pid == 0) ||
|
if(((i % 3) == 0 && pid == 0) ||
|
||||||
((i % 3) == 1 && pid != 0)){
|
((i % 3) == 1 && pid != 0)){
|
||||||
fd = open(file, 0);
|
close(open(file, 0));
|
||||||
close(fd);
|
close(open(file, 0));
|
||||||
|
close(open(file, 0));
|
||||||
|
close(open(file, 0));
|
||||||
} else {
|
} else {
|
||||||
unlink(file);
|
unlink(file);
|
||||||
|
unlink(file);
|
||||||
|
unlink(file);
|
||||||
|
unlink(file);
|
||||||
}
|
}
|
||||||
if(pid == 0)
|
if(pid == 0)
|
||||||
exit();
|
exit();
|
||||||
|
@ -742,6 +749,42 @@ concreate(void)
|
||||||
printf(1, "concreate ok\n");
|
printf(1, "concreate ok\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// another concurrent link/unlink/create test,
|
||||||
|
// to look for deadlocks.
|
||||||
|
void
|
||||||
|
linkunlink()
|
||||||
|
{
|
||||||
|
int pid, i;
|
||||||
|
|
||||||
|
printf(1, "linkunlink test\n");
|
||||||
|
|
||||||
|
unlink("x");
|
||||||
|
pid = fork();
|
||||||
|
if(pid < 0){
|
||||||
|
printf(1, "fork failed\n");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int x = (pid ? 1 : 97);
|
||||||
|
for(i = 0; i < 100; i++){
|
||||||
|
x = x * 1103515245 + 12345;
|
||||||
|
if((x % 3) == 0){
|
||||||
|
close(open("x", O_RDWR | O_CREATE));
|
||||||
|
} else if((x % 3) == 1){
|
||||||
|
link("cat", "x");
|
||||||
|
} else {
|
||||||
|
unlink("x");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pid)
|
||||||
|
wait();
|
||||||
|
else
|
||||||
|
exit();
|
||||||
|
|
||||||
|
printf(1, "linkunlink ok\n");
|
||||||
|
}
|
||||||
|
|
||||||
// directory that uses indirect blocks
|
// directory that uses indirect blocks
|
||||||
void
|
void
|
||||||
bigdir(void)
|
bigdir(void)
|
||||||
|
@ -1518,6 +1561,7 @@ main(int argc, char *argv[])
|
||||||
bigfile();
|
bigfile();
|
||||||
subdir();
|
subdir();
|
||||||
concreate();
|
concreate();
|
||||||
|
linkunlink();
|
||||||
linktest();
|
linktest();
|
||||||
unlinkread();
|
unlinkread();
|
||||||
createdelete();
|
createdelete();
|
||||||
|
|
Loading…
Reference in a new issue