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