| /* |
| * Copyright 1998 Hans Reiser |
| */ |
| /*#include <stdio.h> |
| #include <string.h>*/ |
| /*#include <asm/bitops.h> |
| #include "../include/reiserfs_fs.h" |
| #include "../include/reiserfs_fs_sb.h" |
| #include "../include/reiserfslib.h"*/ |
| #include "fsck.h" |
| |
| |
| /* there is a situation, when we overwrite contents of unformatted |
| node with direct item. One unformatted node can be overwritten |
| several times by direct items */ |
| /* |
| struct overwritten_unfm_segment { |
| int ous_begin; |
| int ous_end; |
| struct overwritten_unfm_segment * ous_next; |
| }; |
| */ |
| struct overwritten_unfm { |
| unsigned long ou_unfm_ptr; /* block number of unfm node */ |
| unsigned long ou_dir_id; |
| unsigned long ou_objectid; /* key corresponding to an unfm node */ |
| unsigned long ou_offset; |
| |
| struct overwritten_unfm_segment * ou_segments; /* list of segmens, than have been overwritten in ths unfm node */ |
| }; |
| |
| struct overwritten_unfm ** g_overwritten_unfms; |
| int g_overwritten_unfms_amount; /* number of unformatted nodes, which contain direct items */ |
| |
| |
| /* adds segment to the single linked list of segments sorted by begin |
| field. Retuns pointer to first element of list */ |
| static struct overwritten_unfm_segment * add_segment (struct overwritten_unfm_segment * first, int begin, int end) |
| { |
| struct overwritten_unfm_segment * new, * next, * prev; |
| |
| new = getmem (sizeof (struct overwritten_unfm_segment)); |
| new->ous_begin = begin; |
| new->ous_end = end; |
| new->ous_next = 0; |
| |
| next = first; |
| prev = 0; |
| while (next) { |
| if (next->ous_begin > begin) |
| break; |
| prev = next; |
| next = next->ous_next; |
| } |
| |
| if (prev == 0) { |
| /* insert into head of list */ |
| first = new; |
| } else { |
| prev->ous_next = new; |
| } |
| new->ous_next = next; |
| return first; |
| } |
| |
| |
| /* input parameter |
| `list_head` - first element of overlapping segments sorted by left edge |
| `unoverwritten_segment` - returned by previous call of get_unoverwritten_segment or (-2,-2) if called first time |
| */ |
| /* returns |
| 1 and segment unoverwritten by elements of list `list_head` |
| 0 if there isno such segment |
| */ |
| int get_unoverwritten_segment (struct overwritten_unfm_segment * list_head, struct overwritten_unfm_segment * unoverwritten_segment) |
| { |
| int end; |
| |
| /* look for segment, which has begin field greater than end of previous interval */ |
| while (list_head->ous_begin <= unoverwritten_segment->ous_end) { |
| list_head = list_head->ous_next; |
| } |
| /* look for the end of the continuous region covered by otrezkami */ |
| end = list_head->ous_end; |
| while (list_head->ous_next) { |
| if (list_head->ous_next->ous_begin > end + 1) |
| /* intreval found */ |
| break; |
| if (list_head->ous_next->ous_end > end) |
| end = list_head->ous_next->ous_end; |
| list_head = list_head->ous_next; |
| } |
| /* ok, between segment and segment->next we have an interval (segment->next != 0) */ |
| if (list_head->ous_next != 0) { |
| unoverwritten_segment->ous_begin = end + 1; |
| unoverwritten_segment->ous_end = list_head->ous_next->ous_begin - 1; |
| return 1; |
| } |
| return 0; |
| } |
| |
| |
| void print_segments (struct overwritten_unfm_segment * list_head) |
| { |
| struct overwritten_unfm_segment * cur; |
| |
| cur = list_head; |
| while (cur) { |
| printf ("%s%d %d%s", cur == list_head ? "(" : "", cur->ous_begin, cur->ous_end, cur->ous_next ? ", " : ")\n"); |
| cur = cur->ous_next; |
| } |
| } |
| |
| |
| /* this prepare list of segments to extracting of unoverwritten segments */ |
| struct overwritten_unfm_segment * find_overwritten_unfm (unsigned long unfm, int length, struct overwritten_unfm_segment * segment_to_init) |
| { |
| int i; |
| |
| for (i = 0; i < g_overwritten_unfms_amount && g_overwritten_unfms[i] != 0; i ++) |
| if (g_overwritten_unfms[i]->ou_unfm_ptr == unfm) { |
| if (g_overwritten_unfms[i]->ou_segments == 0) |
| die ("find_overwritten_unfm: no segment found"); |
| g_overwritten_unfms[i]->ou_segments = add_segment (g_overwritten_unfms[i]->ou_segments, -1, -1); |
| add_segment (g_overwritten_unfms[i]->ou_segments, length, length); |
| segment_to_init->ous_begin = -2; |
| segment_to_init->ous_end = -2; |
| return g_overwritten_unfms[i]->ou_segments; |
| } |
| return 0; |
| } |
| |
| struct overwritten_unfm * look_for_overwritten_unfm (__u32 unfm) |
| { |
| int i; |
| |
| for (i = 0; i < g_overwritten_unfms_amount && g_overwritten_unfms[i] != 0; i ++) |
| if (g_overwritten_unfms[i]->ou_unfm_ptr == unfm) |
| return g_overwritten_unfms[i]; |
| return 0; |
| } |
| |
| #define GROW_BY 10 |
| struct overwritten_unfm * add_overwritten_unfm (unsigned long unfm, struct item_head * direct_ih) |
| { |
| int i; |
| |
| for (i = 0; i < g_overwritten_unfms_amount && g_overwritten_unfms[i] != 0; i ++) { |
| if (g_overwritten_unfms[i]->ou_unfm_ptr == unfm) |
| return g_overwritten_unfms[i]; |
| } |
| |
| if (i == g_overwritten_unfms_amount) { |
| g_overwritten_unfms = expandmem (g_overwritten_unfms, sizeof (struct overwritten_unfm *) * i, |
| sizeof (struct overwritten_unfm *) * GROW_BY); |
| g_overwritten_unfms_amount += GROW_BY; |
| } |
| g_overwritten_unfms[i] = getmem (sizeof (struct overwritten_unfm)); |
| g_overwritten_unfms[i]->ou_unfm_ptr = unfm; |
| g_overwritten_unfms[i]->ou_dir_id = direct_ih->ih_key.k_dir_id; |
| g_overwritten_unfms[i]->ou_objectid = direct_ih->ih_key.k_objectid; |
| g_overwritten_unfms[i]->ou_offset = get_offset(&direct_ih->ih_key) - (get_offset(&direct_ih->ih_key) - 1) % fs->s_blocksize; |
| return g_overwritten_unfms[i]; |
| } |
| |
| |
| void save_unfm_overwriting (unsigned long unfm, struct item_head * direct_ih) |
| { |
| struct overwritten_unfm * ov_unfm; |
| |
| /* add new overwritten unfm or return existing one */ |
| ov_unfm = add_overwritten_unfm (unfm, direct_ih); |
| ov_unfm->ou_segments = add_segment (ov_unfm->ou_segments, (get_offset(&direct_ih->ih_key) - 1) % fs->s_blocksize, |
| (get_offset(&direct_ih->ih_key) - 1) % fs->s_blocksize + ih_item_len (direct_ih) - 1); |
| } |
| |
| |
| void free_overwritten_unfms (void) |
| { |
| int i; |
| |
| for (i = 0; i < g_overwritten_unfms_amount && g_overwritten_unfms[i]; i ++) { |
| /* free all segments */ |
| while (g_overwritten_unfms[i]->ou_segments) { |
| struct overwritten_unfm_segment * tmp; |
| |
| tmp = g_overwritten_unfms[i]->ou_segments->ous_next; |
| freemem (g_overwritten_unfms[i]->ou_segments); |
| g_overwritten_unfms[i]->ou_segments = tmp; |
| } |
| /* free struct overwritten_unfm */ |
| freemem (g_overwritten_unfms[i]); |
| } |
| |
| /* free array of pointers to overwritten unfms */ |
| if (g_overwritten_unfms) |
| freemem (g_overwritten_unfms); |
| } |
| |
| |
| |
| |