Line data Source code
1 : #include "clusterautoconfig.h"
2 :
3 : /*
4 : * NOTE:
5 : *
6 : * This code was pilfered from the gfs2 kernel and adapted to userland.
7 : * If you change this part, you should evaluate whether the upstream kernel
8 : * version of recovery.c should be changed as well. Likewise, if the
9 : * upstream version changes, this part should be kept in sync.
10 : *
11 : */
12 :
13 : #include <errno.h>
14 : #include <string.h>
15 : #include "libgfs2.h"
16 :
17 0 : void lgfs2_replay_incr_blk(struct lgfs2_inode *ip, unsigned int *blk)
18 : {
19 0 : uint32_t jd_blocks = ip->i_size / ip->i_sbd->sd_bsize;
20 :
21 0 : if (++*blk == jd_blocks)
22 0 : *blk = 0;
23 0 : }
24 :
25 1894324 : int lgfs2_replay_read_block(struct lgfs2_inode *ip, unsigned int blk,
26 : struct lgfs2_buffer_head **bh)
27 : {
28 1894324 : int new = 0;
29 : uint64_t dblock;
30 :
31 1894324 : if (lgfs2_block_map(ip, blk, &new, &dblock, NULL, 0))
32 0 : return -EINVAL;
33 1894324 : if (!dblock)
34 0 : return -EIO;
35 :
36 1894324 : *bh = lgfs2_bread(ip->i_sbd, dblock);
37 1894324 : return 0;
38 : }
39 :
40 1894324 : static void log_header_in(struct lgfs2_log_header *lh, char *buf)
41 : {
42 1894324 : struct gfs2_log_header *lhd = (struct gfs2_log_header *)buf;
43 :
44 1894324 : lh->lh_sequence = be64_to_cpu(lhd->lh_sequence);
45 1894324 : lh->lh_flags = be32_to_cpu(lhd->lh_flags);
46 1894324 : lh->lh_tail = be32_to_cpu(lhd->lh_tail);
47 1894324 : lh->lh_blkno = be32_to_cpu(lhd->lh_blkno);
48 1894324 : lh->lh_hash = be32_to_cpu(lhd->lh_hash);
49 1894324 : lh->lh_crc = be32_to_cpu(lhd->lh_crc);
50 1894324 : lh->lh_local_total = be64_to_cpu(lhd->lh_local_total);
51 1894324 : lh->lh_local_free = be64_to_cpu(lhd->lh_local_free);
52 1894324 : lh->lh_local_dinodes = be64_to_cpu(lhd->lh_local_dinodes);
53 1894324 : }
54 :
55 : /**
56 : * get_log_header - read the log header for a given segment
57 : * @ip: the journal incore inode
58 : * @blk: the block to look at
59 : * @lh: the log header to return
60 : *
61 : * Read the log header for a given segement in a given journal. Do a few
62 : * sanity checks on it.
63 : *
64 : * Returns: 0 on success,
65 : * 1 if the header was invalid or incomplete,
66 : * errno on error
67 : */
68 :
69 1894324 : int lgfs2_get_log_header(struct lgfs2_inode *ip, unsigned int blk,
70 : struct lgfs2_log_header *head)
71 : {
72 : struct lgfs2_buffer_head *bh;
73 : struct lgfs2_log_header lh;
74 : struct gfs2_log_header *tmp;
75 : __be32 saved_hash;
76 : uint32_t hash;
77 1894324 : uint32_t lh_crc = 0;
78 : uint32_t crc;
79 : int error;
80 :
81 1894324 : error = lgfs2_replay_read_block(ip, blk, &bh);
82 1894324 : if (error)
83 0 : return error;
84 :
85 1894324 : tmp = (struct gfs2_log_header *)bh->b_data;
86 1894324 : saved_hash = tmp->lh_hash;
87 1894324 : tmp->lh_hash = 0;
88 1894324 : hash = lgfs2_log_header_hash(bh->b_data);
89 1894324 : tmp->lh_hash = saved_hash;
90 1894324 : crc = lgfs2_log_header_crc(bh->b_data, ip->i_sbd->sd_bsize);
91 1894324 : log_header_in(&lh, bh->b_data);
92 1894324 : lgfs2_brelse(bh);
93 1894324 : lh_crc = lh.lh_crc;
94 1894324 : if (error || lh.lh_blkno != blk || lh.lh_hash != hash)
95 0 : return 1;
96 : /* Don't check the crc if it's zero, as it is in pre-v2 log headers */
97 1894324 : if (lh_crc != 0 && lh_crc != crc)
98 0 : return 1;
99 :
100 1894324 : *head = lh;
101 :
102 1894324 : return 0;
103 : }
104 :
105 : /**
106 : * find_good_lh - find a good log header
107 : * @ip: the journal incore inode
108 : * @blk: the segment to start searching from
109 : * @lh: the log header to fill in
110 : * @forward: if true search forward in the log, else search backward
111 : *
112 : * Call get_log_header() to get a log header for a segment, but if the
113 : * segment is bad, either scan forward or backward until we find a good one.
114 : *
115 : * Returns: errno
116 : */
117 1910 : static int find_good_lh(struct lgfs2_inode *ip, unsigned int *blk, struct lgfs2_log_header *head)
118 : {
119 1910 : unsigned int orig_blk = *blk;
120 : int error;
121 1910 : uint32_t jd_blocks = ip->i_size / ip->i_sbd->sd_bsize;
122 :
123 : for (;;) {
124 1910 : error = lgfs2_get_log_header(ip, *blk, head);
125 1910 : if (error <= 0)
126 1910 : return error;
127 :
128 0 : if (++*blk == jd_blocks)
129 0 : *blk = 0;
130 :
131 0 : if (*blk == orig_blk)
132 0 : return -EIO;
133 : }
134 : }
135 :
136 : /**
137 : * jhead_scan - make sure we've found the head of the log
138 : * @jd: the journal
139 : * @head: this is filled in with the log descriptor of the head
140 : *
141 : * At this point, seg and lh should be either the head of the log or just
142 : * before. Scan forward until we find the head.
143 : *
144 : * Returns: errno
145 : */
146 :
147 62 : static int jhead_scan(struct lgfs2_inode *ip, struct lgfs2_log_header *head)
148 : {
149 62 : unsigned int blk = head->lh_blkno;
150 62 : uint32_t jd_blocks = ip->i_size / ip->i_sbd->sd_bsize;
151 : struct lgfs2_log_header lh;
152 : int error;
153 :
154 : for (;;) {
155 62 : if (++blk == jd_blocks)
156 0 : blk = 0;
157 :
158 62 : error = lgfs2_get_log_header(ip, blk, &lh);
159 62 : if (error < 0)
160 0 : return error;
161 62 : if (error == 1)
162 0 : continue;
163 :
164 62 : if (lh.lh_sequence == head->lh_sequence)
165 0 : return -EIO;
166 62 : if (lh.lh_sequence < head->lh_sequence)
167 62 : break;
168 :
169 0 : *head = lh;
170 : }
171 :
172 62 : return 0;
173 : }
174 :
175 : /**
176 : * gfs2_find_jhead - find the head of a log
177 : * @jd: the journal
178 : * @head: the log descriptor for the head of the log is returned here
179 : *
180 : * Do a binary search of a journal and find the valid log entry with the
181 : * highest sequence number. (i.e. the log head)
182 : *
183 : * Returns: errno
184 : */
185 :
186 62 : int lgfs2_find_jhead(struct lgfs2_inode *ip, struct lgfs2_log_header *head)
187 : {
188 : struct lgfs2_log_header lh_1, lh_m;
189 : uint32_t blk_1, blk_2, blk_m;
190 62 : uint32_t jd_blocks = ip->i_size / ip->i_sbd->sd_bsize;
191 : int error;
192 :
193 62 : blk_1 = 0;
194 62 : blk_2 = jd_blocks - 1;
195 :
196 : for (;;) {
197 955 : blk_m = (blk_1 + blk_2) / 2;
198 :
199 955 : error = find_good_lh(ip, &blk_1, &lh_1);
200 955 : if (error)
201 0 : return error;
202 :
203 955 : error = find_good_lh(ip, &blk_m, &lh_m);
204 955 : if (error)
205 0 : return error;
206 :
207 955 : if (blk_1 == blk_m || blk_m == blk_2)
208 : break;
209 :
210 893 : if (lh_1.lh_sequence <= lh_m.lh_sequence)
211 435 : blk_1 = blk_m;
212 : else
213 458 : blk_2 = blk_m;
214 : }
215 :
216 62 : error = jhead_scan(ip, &lh_1);
217 62 : if (error)
218 0 : return error;
219 :
220 62 : *head = lh_1;
221 :
222 62 : return error;
223 : }
224 :
225 : /**
226 : * clean_journal - mark a dirty journal as being clean
227 : * @sdp: the filesystem
228 : * @jd: the journal
229 : * @head: the head journal to start from
230 : *
231 : * Returns: errno
232 : */
233 :
234 0 : int lgfs2_clean_journal(struct lgfs2_inode *ip, struct lgfs2_log_header *head)
235 : {
236 : unsigned int lblock;
237 : struct gfs2_log_header *lh;
238 : uint32_t hash;
239 : struct lgfs2_buffer_head *bh;
240 0 : int new = 0;
241 : uint64_t dblock;
242 :
243 0 : lblock = head->lh_blkno;
244 0 : lgfs2_replay_incr_blk(ip, &lblock);
245 0 : if (lgfs2_block_map(ip, lblock, &new, &dblock, NULL, 0))
246 0 : return -EINVAL;
247 0 : if (!dblock)
248 0 : return -EIO;
249 :
250 0 : bh = lgfs2_bread(ip->i_sbd, dblock);
251 0 : memset(bh->b_data, 0, ip->i_sbd->sd_bsize);
252 :
253 0 : lh = (struct gfs2_log_header *)bh->b_data;
254 0 : memset(lh, 0, sizeof(struct gfs2_log_header));
255 0 : lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
256 0 : lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH);
257 0 : lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH);
258 0 : lh->lh_sequence = cpu_to_be64(head->lh_sequence + 1);
259 0 : lh->lh_flags = cpu_to_be32(GFS2_LOG_HEAD_UNMOUNT);
260 0 : lh->lh_blkno = cpu_to_be32(lblock);
261 0 : hash = lgfs2_log_header_hash(bh->b_data);
262 0 : lh->lh_hash = cpu_to_be32(hash);
263 0 : lgfs2_bmodified(bh);
264 0 : lgfs2_brelse(bh);
265 :
266 0 : return 0;
267 : }
268 :
|