forked from mit-pdos/xv6-public
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Passes usertests and stressfs Seems to recover correctly in a number of simple cases
- Loading branch information
Frans Kaashoek
authored and
Frans Kaashoek
committed
Jul 28, 2011
1 parent
97657d7
commit 13a96ba
Showing
11 changed files
with
244 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
#include "types.h" | ||
#include "defs.h" | ||
#include "param.h" | ||
#include "mmu.h" | ||
#include "proc.h" | ||
#include "x86.h" | ||
#include "spinlock.h" | ||
#include "fs.h" | ||
#include "buf.h" | ||
|
||
// Dirt simple "logging" supporting only one transaction. All file system calls | ||
// that potentially write a block should be wrapped in begin_trans and commit_trans, | ||
// so that there is never more than one transaction. This serializes all file system | ||
// operations that potentially write, but simplifies recovery (only the last | ||
// one transaction to recover) and concurrency (don't have to worry about reading a modified | ||
// block from a transaction that hasn't committed yet). | ||
|
||
// The header of the log. If head == 0, there are no log entries. All entries till head | ||
// are committed. sector[] records the home sector for each block in the log | ||
// (i.e., physical logging). | ||
struct logheader { | ||
int head; | ||
int sector[LOGSIZE]; | ||
}; | ||
|
||
struct { | ||
struct spinlock lock; | ||
int start; | ||
int size; | ||
int intrans; | ||
int dev; | ||
struct logheader lh; | ||
} log; | ||
|
||
static void recover_from_log(void); | ||
|
||
void | ||
initlog(void) | ||
{ | ||
if (sizeof(struct logheader) >= BSIZE) | ||
panic("initlog: too big logheader"); | ||
|
||
struct superblock sb; | ||
initlock(&log.lock, "log"); | ||
readsb(ROOTDEV, &sb); | ||
log.start = sb.size - sb.nlog; | ||
log.size = sb.nlog; | ||
log.dev = ROOTDEV; | ||
recover_from_log(); | ||
} | ||
|
||
// Copy committed blocks from log to their home location | ||
static void | ||
install_trans(void) | ||
{ | ||
int tail; | ||
|
||
if (log.lh.head > 0) | ||
cprintf("install_trans %d\n", log.lh.head); | ||
for (tail = 0; tail < log.lh.head; tail++) { | ||
cprintf("put entry %d to disk block %d\n", tail, log.lh.sector[tail]); | ||
struct buf *lbuf = bread(log.dev, log.start+tail+1); // read i'th block from log | ||
struct buf *dbuf = bread(log.dev, log.lh.sector[tail]); // read dst block | ||
memmove(dbuf->data, lbuf->data, BSIZE); | ||
bwrite(dbuf); | ||
brelse(lbuf); | ||
brelse(dbuf); | ||
} | ||
} | ||
|
||
// Read the log header from disk into the in-memory log header | ||
static void | ||
read_head(void) | ||
{ | ||
struct buf *buf = bread(log.dev, log.start); | ||
struct logheader *lh = (struct logheader *) (buf->data); | ||
int i; | ||
log.lh.head = lh->head; | ||
for (i = 0; i < log.lh.head; i++) { | ||
log.lh.sector[i] = lh->sector[i]; | ||
} | ||
brelse(buf); | ||
if (log.lh.head > 0) | ||
cprintf("read_head: %d\n", log.lh.head); | ||
} | ||
|
||
// Write the in-memory log header to disk, committing log entries till head | ||
static void | ||
write_head(void) | ||
{ | ||
if (log.lh.head > 0) | ||
cprintf("write_head: %d\n", log.lh.head); | ||
|
||
struct buf *buf = bread(log.dev, log.start); | ||
struct logheader *hb = (struct logheader *) (buf->data); | ||
int i; | ||
hb->head = log.lh.head; | ||
for (i = 0; i < log.lh.head; i++) { | ||
hb->sector[i] = log.lh.sector[i]; | ||
} | ||
bwrite(buf); | ||
brelse(buf); | ||
} | ||
|
||
static void | ||
recover_from_log(void) | ||
{ | ||
read_head(); | ||
install_trans(); // Install all transactions till head | ||
log.lh.head = 0; | ||
write_head(); // Reclaim log | ||
} | ||
|
||
void | ||
begin_trans(void) | ||
{ | ||
acquire(&log.lock); | ||
while (log.intrans) { | ||
sleep(&log, &log.lock); | ||
} | ||
log.intrans = 1; | ||
release(&log.lock); | ||
} | ||
|
||
void | ||
commit_trans(void) | ||
{ | ||
write_head(); // This causes all blocks till log.head to be commited | ||
install_trans(); // Install all the transactions till head | ||
log.lh.head = 0; | ||
write_head(); // Reclaim log | ||
|
||
acquire(&log.lock); | ||
log.intrans = 0; | ||
wakeup(&log); | ||
release(&log.lock); | ||
} | ||
|
||
// Write buffer into the log at log.head and record the block number log.lh.entry, but | ||
// don't write the log header (which would commit the write). | ||
void | ||
log_write(struct buf *b) | ||
{ | ||
int i; | ||
|
||
if (log.lh.head >= LOGSIZE) | ||
panic("too big a transaction"); | ||
if (!log.intrans) | ||
panic("write outside of trans"); | ||
|
||
cprintf("log_write: %d %d\n", b->sector, log.lh.head); | ||
|
||
for (i = 0; i < log.lh.head; i++) { | ||
if (log.lh.sector[i] == b->sector) // log absorbtion? | ||
break; | ||
} | ||
log.lh.sector[i] = b->sector; | ||
struct buf *lbuf = bread(b->dev, log.start+i+1); | ||
memmove(lbuf->data, b->data, BSIZE); | ||
bwrite(lbuf); | ||
brelse(lbuf); | ||
if (i == log.lh.head) | ||
log.lh.head++; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.