summaryrefslogtreecommitdiff
path: root/log.c
diff options
context:
space:
mode:
authorRobert Morris <[email protected]>2019-06-11 09:57:14 -0400
committerRobert Morris <[email protected]>2019-06-11 09:57:14 -0400
commit5753553213df8f9de851adb68377db43faecb91f (patch)
tree3b629ff54897fca414146677532cb459a2ed11ba /log.c
parent91ba81110acd3163f7de3580b677eece0c57f5e7 (diff)
downloadxv6-labs-5753553213df8f9de851adb68377db43faecb91f.tar.gz
xv6-labs-5753553213df8f9de851adb68377db43faecb91f.tar.bz2
xv6-labs-5753553213df8f9de851adb68377db43faecb91f.zip
separate source into kernel/ user/ mkfs/
Diffstat (limited to 'log.c')
-rw-r--r--log.c235
1 files changed, 0 insertions, 235 deletions
diff --git a/log.c b/log.c
deleted file mode 100644
index c8f7e62..0000000
--- a/log.c
+++ /dev/null
@@ -1,235 +0,0 @@
-#include "types.h"
-#include "riscv.h"
-#include "defs.h"
-#include "param.h"
-#include "spinlock.h"
-#include "sleeplock.h"
-#include "fs.h"
-#include "buf.h"
-
-// Simple logging that allows concurrent FS system calls.
-//
-// A log transaction contains the updates of multiple FS system
-// calls. The logging system only commits when there are
-// no FS system calls active. Thus there is never
-// any reasoning required about whether a commit might
-// write an uncommitted system call's updates to disk.
-//
-// A system call should call begin_op()/end_op() to mark
-// its start and end. Usually begin_op() just increments
-// the count of in-progress FS system calls and returns.
-// But if it thinks the log is close to running out, it
-// sleeps until the last outstanding end_op() commits.
-//
-// The log is a physical re-do log containing disk blocks.
-// The on-disk log format:
-// header block, containing block #s for block A, B, C, ...
-// block A
-// block B
-// block C
-// ...
-// Log appends are synchronous.
-
-// Contents of the header block, used for both the on-disk header block
-// and to keep track in memory of logged block# before commit.
-struct logheader {
- int n;
- int block[LOGSIZE];
-};
-
-struct log {
- struct spinlock lock;
- int start;
- int size;
- int outstanding; // how many FS sys calls are executing.
- int committing; // in commit(), please wait.
- int dev;
- struct logheader lh;
-};
-struct log log;
-
-static void recover_from_log(void);
-static void commit();
-
-void
-initlog(int dev)
-{
- if (sizeof(struct logheader) >= BSIZE)
- panic("initlog: too big logheader");
-
- struct superblock sb;
- initlock(&log.lock, "log");
- readsb(dev, &sb);
- log.start = sb.logstart;
- log.size = sb.nlog;
- log.dev = dev;
- recover_from_log();
-}
-
-// Copy committed blocks from log to their home location
-static void
-install_trans(void)
-{
- int tail;
-
- for (tail = 0; tail < log.lh.n; tail++) {
- struct buf *lbuf = bread(log.dev, log.start+tail+1); // read log block
- struct buf *dbuf = bread(log.dev, log.lh.block[tail]); // read dst
- memmove(dbuf->data, lbuf->data, BSIZE); // copy block to dst
- bwrite(dbuf); // write dst to disk
- 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.n = lh->n;
- for (i = 0; i < log.lh.n; i++) {
- log.lh.block[i] = lh->block[i];
- }
- brelse(buf);
-}
-
-// Write in-memory log header to disk.
-// This is the true point at which the
-// current transaction commits.
-static void
-write_head(void)
-{
- struct buf *buf = bread(log.dev, log.start);
- struct logheader *hb = (struct logheader *) (buf->data);
- int i;
- hb->n = log.lh.n;
- for (i = 0; i < log.lh.n; i++) {
- hb->block[i] = log.lh.block[i];
- }
- bwrite(buf);
- brelse(buf);
-}
-
-static void
-recover_from_log(void)
-{
- read_head();
- install_trans(); // if committed, copy from log to disk
- log.lh.n = 0;
- write_head(); // clear the log
-}
-
-// called at the start of each FS system call.
-void
-begin_op(void)
-{
- acquire(&log.lock);
- while(1){
- if(log.committing){
- sleep(&log, &log.lock);
- } else if(log.lh.n + (log.outstanding+1)*MAXOPBLOCKS > LOGSIZE){
- // this op might exhaust log space; wait for commit.
- sleep(&log, &log.lock);
- } else {
- log.outstanding += 1;
- release(&log.lock);
- break;
- }
- }
-}
-
-// called at the end of each FS system call.
-// commits if this was the last outstanding operation.
-void
-end_op(void)
-{
- int do_commit = 0;
-
- acquire(&log.lock);
- log.outstanding -= 1;
- if(log.committing)
- panic("log.committing");
- if(log.outstanding == 0){
- do_commit = 1;
- log.committing = 1;
- } else {
- // begin_op() may be waiting for log space,
- // and decrementing log.outstanding has decreased
- // the amount of reserved space.
- wakeup(&log);
- }
- release(&log.lock);
-
- if(do_commit){
- // call commit w/o holding locks, since not allowed
- // to sleep with locks.
- commit();
- acquire(&log.lock);
- log.committing = 0;
- wakeup(&log);
- release(&log.lock);
- }
-}
-
-// Copy modified blocks from cache to log.
-static void
-write_log(void)
-{
- int tail;
-
- for (tail = 0; tail < log.lh.n; tail++) {
- struct buf *to = bread(log.dev, log.start+tail+1); // log block
- struct buf *from = bread(log.dev, log.lh.block[tail]); // cache block
- memmove(to->data, from->data, BSIZE);
- bwrite(to); // write the log
- brelse(from);
- brelse(to);
- }
-}
-
-static void
-commit()
-{
- if (log.lh.n > 0) {
- write_log(); // Write modified blocks from cache to log
- write_head(); // Write header to disk -- the real commit
- install_trans(); // Now install writes to home locations
- log.lh.n = 0;
- write_head(); // Erase the transaction from the log
- }
-}
-
-// Caller has modified b->data and is done with the buffer.
-// Record the block number and pin in the cache with B_DIRTY.
-// commit()/write_log() will do the disk write.
-//
-// log_write() replaces bwrite(); a typical use is:
-// bp = bread(...)
-// modify bp->data[]
-// log_write(bp)
-// brelse(bp)
-void
-log_write(struct buf *b)
-{
- int i;
-
- if (log.lh.n >= LOGSIZE || log.lh.n >= log.size - 1)
- panic("too big a transaction");
- if (log.outstanding < 1)
- panic("log_write outside of trans");
-
- acquire(&log.lock);
- for (i = 0; i < log.lh.n; i++) {
- if (log.lh.block[i] == b->blockno) // log absorbtion
- break;
- }
- log.lh.block[i] = b->blockno;
- if (i == log.lh.n)
- log.lh.n++;
- b->flags |= B_DIRTY; // prevent eviction
- release(&log.lock);
-}
-