every iput() and namei() must be inside a transaction
This commit is contained in:
parent
020c8e2384
commit
2c56547272
6 changed files with 145 additions and 17 deletions
10
exec.c
10
exec.c
|
@ -18,8 +18,11 @@ exec(char *path, char **argv)
|
||||||
struct proghdr ph;
|
struct proghdr ph;
|
||||||
pde_t *pgdir, *oldpgdir;
|
pde_t *pgdir, *oldpgdir;
|
||||||
|
|
||||||
if((ip = namei(path)) == 0)
|
begin_trans();
|
||||||
|
if((ip = namei(path)) == 0){
|
||||||
|
commit_trans();
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
ilock(ip);
|
ilock(ip);
|
||||||
pgdir = 0;
|
pgdir = 0;
|
||||||
|
|
||||||
|
@ -47,6 +50,7 @@ exec(char *path, char **argv)
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
iunlockput(ip);
|
iunlockput(ip);
|
||||||
|
commit_trans();
|
||||||
ip = 0;
|
ip = 0;
|
||||||
|
|
||||||
// Allocate two pages at the next page boundary.
|
// Allocate two pages at the next page boundary.
|
||||||
|
@ -95,7 +99,9 @@ exec(char *path, char **argv)
|
||||||
bad:
|
bad:
|
||||||
if(pgdir)
|
if(pgdir)
|
||||||
freevm(pgdir);
|
freevm(pgdir);
|
||||||
if(ip)
|
if(ip){
|
||||||
iunlockput(ip);
|
iunlockput(ip);
|
||||||
|
commit_trans();
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
3
fs.c
3
fs.c
|
@ -314,6 +314,8 @@ iunlock(struct inode *ip)
|
||||||
// be recycled.
|
// be recycled.
|
||||||
// If that was the last reference and the inode has no links
|
// If that was the last reference and the inode has no links
|
||||||
// to it, free the inode (and its content) on disk.
|
// to it, free the inode (and its content) on disk.
|
||||||
|
// All calls to iput() must be inside a transaction in
|
||||||
|
// case it has to free the inode.
|
||||||
void
|
void
|
||||||
iput(struct inode *ip)
|
iput(struct inode *ip)
|
||||||
{
|
{
|
||||||
|
@ -601,6 +603,7 @@ skipelem(char *path, char *name)
|
||||||
// Look up and return the inode for a path name.
|
// Look up and return the inode for a path name.
|
||||||
// If parent != 0, return the inode for the parent and copy the final
|
// If parent != 0, return the inode for the parent and copy the final
|
||||||
// path element into name, which must have room for DIRSIZ bytes.
|
// path element into name, which must have room for DIRSIZ bytes.
|
||||||
|
// Must be called inside a transaction since it calls iput().
|
||||||
static struct inode*
|
static struct inode*
|
||||||
namex(char *path, int nameiparent, char *name)
|
namex(char *path, int nameiparent, char *name)
|
||||||
{
|
{
|
||||||
|
|
6
log.c
6
log.c
|
@ -5,7 +5,7 @@
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "buf.h"
|
#include "buf.h"
|
||||||
|
|
||||||
// Simple logging. Each system call that might write the file system
|
// Simple logging. Each file system system call
|
||||||
// should be surrounded with begin_trans() and commit_trans() calls.
|
// should be surrounded with begin_trans() and commit_trans() calls.
|
||||||
//
|
//
|
||||||
// The log holds at most one transaction at a time. Commit forces
|
// The log holds at most one transaction at a time. Commit forces
|
||||||
|
@ -18,10 +18,6 @@
|
||||||
// one transaction reading a block that another one has modified,
|
// one transaction reading a block that another one has modified,
|
||||||
// for example an i-node block.
|
// for example an i-node block.
|
||||||
//
|
//
|
||||||
// Read-only system calls don't need to use transactions, though
|
|
||||||
// this means that they may observe uncommitted data. I-node and
|
|
||||||
// buffer locks prevent read-only calls from seeing inconsistent data.
|
|
||||||
//
|
|
||||||
// The log is a physical re-do log containing disk blocks.
|
// The log is a physical re-do log containing disk blocks.
|
||||||
// The on-disk log format:
|
// The on-disk log format:
|
||||||
// header block, containing sector #s for block A, B, C, ...
|
// header block, containing sector #s for block A, B, C, ...
|
||||||
|
|
2
proc.c
2
proc.c
|
@ -186,7 +186,9 @@ exit(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
begin_trans();
|
||||||
iput(proc->cwd);
|
iput(proc->cwd);
|
||||||
|
commit_trans();
|
||||||
proc->cwd = 0;
|
proc->cwd = 0;
|
||||||
|
|
||||||
acquire(&ptable.lock);
|
acquire(&ptable.lock);
|
||||||
|
|
35
sysfile.c
35
sysfile.c
|
@ -120,10 +120,12 @@ sys_link(void)
|
||||||
|
|
||||||
if(argstr(0, &old) < 0 || argstr(1, &new) < 0)
|
if(argstr(0, &old) < 0 || argstr(1, &new) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if((ip = namei(old)) == 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
begin_trans();
|
begin_trans();
|
||||||
|
if((ip = namei(old)) == 0){
|
||||||
|
commit_trans();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
ilock(ip);
|
ilock(ip);
|
||||||
if(ip->type == T_DIR){
|
if(ip->type == T_DIR){
|
||||||
|
@ -186,10 +188,12 @@ sys_unlink(void)
|
||||||
|
|
||||||
if(argstr(0, &path) < 0)
|
if(argstr(0, &path) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if((dp = nameiparent(path, name)) == 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
begin_trans();
|
begin_trans();
|
||||||
|
if((dp = nameiparent(path, name)) == 0){
|
||||||
|
commit_trans();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
ilock(dp);
|
ilock(dp);
|
||||||
|
|
||||||
|
@ -286,18 +290,24 @@ sys_open(void)
|
||||||
|
|
||||||
if(argstr(0, &path) < 0 || argint(1, &omode) < 0)
|
if(argstr(0, &path) < 0 || argint(1, &omode) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
begin_trans();
|
||||||
|
|
||||||
if(omode & O_CREATE){
|
if(omode & O_CREATE){
|
||||||
begin_trans();
|
|
||||||
ip = create(path, T_FILE, 0, 0);
|
ip = create(path, T_FILE, 0, 0);
|
||||||
commit_trans();
|
if(ip == 0){
|
||||||
if(ip == 0)
|
commit_trans();
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if((ip = namei(path)) == 0)
|
if((ip = namei(path)) == 0){
|
||||||
|
commit_trans();
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
ilock(ip);
|
ilock(ip);
|
||||||
if(ip->type == T_DIR && omode != O_RDONLY){
|
if(ip->type == T_DIR && omode != O_RDONLY){
|
||||||
iunlockput(ip);
|
iunlockput(ip);
|
||||||
|
commit_trans();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -306,9 +316,11 @@ sys_open(void)
|
||||||
if(f)
|
if(f)
|
||||||
fileclose(f);
|
fileclose(f);
|
||||||
iunlockput(ip);
|
iunlockput(ip);
|
||||||
|
commit_trans();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
iunlock(ip);
|
iunlock(ip);
|
||||||
|
commit_trans();
|
||||||
|
|
||||||
f->type = FD_INODE;
|
f->type = FD_INODE;
|
||||||
f->ip = ip;
|
f->ip = ip;
|
||||||
|
@ -361,15 +373,20 @@ sys_chdir(void)
|
||||||
char *path;
|
char *path;
|
||||||
struct inode *ip;
|
struct inode *ip;
|
||||||
|
|
||||||
if(argstr(0, &path) < 0 || (ip = namei(path)) == 0)
|
begin_trans();
|
||||||
|
if(argstr(0, &path) < 0 || (ip = namei(path)) == 0){
|
||||||
|
commit_trans();
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
ilock(ip);
|
ilock(ip);
|
||||||
if(ip->type != T_DIR){
|
if(ip->type != T_DIR){
|
||||||
iunlockput(ip);
|
iunlockput(ip);
|
||||||
|
commit_trans();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
iunlock(ip);
|
iunlock(ip);
|
||||||
iput(proc->cwd);
|
iput(proc->cwd);
|
||||||
|
commit_trans();
|
||||||
proc->cwd = ip;
|
proc->cwd = ip;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
106
usertests.c
106
usertests.c
|
@ -13,6 +13,106 @@ char name[3];
|
||||||
char *echoargv[] = { "echo", "ALL", "TESTS", "PASSED", 0 };
|
char *echoargv[] = { "echo", "ALL", "TESTS", "PASSED", 0 };
|
||||||
int stdout = 1;
|
int stdout = 1;
|
||||||
|
|
||||||
|
// does chdir() call iput(p->cwd) in a transaction?
|
||||||
|
void
|
||||||
|
iputtest(void)
|
||||||
|
{
|
||||||
|
printf(stdout, "iput test\n");
|
||||||
|
|
||||||
|
if(mkdir("iputdir") < 0){
|
||||||
|
printf(stdout, "mkdir failed\n");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
if(chdir("iputdir") < 0){
|
||||||
|
printf(stdout, "chdir iputdir failed\n");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
if(unlink("../iputdir") < 0){
|
||||||
|
printf(stdout, "unlink ../iputdir failed\n");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
if(chdir("/") < 0){
|
||||||
|
printf(stdout, "chdir / failed\n");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
printf(stdout, "iput test ok\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// does exit() call iput(p->cwd) in a transaction?
|
||||||
|
void
|
||||||
|
exitiputtest(void)
|
||||||
|
{
|
||||||
|
int pid;
|
||||||
|
|
||||||
|
printf(stdout, "exitiput test\n");
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
|
if(pid < 0){
|
||||||
|
printf(stdout, "fork failed\n");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
if(pid == 0){
|
||||||
|
if(mkdir("iputdir") < 0){
|
||||||
|
printf(stdout, "mkdir failed\n");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
if(chdir("iputdir") < 0){
|
||||||
|
printf(stdout, "child chdir failed\n");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
if(unlink("../iputdir") < 0){
|
||||||
|
printf(stdout, "unlink ../iputdir failed\n");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
wait();
|
||||||
|
printf(stdout, "exitiput test ok\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// does the error path in open() for attempt to write a
|
||||||
|
// directory call iput() in a transaction?
|
||||||
|
// needs a hacked kernel that pauses just after the namei()
|
||||||
|
// call in sys_open():
|
||||||
|
// if((ip = namei(path)) == 0)
|
||||||
|
// return -1;
|
||||||
|
// {
|
||||||
|
// int i;
|
||||||
|
// for(i = 0; i < 10000; i++)
|
||||||
|
// yield();
|
||||||
|
// }
|
||||||
|
void
|
||||||
|
openiputtest(void)
|
||||||
|
{
|
||||||
|
int pid;
|
||||||
|
|
||||||
|
printf(stdout, "openiput test\n");
|
||||||
|
if(mkdir("oidir") < 0){
|
||||||
|
printf(stdout, "mkdir oidir failed\n");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
pid = fork();
|
||||||
|
if(pid < 0){
|
||||||
|
printf(stdout, "fork failed\n");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
if(pid == 0){
|
||||||
|
int fd = open("oidir", O_RDWR);
|
||||||
|
if(fd >= 0){
|
||||||
|
printf(stdout, "open directory for write succeeded\n");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
sleep(1);
|
||||||
|
if(unlink("oidir") != 0){
|
||||||
|
printf(stdout, "unlink failed\n");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
wait();
|
||||||
|
printf(stdout, "openiput test ok\n");
|
||||||
|
}
|
||||||
|
|
||||||
// simple file system tests
|
// simple file system tests
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -187,7 +287,7 @@ void dirtest(void)
|
||||||
printf(stdout, "unlink dir0 failed\n");
|
printf(stdout, "unlink dir0 failed\n");
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
printf(stdout, "mkdir test\n");
|
printf(stdout, "mkdir test ok\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1628,6 +1728,10 @@ main(int argc, char *argv[])
|
||||||
writetest1();
|
writetest1();
|
||||||
createtest();
|
createtest();
|
||||||
|
|
||||||
|
openiputtest();
|
||||||
|
exitiputtest();
|
||||||
|
iputtest();
|
||||||
|
|
||||||
mem();
|
mem();
|
||||||
pipe1();
|
pipe1();
|
||||||
preempt();
|
preempt();
|
||||||
|
|
Loading…
Add table
Reference in a new issue