1 /*
2 journal.c -- reiserfs journal code
3 Copyright (C) 2001, 2002 Yury Umanets <torque@ukrpost.net>, see COPYING for
4 licensing and copyright details.
5
6 Some parts of this code inspired by the original reiserfs code, as found in
7 reiserfsprogs and the linux kernel.
8 */
9
10 #ifdef HAVE_CONFIG_H
11 # include <config.h>
12 #endif
13
14 #include <string.h>
15
16 #include <reiserfs/reiserfs.h>
17 #include <reiserfs/debug.h>
18 #include <reiserfs/callback.h>
19
20 #include <dal/dal.h>
21
22 #define N_(String) (String)
23 #if ENABLE_NLS
24 # include <libintl.h>
25 # define _(String) dgettext (PACKAGE, String)
26 #else
27 # define _(String) (String)
28 #endif
29
30 #define JOURNAL_DESC_SIGN "ReIsErLB"
31 #define JOURNAL_DESC_COMM 1
32 #define JOURNAL_DESC_NEXT 2
33
34 #define CASHE_SIZE(len) ((len) * sizeof(uint32_t))
35
reiserfs_journal_desc_match_comm(reiserfs_block_t * desc,reiserfs_block_t * comm)36 static int reiserfs_journal_desc_match_comm(reiserfs_block_t *desc, reiserfs_block_t *comm) {
37 return (get_jc_commit_trans_id(comm) == get_jd_desc_trans_id(desc) &&
38 get_jc_commit_trans_len(comm) == get_jd_desc_trans_len(desc));
39 }
40
reiserfs_journal_desc_prop(reiserfs_journal_head_t * head,reiserfs_block_t * desc,int prop)41 static blk_t reiserfs_journal_desc_prop(reiserfs_journal_head_t *head, reiserfs_block_t *desc,
42 int prop)
43 {
44 blk_t offset = reiserfs_block_get_nr(desc) - get_jp_start(&head->jh_params);
45 return get_jp_start(&head->jh_params) + ((offset +
46 get_jd_desc_trans_len(desc) + prop) % get_jp_len(&head->jh_params));
47 }
48
reiserfs_journal_desc_comm(reiserfs_journal_head_t * head,reiserfs_block_t * desc)49 static blk_t reiserfs_journal_desc_comm(reiserfs_journal_head_t *head, reiserfs_block_t *desc) {
50 return reiserfs_journal_desc_prop(head, desc, JOURNAL_DESC_COMM);
51 }
52
reiserfs_journal_desc_next(reiserfs_journal_head_t * head,reiserfs_block_t * desc)53 static blk_t reiserfs_journal_desc_next(reiserfs_journal_head_t *head, reiserfs_block_t *desc) {
54 return reiserfs_journal_desc_prop(head, desc, JOURNAL_DESC_NEXT);
55 }
56
reiserfs_journal_desc_block(reiserfs_block_t * desc)57 static int reiserfs_journal_desc_block(reiserfs_block_t *desc) {
58 if (!memcmp(get_jd_magic(desc, dal_get_blocksize(desc->dal)), JOURNAL_DESC_SIGN, 8) &&
59 LE32_TO_CPU(*((uint32_t *)(desc->data + 4))) > 0)
60 return 1;
61
62 return 0;
63 }
64
65 /*
66 Checking whether given transaction is valid. Transaction is
67 valid if his description block is valid, commit block is valid
68 and commit block matches description block.
69
70 Transaction looks like this:
71 desc_block + [ trans_blocks ] + comm_block
72 */
reiserfs_journal_desc_valid(reiserfs_journal_head_t * head,reiserfs_block_t * desc)73 static int reiserfs_journal_desc_valid(reiserfs_journal_head_t *head,
74 reiserfs_block_t *desc)
75 {
76 blk_t blk;
77 reiserfs_block_t *comm;
78
79 if (!desc || !reiserfs_journal_desc_block(desc))
80 return 0;
81
82 blk = reiserfs_journal_desc_comm(head, desc);
83 if (!(comm = reiserfs_block_read(desc->dal, blk)))
84 reiserfs_block_reading_failed(blk, dal_error(desc->dal), return 0);
85
86 if (!reiserfs_journal_desc_match_comm(desc, comm))
87 goto error_free_comm;
88
89 reiserfs_block_free(comm);
90 return 1;
91
92 error_free_comm:
93 reiserfs_block_free(comm);
94 error:
95 return 0;
96 }
97
reiserfs_journal_max_trans(blk_t max_trans,blk_t len,size_t blocksize)98 uint32_t reiserfs_journal_max_trans(blk_t max_trans, blk_t len,
99 size_t blocksize)
100 {
101 uint32_t ratio = 1;
102
103 if (blocksize < 4096)
104 ratio = 4096 / blocksize;
105
106 if (!max_trans)
107 max_trans = JOURNAL_MAX_TRANS / ratio;
108
109 if (len / max_trans < JOURNAL_MIN_RATIO)
110 max_trans = len / JOURNAL_MIN_RATIO;
111
112 if (max_trans > JOURNAL_MAX_TRANS / ratio)
113 max_trans = JOURNAL_MAX_TRANS / ratio;
114
115 if (max_trans < JOURNAL_MIN_TRANS / ratio)
116 max_trans = JOURNAL_MIN_TRANS / ratio;
117
118 return max_trans;
119 }
120
reiserfs_journal_max_len(dal_t * dal,blk_t start,int relocated)121 blk_t reiserfs_journal_max_len(dal_t *dal, blk_t start, int relocated) {
122 if (relocated)
123 return dal_len(dal) - start - 1;
124
125 return (dal_get_blocksize(dal) * 8) - start - 1;
126 }
127
reiserfs_journal_params_check(dal_t * dal,blk_t start,blk_t len,int relocated)128 int reiserfs_journal_params_check(dal_t *dal, blk_t start, blk_t len, int relocated) {
129 blk_t max_len;
130
131 ASSERT(dal != NULL, return 0);
132
133 if (!relocated) {
134 blk_t super_blk = (DEFAULT_SUPER_OFFSET / dal_get_blocksize(dal));
135
136 if (start && start != super_blk + 2) {
137 libreiserfs_exception_throw(EXCEPTION_ERROR, EXCEPTION_CANCEL,
138 _("Invalid journal start (%lu) for journal on host device."), start);
139 return 0;
140 }
141 }
142
143 max_len = reiserfs_journal_max_len(dal, start, relocated);
144
145 if (len > max_len) {
146 libreiserfs_exception_throw(EXCEPTION_ERROR, EXCEPTION_CANCEL,
147 _("Journal size is too big (%lu). It must be smaller or equal "
148 "%lu blocks for block size %d."), len, max_len, dal_get_blocksize(dal));
149 return 0;
150 }
151
152 if (len && len < JOURNAL_MIN_SIZE) {
153 libreiserfs_exception_throw(EXCEPTION_ERROR, EXCEPTION_CANCEL,
154 _("Journal size (%lu) is smaller minimal recomended (%lu)."),
155 len, JOURNAL_MIN_SIZE);
156 return 0;
157 }
158
159 return 1;
160 }
161
reiserfs_journal_params_update(reiserfs_journal_params_t * params,blk_t start,blk_t len,blk_t max_trans,uint32_t dev,size_t blocksize)162 void reiserfs_journal_params_update(reiserfs_journal_params_t *params, blk_t start,
163 blk_t len, blk_t max_trans, uint32_t dev, size_t blocksize)
164 {
165
166 ASSERT(params != NULL, return);
167
168 set_jp_start(params, start);
169 set_jp_len(params, len);
170
171 set_jp_max_trans_len(params,
172 reiserfs_journal_max_trans(max_trans, len, blocksize));
173
174 set_jp_magic(params, reiserfs_tools_random());
175 set_jp_max_batch(params, max_trans * JOURNAL_MAX_BATCH/JOURNAL_MAX_TRANS);
176
177 set_jp_max_commit_age(params, JOURNAL_MAX_COMMIT_AGE);
178 set_jp_max_trans_age(params, JOURNAL_MAX_TRANS_AGE);
179
180 set_jp_dev(params, dev);
181 }
182
reiserfs_journal_pipe(reiserfs_journal_t * journal,blk_t from,reiserfs_journal_pipe_func_t pipe_func,void * data)183 int reiserfs_journal_pipe(reiserfs_journal_t *journal, blk_t from,
184 reiserfs_journal_pipe_func_t pipe_func, void *data)
185 {
186 blk_t start, len, curr;
187 reiserfs_block_t *desc, *comm;
188 blk_t replay_start = get_jh_replay_offset(&journal->head);
189
190 start = get_jp_start(&journal->head.jh_params);
191 len = get_jp_len(&journal->head.jh_params);
192
193 if (from >= len) {
194 libreiserfs_exception_throw(EXCEPTION_ERROR, EXCEPTION_CANCEL,
195 _("Invalid start (%lu) for journal len %lu."), from, len);
196 return 0;
197 }
198
199 for (curr = from; curr < len; curr++) {
200 if (!(desc = reiserfs_block_read(journal->dal, start + curr)))
201 reiserfs_block_reading_failed(start + curr, dal_error(journal->dal), return 0);
202
203 if (!(comm = reiserfs_block_read(journal->dal,
204 reiserfs_journal_desc_comm(&journal->head, desc))))
205 {
206 reiserfs_block_reading_failed(reiserfs_journal_desc_comm(&journal->head, desc),
207 dal_error(journal->dal), goto error_free_desc);
208 }
209
210 if (!reiserfs_journal_desc_valid(&journal->head, desc))
211 goto error_continue;
212
213 if (pipe_func && !pipe_func(journal, desc, comm, curr, data))
214 goto error_free_comm;
215
216 curr += get_jd_desc_trans_len(desc) + 1;
217 error_continue:
218 reiserfs_block_free(comm);
219 reiserfs_block_free(desc);
220 }
221 return 1;
222
223 error_free_comm:
224 libreiserfs_free(comm);
225 error_free_desc:
226 libreiserfs_free(desc);
227 error:
228 return 0;
229 }
230
231 struct reiserfs_read_desc {
232 blk_t needle, found;
233 };
234
callback_journal_read(reiserfs_journal_t * journal,reiserfs_block_t * desc,reiserfs_block_t * comm,uint32_t number,struct reiserfs_read_desc * read_desc)235 static int callback_journal_read(reiserfs_journal_t *journal, reiserfs_block_t *desc,
236 reiserfs_block_t *comm, uint32_t number, struct reiserfs_read_desc *read_desc)
237 {
238 uint32_t i;
239 blk_t trans_half = journal_trans_half(dal_get_blocksize(journal->dal));
240 blk_t len = get_jp_len(&journal->head.jh_params) - 1;
241 blk_t start = get_jp_start(&journal->head.jh_params);
242
243 for (i = 0; i < get_jd_desc_trans_len(desc) && i < trans_half; i++) {
244 if (read_desc->needle == LE32_TO_CPU(get_desc_header(desc)->jd_realblock[i]))
245 read_desc->found = (start + number + i + 1) & len;
246 }
247
248 if (i >= trans_half) {
249 for (; i < get_jd_desc_trans_len(desc); i++) {
250 uint32_t blk = LE32_TO_CPU(get_comm_header(comm)->jc_realblock[i - trans_half]);
251 if (read_desc->needle == blk)
252 read_desc->found = (start + number + i + 1) & len;
253 }
254 }
255
256 return 1;
257 }
258
reiserfs_journal_read(reiserfs_journal_t * journal,blk_t blk)259 reiserfs_block_t *reiserfs_journal_read(reiserfs_journal_t *journal, blk_t blk) {
260 struct reiserfs_read_desc desc;
261
262 ASSERT(journal != NULL, return NULL);
263
264 memset(&desc, 0, sizeof(desc));
265 desc.needle = blk;
266
267 if (!reiserfs_journal_pipe(journal, get_jh_replay_offset(&journal->head),
268 (reiserfs_journal_pipe_func_t)callback_journal_read, &desc))
269 return NULL;
270
271 if (desc.found && desc.found > get_jp_start(&journal->head.jh_params) +
272 get_jp_len(&journal->head.jh_params) - 1)
273 return NULL;
274
275 return desc.found ? reiserfs_block_read(journal->dal, desc.found) : NULL;
276 }
277
reiserfs_journal_open(dal_t * dal,blk_t start,blk_t len,int relocated)278 reiserfs_journal_t *reiserfs_journal_open(dal_t *dal, blk_t start, blk_t len, int relocated) {
279 uint32_t dev;
280 reiserfs_block_t *block;
281 reiserfs_journal_t *journal;
282 reiserfs_journal_params_t *params;
283
284 ASSERT(dal != NULL, return NULL);
285
286 if (!(block = reiserfs_block_read(dal, start + len)))
287 reiserfs_block_reading_failed(start + len, dal_error(dal), goto error);
288
289 /* Checking for journal validness */
290 params = &((reiserfs_journal_head_t *)block->data)->jh_params;
291 libreiserfs_exception_fetch_all();
292 if (!reiserfs_journal_params_check(dal, get_jp_start(params),
293 get_jp_len(params), relocated))
294 {
295 libreiserfs_exception_leave_all();
296 libreiserfs_exception_throw(EXCEPTION_ERROR, EXCEPTION_CANCEL,
297 _("Invalid journal parameters detected."));
298 goto error_free_block;
299 }
300 libreiserfs_exception_leave_all();
301
302 if (get_jh_replay_offset((reiserfs_journal_head_t *)block->data) >= start + len) {
303 libreiserfs_exception_throw(EXCEPTION_ERROR, EXCEPTION_CANCEL,
304 _("Invalid journal parameters detected."));
305 goto error_free_block;
306 }
307
308 if (!(journal = libreiserfs_calloc(sizeof(reiserfs_journal_t), 0)))
309 goto error_free_block;
310
311 memcpy(&journal->head, block->data, sizeof(reiserfs_journal_head_t));
312
313 if (!(dev = dal_stat(dal))) {
314 libreiserfs_exception_throw(EXCEPTION_ERROR, EXCEPTION_CANCEL,
315 _("Couldn't stat journal device."));
316 goto error_free_journal;
317 }
318
319 set_jp_dev(&journal->head.jh_params, dev);
320 reiserfs_block_free(block);
321
322 journal->dal = dal;
323
324 return journal;
325
326 error_free_journal:
327 libreiserfs_free(journal);
328 error_free_block:
329 reiserfs_block_free(block);
330 error:
331 return NULL;
332 }
333
reiserfs_journal_create(dal_t * dal,blk_t start,blk_t len,blk_t max_trans,int relocated)334 reiserfs_journal_t *reiserfs_journal_create(dal_t *dal, blk_t start, blk_t len,
335 blk_t max_trans, int relocated)
336 {
337 uint32_t dev;
338 reiserfs_gauge_t *gauge;
339 reiserfs_segment_t segment;
340 reiserfs_block_t *block;
341 reiserfs_journal_t *journal;
342 reiserfs_journal_params_t *params;
343
344 ASSERT(dal != NULL, return NULL);
345
346 if (!reiserfs_journal_params_check(dal, start, len, relocated))
347 return NULL;
348
349 if (!reiserfs_segment_init(&segment, dal, start, start + len))
350 return NULL;
351
352 if ((gauge = libreiserfs_get_gauge())) {
353 libreiserfs_gauge_reset(gauge);
354 libreiserfs_gauge_set_name(gauge, _("initializing journal"));
355 }
356
357 if (!reiserfs_segment_fill(&segment, 0, (reiserfs_segment_func_t)
358 reiserfs_callback_segment_gauge, gauge))
359 return NULL;
360
361 if (gauge)
362 libreiserfs_gauge_finish(gauge, 1);
363
364 dev = 0;
365 if (relocated) {
366 if (!(dev = dal_stat(dal))) {
367 libreiserfs_exception_throw(EXCEPTION_ERROR, EXCEPTION_CANCEL,
368 _("Can't stat journal device."));
369 return NULL;
370 }
371 }
372
373 if (!(journal = (reiserfs_journal_t *)libreiserfs_calloc(sizeof(*journal), 0)))
374 return NULL;
375
376 reiserfs_journal_params_update(&journal->head.jh_params, start, len, max_trans, dev,
377 dal_get_blocksize(dal));
378
379 if (!(block = reiserfs_block_alloc_with_copy(dal, start + len,
380 (void *)&journal->head)))
381 goto error_free_journal;
382
383 /* Writing journal parameters onto device */
384 if (!reiserfs_block_write(dal, block)) {
385 reiserfs_block_writing_failed(reiserfs_block_get_nr(block),
386 dal_error(dal), goto error_free_block);
387 }
388 reiserfs_block_free(block);
389
390 journal->dal = dal;
391 return journal;
392
393 error_free_block:
394 reiserfs_block_free(block);
395 error_free_journal:
396 libreiserfs_free(journal);
397 error:
398 return NULL;
399 }
400
reiserfs_journal_close(reiserfs_journal_t * journal)401 void reiserfs_journal_close(reiserfs_journal_t *journal) {
402 ASSERT(journal != NULL, return);
403
404 if (journal->cashe.blocks)
405 libreiserfs_free(journal->cashe.blocks);
406
407 libreiserfs_free(journal);
408 }
409
reiserfs_journal_sync(reiserfs_journal_t * journal)410 int reiserfs_journal_sync(reiserfs_journal_t *journal) {
411 reiserfs_block_t *block;
412
413 ASSERT(journal != NULL, return 0);
414
415 if (!(block = reiserfs_block_alloc_with_copy(journal->dal,
416 get_jp_start(&journal->head.jh_params) +
417 get_jp_len(&journal->head.jh_params), (void *)&journal->head)))
418 goto error;
419
420 if (!reiserfs_block_write(journal->dal, block)) {
421 reiserfs_block_writing_failed(reiserfs_block_get_nr(block),
422 dal_error(journal->dal), goto error_free_block);
423 }
424
425 reiserfs_block_free(block);
426 return 1;
427
428 error_free_block:
429 reiserfs_block_free(block);
430 error:
431 return 0;
432 }
433
reiserfs_journal_desc_desc2trans(reiserfs_journal_head_t * head,reiserfs_block_t * desc,reiserfs_journal_trans_t * trans)434 static void reiserfs_journal_desc_desc2trans(reiserfs_journal_head_t *head,
435 reiserfs_block_t *desc, reiserfs_journal_trans_t *trans)
436 {
437 trans->jt_mount_id = get_jd_desc_mount_id(desc);
438 trans->jt_trans_id = get_jd_desc_trans_id(desc);
439 trans->jt_desc_blocknr = reiserfs_block_get_nr(desc);
440 trans->jt_trans_len = get_jd_desc_trans_len(desc);
441 trans->jt_commit_blocknr = reiserfs_journal_desc_comm(head, desc);
442 trans->jt_next_trans_offset = reiserfs_journal_desc_next(head, desc) -
443 get_jp_len(&head->jh_params);
444 }
445
446 struct reiserfs_replay_desc {
447 uint32_t trans;
448 reiserfs_gauge_t *gauge;
449 uint32_t oldest_id, newest_id;
450 reiserfs_journal_trans_t *oldest_tr;
451 reiserfs_journal_trans_t *newest_tr;
452 };
453
callback_journal_replay(reiserfs_journal_t * journal,reiserfs_block_t * desc,reiserfs_block_t * comm,uint32_t number,struct reiserfs_replay_desc * replay_desc)454 static int callback_journal_replay(reiserfs_journal_t *journal, reiserfs_block_t *desc,
455 reiserfs_block_t *comm, uint32_t number, struct reiserfs_replay_desc *replay_desc)
456 {
457 if (replay_desc->gauge) {
458 libreiserfs_gauge_set_value(replay_desc->gauge, (unsigned int)((number * 100) /
459 get_jp_len(&journal->head.jh_params)) + 1);
460 }
461
462 if (!reiserfs_journal_desc_valid(&journal->head, desc)) {
463 reiserfs_block_free(desc);
464 return 1;
465 }
466
467 replay_desc->trans++;
468
469 if (get_jd_desc_trans_id(desc) < replay_desc->oldest_id) {
470 replay_desc->oldest_id = get_jd_desc_trans_id(desc);
471 reiserfs_journal_desc_desc2trans(&journal->head, desc, replay_desc->oldest_tr);
472 }
473
474 if (get_jd_desc_trans_id(desc) > replay_desc->newest_id) {
475 replay_desc->newest_id = get_jd_desc_trans_id(desc);
476 reiserfs_journal_desc_desc2trans(&journal->head, desc, replay_desc->newest_tr);
477 }
478
479 return 1;
480 }
481
reiserfs_journal_boundary_transactions(reiserfs_journal_t * journal,reiserfs_journal_trans_t * oldest,reiserfs_journal_trans_t * newest)482 blk_t reiserfs_journal_boundary_transactions(reiserfs_journal_t *journal,
483 reiserfs_journal_trans_t *oldest, reiserfs_journal_trans_t *newest)
484 {
485 reiserfs_gauge_t *gauge = NULL;
486 struct reiserfs_replay_desc desc;
487
488 desc.oldest_id = 0xffffffff; desc.newest_id = 0x0;
489
490 if (gauge) {
491 libreiserfs_gauge_reset(gauge);
492 libreiserfs_gauge_set_name(gauge, _("looking for transactions"));
493 }
494
495 desc.gauge = gauge; desc.trans = 0;
496
497 if (!reiserfs_journal_pipe(journal, 0,
498 (reiserfs_journal_pipe_func_t)callback_journal_replay, &desc))
499 return 0;
500
501 if (gauge)
502 libreiserfs_gauge_finish(gauge, 1);
503
504 return desc.trans;
505 }
506
507