1*13a96baeSFrans Kaashoek #include "types.h" 2*13a96baeSFrans Kaashoek #include "defs.h" 3*13a96baeSFrans Kaashoek #include "param.h" 4*13a96baeSFrans Kaashoek #include "mmu.h" 5*13a96baeSFrans Kaashoek #include "proc.h" 6*13a96baeSFrans Kaashoek #include "x86.h" 7*13a96baeSFrans Kaashoek #include "spinlock.h" 8*13a96baeSFrans Kaashoek #include "fs.h" 9*13a96baeSFrans Kaashoek #include "buf.h" 10*13a96baeSFrans Kaashoek 11*13a96baeSFrans Kaashoek // Dirt simple "logging" supporting only one transaction. All file system calls 12*13a96baeSFrans Kaashoek // that potentially write a block should be wrapped in begin_trans and commit_trans, 13*13a96baeSFrans Kaashoek // so that there is never more than one transaction. This serializes all file system 14*13a96baeSFrans Kaashoek // operations that potentially write, but simplifies recovery (only the last 15*13a96baeSFrans Kaashoek // one transaction to recover) and concurrency (don't have to worry about reading a modified 16*13a96baeSFrans Kaashoek // block from a transaction that hasn't committed yet). 17*13a96baeSFrans Kaashoek 18*13a96baeSFrans Kaashoek // The header of the log. If head == 0, there are no log entries. All entries till head 19*13a96baeSFrans Kaashoek // are committed. sector[] records the home sector for each block in the log 20*13a96baeSFrans Kaashoek // (i.e., physical logging). 21*13a96baeSFrans Kaashoek struct logheader { 22*13a96baeSFrans Kaashoek int head; 23*13a96baeSFrans Kaashoek int sector[LOGSIZE]; 24*13a96baeSFrans Kaashoek }; 25*13a96baeSFrans Kaashoek 26*13a96baeSFrans Kaashoek struct { 27*13a96baeSFrans Kaashoek struct spinlock lock; 28*13a96baeSFrans Kaashoek int start; 29*13a96baeSFrans Kaashoek int size; 30*13a96baeSFrans Kaashoek int intrans; 31*13a96baeSFrans Kaashoek int dev; 32*13a96baeSFrans Kaashoek struct logheader lh; 33*13a96baeSFrans Kaashoek } log; 34*13a96baeSFrans Kaashoek 35*13a96baeSFrans Kaashoek static void recover_from_log(void); 36*13a96baeSFrans Kaashoek 37*13a96baeSFrans Kaashoek void 38*13a96baeSFrans Kaashoek initlog(void) 39*13a96baeSFrans Kaashoek { 40*13a96baeSFrans Kaashoek if (sizeof(struct logheader) >= BSIZE) 41*13a96baeSFrans Kaashoek panic("initlog: too big logheader"); 42*13a96baeSFrans Kaashoek 43*13a96baeSFrans Kaashoek struct superblock sb; 44*13a96baeSFrans Kaashoek initlock(&log.lock, "log"); 45*13a96baeSFrans Kaashoek readsb(ROOTDEV, &sb); 46*13a96baeSFrans Kaashoek log.start = sb.size - sb.nlog; 47*13a96baeSFrans Kaashoek log.size = sb.nlog; 48*13a96baeSFrans Kaashoek log.dev = ROOTDEV; 49*13a96baeSFrans Kaashoek recover_from_log(); 50*13a96baeSFrans Kaashoek } 51*13a96baeSFrans Kaashoek 52*13a96baeSFrans Kaashoek // Copy committed blocks from log to their home location 53*13a96baeSFrans Kaashoek static void 54*13a96baeSFrans Kaashoek install_trans(void) 55*13a96baeSFrans Kaashoek { 56*13a96baeSFrans Kaashoek int tail; 57*13a96baeSFrans Kaashoek 58*13a96baeSFrans Kaashoek if (log.lh.head > 0) 59*13a96baeSFrans Kaashoek cprintf("install_trans %d\n", log.lh.head); 60*13a96baeSFrans Kaashoek for (tail = 0; tail < log.lh.head; tail++) { 61*13a96baeSFrans Kaashoek cprintf("put entry %d to disk block %d\n", tail, log.lh.sector[tail]); 62*13a96baeSFrans Kaashoek struct buf *lbuf = bread(log.dev, log.start+tail+1); // read i'th block from log 63*13a96baeSFrans Kaashoek struct buf *dbuf = bread(log.dev, log.lh.sector[tail]); // read dst block 64*13a96baeSFrans Kaashoek memmove(dbuf->data, lbuf->data, BSIZE); 65*13a96baeSFrans Kaashoek bwrite(dbuf); 66*13a96baeSFrans Kaashoek brelse(lbuf); 67*13a96baeSFrans Kaashoek brelse(dbuf); 68*13a96baeSFrans Kaashoek } 69*13a96baeSFrans Kaashoek } 70*13a96baeSFrans Kaashoek 71*13a96baeSFrans Kaashoek // Read the log header from disk into the in-memory log header 72*13a96baeSFrans Kaashoek static void 73*13a96baeSFrans Kaashoek read_head(void) 74*13a96baeSFrans Kaashoek { 75*13a96baeSFrans Kaashoek struct buf *buf = bread(log.dev, log.start); 76*13a96baeSFrans Kaashoek struct logheader *lh = (struct logheader *) (buf->data); 77*13a96baeSFrans Kaashoek int i; 78*13a96baeSFrans Kaashoek log.lh.head = lh->head; 79*13a96baeSFrans Kaashoek for (i = 0; i < log.lh.head; i++) { 80*13a96baeSFrans Kaashoek log.lh.sector[i] = lh->sector[i]; 81*13a96baeSFrans Kaashoek } 82*13a96baeSFrans Kaashoek brelse(buf); 83*13a96baeSFrans Kaashoek if (log.lh.head > 0) 84*13a96baeSFrans Kaashoek cprintf("read_head: %d\n", log.lh.head); 85*13a96baeSFrans Kaashoek } 86*13a96baeSFrans Kaashoek 87*13a96baeSFrans Kaashoek // Write the in-memory log header to disk, committing log entries till head 88*13a96baeSFrans Kaashoek static void 89*13a96baeSFrans Kaashoek write_head(void) 90*13a96baeSFrans Kaashoek { 91*13a96baeSFrans Kaashoek if (log.lh.head > 0) 92*13a96baeSFrans Kaashoek cprintf("write_head: %d\n", log.lh.head); 93*13a96baeSFrans Kaashoek 94*13a96baeSFrans Kaashoek struct buf *buf = bread(log.dev, log.start); 95*13a96baeSFrans Kaashoek struct logheader *hb = (struct logheader *) (buf->data); 96*13a96baeSFrans Kaashoek int i; 97*13a96baeSFrans Kaashoek hb->head = log.lh.head; 98*13a96baeSFrans Kaashoek for (i = 0; i < log.lh.head; i++) { 99*13a96baeSFrans Kaashoek hb->sector[i] = log.lh.sector[i]; 100*13a96baeSFrans Kaashoek } 101*13a96baeSFrans Kaashoek bwrite(buf); 102*13a96baeSFrans Kaashoek brelse(buf); 103*13a96baeSFrans Kaashoek } 104*13a96baeSFrans Kaashoek 105*13a96baeSFrans Kaashoek static void 106*13a96baeSFrans Kaashoek recover_from_log(void) 107*13a96baeSFrans Kaashoek { 108*13a96baeSFrans Kaashoek read_head(); 109*13a96baeSFrans Kaashoek install_trans(); // Install all transactions till head 110*13a96baeSFrans Kaashoek log.lh.head = 0; 111*13a96baeSFrans Kaashoek write_head(); // Reclaim log 112*13a96baeSFrans Kaashoek } 113*13a96baeSFrans Kaashoek 114*13a96baeSFrans Kaashoek void 115*13a96baeSFrans Kaashoek begin_trans(void) 116*13a96baeSFrans Kaashoek { 117*13a96baeSFrans Kaashoek acquire(&log.lock); 118*13a96baeSFrans Kaashoek while (log.intrans) { 119*13a96baeSFrans Kaashoek sleep(&log, &log.lock); 120*13a96baeSFrans Kaashoek } 121*13a96baeSFrans Kaashoek log.intrans = 1; 122*13a96baeSFrans Kaashoek release(&log.lock); 123*13a96baeSFrans Kaashoek } 124*13a96baeSFrans Kaashoek 125*13a96baeSFrans Kaashoek void 126*13a96baeSFrans Kaashoek commit_trans(void) 127*13a96baeSFrans Kaashoek { 128*13a96baeSFrans Kaashoek write_head(); // This causes all blocks till log.head to be commited 129*13a96baeSFrans Kaashoek install_trans(); // Install all the transactions till head 130*13a96baeSFrans Kaashoek log.lh.head = 0; 131*13a96baeSFrans Kaashoek write_head(); // Reclaim log 132*13a96baeSFrans Kaashoek 133*13a96baeSFrans Kaashoek acquire(&log.lock); 134*13a96baeSFrans Kaashoek log.intrans = 0; 135*13a96baeSFrans Kaashoek wakeup(&log); 136*13a96baeSFrans Kaashoek release(&log.lock); 137*13a96baeSFrans Kaashoek } 138*13a96baeSFrans Kaashoek 139*13a96baeSFrans Kaashoek // Write buffer into the log at log.head and record the block number log.lh.entry, but 140*13a96baeSFrans Kaashoek // don't write the log header (which would commit the write). 141*13a96baeSFrans Kaashoek void 142*13a96baeSFrans Kaashoek log_write(struct buf *b) 143*13a96baeSFrans Kaashoek { 144*13a96baeSFrans Kaashoek int i; 145*13a96baeSFrans Kaashoek 146*13a96baeSFrans Kaashoek if (log.lh.head >= LOGSIZE) 147*13a96baeSFrans Kaashoek panic("too big a transaction"); 148*13a96baeSFrans Kaashoek if (!log.intrans) 149*13a96baeSFrans Kaashoek panic("write outside of trans"); 150*13a96baeSFrans Kaashoek 151*13a96baeSFrans Kaashoek cprintf("log_write: %d %d\n", b->sector, log.lh.head); 152*13a96baeSFrans Kaashoek 153*13a96baeSFrans Kaashoek for (i = 0; i < log.lh.head; i++) { 154*13a96baeSFrans Kaashoek if (log.lh.sector[i] == b->sector) // log absorbtion? 155*13a96baeSFrans Kaashoek break; 156*13a96baeSFrans Kaashoek } 157*13a96baeSFrans Kaashoek log.lh.sector[i] = b->sector; 158*13a96baeSFrans Kaashoek struct buf *lbuf = bread(b->dev, log.start+i+1); 159*13a96baeSFrans Kaashoek memmove(lbuf->data, b->data, BSIZE); 160*13a96baeSFrans Kaashoek bwrite(lbuf); 161*13a96baeSFrans Kaashoek brelse(lbuf); 162*13a96baeSFrans Kaashoek if (i == log.lh.head) 163*13a96baeSFrans Kaashoek log.lh.head++; 164*13a96baeSFrans Kaashoek } 165