Mercurial > hg > Members > tobaru > CbC_xv6
comparison src/log.c @ 0:83c23a36980d
Init
author | Tatsuki IHA <e125716@ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 26 May 2017 23:11:05 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:83c23a36980d |
---|---|
1 #include "types.h" | |
2 #include "defs.h" | |
3 #include "param.h" | |
4 #include "spinlock.h" | |
5 #include "fs.h" | |
6 #include "buf.h" | |
7 | |
8 // Simple logging. Each system call that might write the file system | |
9 // should be surrounded with begin_trans() and commit_trans() calls. | |
10 // | |
11 // The log holds at most one transaction at a time. Commit forces | |
12 // the log (with commit record) to disk, then installs the affected | |
13 // blocks to disk, then erases the log. begin_trans() ensures that | |
14 // only one system call can be in a transaction; others must wait. | |
15 // | |
16 // Allowing only one transaction at a time means that the file | |
17 // system code doesn't have to worry about the possibility of | |
18 // one transaction reading a block that another one has modified, | |
19 // for example an i-node block. | |
20 // | |
21 // Read-only system calls don't need to use transactions, though | |
22 // this means that they may observe uncommitted data. I-node and | |
23 // buffer locks prevent read-only calls from seeing inconsistent data. | |
24 // | |
25 // The log is a physical re-do log containing disk blocks. | |
26 // The on-disk log format: | |
27 // header block, containing sector #s for block A, B, C, ... | |
28 // block A | |
29 // block B | |
30 // block C | |
31 // ... | |
32 // Log appends are synchronous. | |
33 | |
34 // Contents of the header block, used for both the on-disk header block | |
35 // and to keep track in memory of logged sector #s before commit. | |
36 struct logheader { | |
37 int n; | |
38 int sector[LOGSIZE]; | |
39 }; | |
40 | |
41 struct log { | |
42 struct spinlock lock; | |
43 int start; | |
44 int size; | |
45 int busy; // a transaction is active | |
46 int dev; | |
47 struct logheader lh; | |
48 }; | |
49 struct log log; | |
50 | |
51 static void recover_from_log(void); | |
52 | |
53 void initlog(void) | |
54 { | |
55 struct superblock sb; | |
56 | |
57 if (sizeof(struct logheader) >= BSIZE) { | |
58 panic("initlog: too big logheader"); | |
59 } | |
60 | |
61 initlock(&log.lock, "log"); | |
62 readsb(ROOTDEV, &sb); | |
63 log.start = sb.size - sb.nlog; | |
64 log.size = sb.nlog; | |
65 log.dev = ROOTDEV; | |
66 recover_from_log(); | |
67 } | |
68 | |
69 // Copy committed blocks from log to their home location | |
70 static void install_trans(void) | |
71 { | |
72 int tail; | |
73 struct buf *lbuf; | |
74 struct buf *dbuf; | |
75 | |
76 for (tail = 0; tail < log.lh.n; tail++) { | |
77 lbuf = bread(log.dev, log.start+tail+1); // read log block | |
78 dbuf = bread(log.dev, log.lh.sector[tail]); // read dst | |
79 | |
80 memmove(dbuf->data, lbuf->data, BSIZE); // copy block to dst | |
81 | |
82 bwrite(dbuf); // write dst to disk | |
83 brelse(lbuf); | |
84 brelse(dbuf); | |
85 } | |
86 } | |
87 | |
88 // Read the log header from disk into the in-memory log header | |
89 static void read_head(void) | |
90 { | |
91 struct buf *buf; | |
92 struct logheader *lh; | |
93 int i; | |
94 | |
95 buf = bread(log.dev, log.start); | |
96 lh = (struct logheader *) (buf->data); | |
97 log.lh.n = lh->n; | |
98 | |
99 for (i = 0; i < log.lh.n; i++) { | |
100 log.lh.sector[i] = lh->sector[i]; | |
101 } | |
102 | |
103 brelse(buf); | |
104 } | |
105 | |
106 // Write in-memory log header to disk. | |
107 // This is the true point at which the | |
108 // current transaction commits. | |
109 static void write_head(void) | |
110 { | |
111 struct buf *buf; | |
112 struct logheader *hb; | |
113 int i; | |
114 | |
115 buf = bread(log.dev, log.start); | |
116 hb = (struct logheader *) (buf->data); | |
117 | |
118 hb->n = log.lh.n; | |
119 | |
120 for (i = 0; i < log.lh.n; i++) { | |
121 hb->sector[i] = log.lh.sector[i]; | |
122 } | |
123 | |
124 bwrite(buf); | |
125 brelse(buf); | |
126 } | |
127 | |
128 static void recover_from_log(void) | |
129 { | |
130 read_head(); | |
131 install_trans(); // if committed, copy from log to disk | |
132 log.lh.n = 0; | |
133 write_head(); // clear the log | |
134 } | |
135 | |
136 void begin_trans(void) | |
137 { | |
138 acquire(&log.lock); | |
139 | |
140 while (log.busy) { | |
141 sleep(&log, &log.lock); | |
142 } | |
143 | |
144 log.busy = 1; | |
145 release(&log.lock); | |
146 } | |
147 | |
148 void commit_trans(void) | |
149 { | |
150 if (log.lh.n > 0) { | |
151 write_head(); // Write header to disk -- the real commit | |
152 install_trans(); // Now install writes to home locations | |
153 log.lh.n = 0; | |
154 write_head(); // Erase the transaction from the log | |
155 } | |
156 | |
157 acquire(&log.lock); | |
158 log.busy = 0; | |
159 wakeup(&log); | |
160 release(&log.lock); | |
161 } | |
162 | |
163 // Caller has modified b->data and is done with the buffer. | |
164 // Append the block to the log and record the block number, | |
165 // but don't write the log header (which would commit the write). | |
166 // log_write() replaces bwrite(); a typical use is: | |
167 // bp = bread(...) | |
168 // modify bp->data[] | |
169 // log_write(bp) | |
170 // brelse(bp) | |
171 void log_write(struct buf *b) | |
172 { | |
173 struct buf *lbuf; | |
174 int i; | |
175 | |
176 if (log.lh.n >= LOGSIZE || log.lh.n >= log.size - 1) { | |
177 panic("too big a transaction"); | |
178 } | |
179 | |
180 if (!log.busy) { | |
181 panic("write outside of trans"); | |
182 } | |
183 | |
184 for (i = 0; i < log.lh.n; i++) { | |
185 if (log.lh.sector[i] == b->sector) { // log absorbtion? | |
186 break; | |
187 } | |
188 } | |
189 | |
190 log.lh.sector[i] = b->sector; | |
191 lbuf = bread(b->dev, log.start+i+1); | |
192 | |
193 memmove(lbuf->data, b->data, BSIZE); | |
194 bwrite(lbuf); | |
195 brelse(lbuf); | |
196 | |
197 if (i == log.lh.n) { | |
198 log.lh.n++; | |
199 } | |
200 | |
201 b->flags |= B_DIRTY; // XXX prevent eviction | |
202 } | |
203 | |
204 //PAGEBREAK! | |
205 // Blank page. | |
206 |