xref: /xv6-public/log.c (revision 13a96bae)
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