From 5753553213df8f9de851adb68377db43faecb91f Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Tue, 11 Jun 2019 09:57:14 -0400 Subject: separate source into kernel/ user/ mkfs/ --- log.c | 235 ------------------------------------------------------------------ 1 file changed, 235 deletions(-) delete mode 100644 log.c (limited to 'log.c') 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); -} - -- cgit v1.2.3