예제 #1
0
/* fills the structure with various parameters of directory entry,
   including key of the pointed object */
static void get_entry_attributes (struct reiserfs_dir_entry * de, int entry_num)
{
#ifdef REISERFS_CHECK
  if (I_ENTRY_COUNT (de->de_ih) < entry_num)
    reiserfs_panic (0, "yr-7006: get_entry_attributes: no such entry (%d-th) in the item (%d)",
		    entry_num, I_ENTRY_COUNT (de->de_ih));
  if (de->de_deh != B_I_DEH (de->de_bh, de->de_ih) + entry_num)
    reiserfs_panic (0, "yr-7008: get_entry_attributes: dir entry header not found");
    
#endif /* REISERFS_CHECK */

  /* few fields are set already (de_bh, de_item_num, de_deh) */
  de->de_entrylen = I_DEH_N_ENTRY_LENGTH (de->de_ih, de->de_deh, entry_num);
  de->de_namelen = de->de_entrylen - (de_with_sd (de->de_deh) ? SD_SIZE : 0);

  de->de_name = B_I_PITEM (de->de_bh, de->de_ih) + de->de_deh->deh_location;

#ifdef REISERFS_ALIGNED
  if ( de->de_name[ de->de_namelen-1 ] == '\0' )
      de->de_namelen = strlen(de->de_name);
#endif

  /* key of object pointed by entry */
  de->de_dir_id = de->de_deh->deh_dir_id;
  de->de_objectid = de->de_deh->deh_objectid;

  /* key of the entry */
  memcpy (&(de->de_entry_key.k_dir_id), &(de->de_ih->ih_key), SHORT_KEY_SIZE);
  de->de_entry_key.k_offset = de->de_deh->deh_offset;
  de->de_entry_key.k_uniqueness = DIRENTRY_UNIQUENESS;

}
예제 #2
0
int is_leaf_bad (struct buffer_head * bh)
{
    int i;
    struct item_head * ih;
    int bad = 0;

    assert (is_leaf_node (bh));

    for (i = 0, ih = B_N_PITEM_HEAD (bh,  0); i < B_NR_ITEMS (bh); i ++, ih ++) {
	if (is_bad_item (bh, ih, B_I_PITEM (bh, ih))) {
	    fsck_log ("is_leaf_bad: block %lu: %d-th item (%H) is bad\n",
		      bh->b_blocknr, i, ih);
	    bad = 1;
	    continue;
	}

	if (i && bad_pair (fs, bh, i)) {
	    fsck_log ("is_leaf_bad: block %luL %d-th item (%H) and "
		      "the next one (%H) are in wrong order\n",
		     bh->b_blocknr, i - 1, ih - 1, ih);
	    bad = 1;
	}
    }

    return bad;
}
예제 #3
0
파일: prints.c 프로젝트: 7799/linux
static int print_leaf(struct buffer_head *bh, int print_mode, int first,
		      int last)
{
	struct block_head *blkh;
	struct item_head *ih;
	int i, nr;
	int from, to;

	if (!B_IS_ITEMS_LEVEL(bh))
		return 1;

	check_leaf(bh);

	blkh = B_BLK_HEAD(bh);
	ih = B_N_PITEM_HEAD(bh, 0);
	nr = blkh_nr_item(blkh);

	printk
	    ("\n===================================================================\n");
	reiserfs_printk("LEAF NODE (%ld) contains %z\n", bh->b_blocknr, bh);

	if (!(print_mode & PRINT_LEAF_ITEMS)) {
		reiserfs_printk("FIRST ITEM_KEY: %k, LAST ITEM KEY: %k\n",
				&(ih->ih_key), &((ih + nr - 1)->ih_key));
		return 0;
	}

	if (first < 0 || first > nr - 1)
		from = 0;
	else
		from = first;

	if (last < 0 || last > nr)
		to = nr;
	else
		to = last;

	ih += from;
	printk
	    ("-------------------------------------------------------------------------------\n");
	printk
	    ("|##|   type    |           key           | ilen | free_space | version | loc  |\n");
	for (i = from; i < to; i++, ih++) {
		printk
		    ("-------------------------------------------------------------------------------\n");
		reiserfs_printk("|%2d| %h |\n", i, ih);
		if (print_mode & PRINT_LEAF_ITEMS)
			op_print_item(ih, B_I_PITEM(bh, ih));
	}

	printk
	    ("===================================================================\n");

	return 0;
}
예제 #4
0
파일: prints.c 프로젝트: 7799/linux
void check_leaf(struct buffer_head *bh)
{
	int i;
	struct item_head *ih;

	if (!bh)
		return;
	check_leaf_block_head(bh);
	for (i = 0, ih = B_N_PITEM_HEAD(bh, 0); i < B_NR_ITEMS(bh); i++, ih++)
		op_check_item(ih, B_I_PITEM(bh, ih));
}
예제 #5
0
// de_bh, de_ih, de_deh (points to first element of array), de_item_num is set
inline void set_de_name_and_namelen(struct reiserfs_dir_entry *de)
{
	struct reiserfs_de_head *deh = de->de_deh + de->de_entry_num;

	BUG_ON(de->de_entry_num >= ih_entry_count(de->de_ih));

	de->de_entrylen = entry_length(de->de_bh, de->de_ih, de->de_entry_num);
	de->de_namelen = de->de_entrylen - (de_with_sd(deh) ? SD_SIZE : 0);
	de->de_name = B_I_PITEM(de->de_bh, de->de_ih) + deh_location(deh);
	if (de->de_name[de->de_namelen - 1] == 0)
		de->de_namelen = strlen(de->de_name);
}
예제 #6
0
/* only directory item can be fatally bad */
static int is_leaf_bad_xx (struct buffer_head * bh)
{
    int i;
    struct item_head * ih;

    if (!is_leaf_node (bh))
	return 0;
    for (i = 0, ih = B_N_PITEM_HEAD (bh,  0); i < B_NR_ITEMS (bh); i ++, ih ++)
	if (is_bad_item (bh, ih, B_I_PITEM (bh, ih))) {
	    return 1;
	}
    return 0;
}
예제 #7
0
/*
 * de_bh, de_ih, de_deh (points to first element of array), de_item_num
 * is set
 */
void
set_de_name_and_namelen(struct reiserfs_dir_entry *de)
{
	struct reiserfs_de_head *deh = de->de_deh + de->de_entry_num;

	if (de->de_entry_num >= ih_entry_count(de->de_ih)) {
		reiserfs_log(LOG_DEBUG, "BUG\n");
		return;
	}

	de->de_entrylen = entry_length(de->de_bp, de->de_ih, de->de_entry_num);
	de->de_namelen  = de->de_entrylen - (de_with_sd(deh) ? SD_SIZE : 0);
	de->de_name     = B_I_PITEM(de->de_bp, de->de_ih) + deh_location(deh);
	if (de->de_name[de->de_namelen - 1] == 0)
		de->de_namelen = strlen(de->de_name);
}
예제 #8
0
/* look for uncompleted unlinks and truncates and complete them */
static void finish_unfinished (struct super_block * s)
{
    INITIALIZE_PATH (path);
    struct cpu_key max_cpu_key, obj_key;
    struct key save_link_key;
    int retval;
    struct item_head * ih;
    struct buffer_head * bh;
    int item_pos;
    char * item;
    int done;
    struct inode * inode;
    int truncate;
 
 
    /* compose key to look for "save" links */
    max_cpu_key.version = KEY_FORMAT_3_5;
    max_cpu_key.on_disk_key = MAX_KEY;
    max_cpu_key.key_length = 3;
 
    done = 0;
    s -> u.reiserfs_sb.s_is_unlinked_ok = 1;
    while (1) {
        retval = search_item (s, &max_cpu_key, &path);
        if (retval != ITEM_NOT_FOUND) {
            reiserfs_warning ("vs-2140: finish_unfinished: search_by_key returned %d\n",
                              retval);
            break;
        }
        
        bh = get_last_bh (&path);
        item_pos = get_item_pos (&path);
        if (item_pos != B_NR_ITEMS (bh)) {
            reiserfs_warning ("vs-2060: finish_unfinished: wrong position found\n");
            break;
        }
        item_pos --;
        ih = B_N_PITEM_HEAD (bh, item_pos);
 
        if (le32_to_cpu (ih->ih_key.k_dir_id) != MAX_KEY_OBJECTID)
            /* there are no "save" links anymore */
            break;
 
        save_link_key = ih->ih_key;
        if (is_indirect_le_ih (ih))
            truncate = 1;
        else
            truncate = 0;
 
        /* reiserfs_iget needs k_dirid and k_objectid only */
        item = B_I_PITEM (bh, ih);
        obj_key.on_disk_key.k_dir_id = le32_to_cpu (*(__u32 *)item);
        obj_key.on_disk_key.k_objectid = le32_to_cpu (ih->ih_key.k_objectid);
	obj_key.on_disk_key.u.k_offset_v1.k_offset = 0;
	obj_key.on_disk_key.u.k_offset_v1.k_uniqueness = 0;
	
        pathrelse (&path);
 
        inode = reiserfs_iget (s, &obj_key);
        if (!inode) {
            /* the unlink almost completed, it just did not manage to remove
	       "save" link and release objectid */
            reiserfs_warning ("vs-2180: finish_unfinished: iget failed for %K\n",
                              &obj_key);
            remove_save_link_only (s, &save_link_key, 1);
            continue;
        }

	if (!truncate && inode->i_nlink) {
	    /* file is not unlinked */
            reiserfs_warning ("vs-2185: finish_unfinished: file %K is not unlinked\n",
                              &obj_key);
            remove_save_link_only (s, &save_link_key, 0);
            continue;
	}

	if (truncate && S_ISDIR (inode->i_mode) ) {
	    /* We got a truncate request for a dir which is impossible.
	       The only imaginable way is to execute unfinished truncate request
	       then boot into old kernel, remove the file and create dir with
	       the same key. */
	    reiserfs_warning("green-2101: impossible truncate on a directory %k. Please report\n", INODE_PKEY (inode));
	    remove_save_link_only (s, &save_link_key, 0);
	    truncate = 0;
	    iput (inode); 
	    continue;
	}
 
        if (truncate) {
            inode -> u.reiserfs_i.i_flags |= i_link_saved_truncate_mask;
            /* not completed truncate found. New size was committed together
	       with "save" link */
            reiserfs_warning ("Truncating %k to %Ld ..",
                              INODE_PKEY (inode), inode->i_size);
            reiserfs_truncate_file (inode, 0/*don't update modification time*/);
            remove_save_link (inode, truncate);
        } else {
            inode -> u.reiserfs_i.i_flags |= i_link_saved_unlink_mask;
            /* not completed unlink (rmdir) found */
            reiserfs_warning ("Removing %k..", INODE_PKEY (inode));
            /* removal gets completed in iput */
        }
 
        iput (inode);
        printk ("done\n");
        done ++;
    }
    s -> u.reiserfs_sb.s_is_unlinked_ok = 0;
     
    pathrelse (&path);
    if (done)
        reiserfs_warning ("There were %d uncompleted unlinks/truncates. "
                          "Completed\n", done);
}
예제 #9
0
/* FIXME: we can improve fixing of broken keys: we can ssfe direct items which
   go after stat data and have broken keys */
static void pass0_correct_leaf (reiserfs_filsys_t fs,
				struct buffer_head * bh)
{
    int i, j;
    struct item_head * ih;
    __u32 * ind_item;
    unsigned long unfm_ptr;
    int dirty = 0;

 start_again:

    ih = B_N_PITEM_HEAD (bh, 0);
    for (i = 0; i < node_item_number (bh); i ++, ih ++) {
	if (ih->ih_key.k_dir_id == 0 || ih->ih_key.k_objectid == 0) {
	    /* sometimes stat datas get k_objectid==0 or k_dir_id==0 */
	    if (i == (node_item_number (bh) - 1)) {
		/* */
		if (i == 0) {
		    fsck_log ("block %lu: item %d: (%H) is alone in the block\n",
			      bh->b_blocknr, i, ih);
		    return;
		}
		/* delete last item */
		delete_item (fs, bh, i - 1);
		return;
	    }

	    /* there is next item: if it is not stat data - take its k_dir_id
               and k_objectid. if key order will be still wrong - the changed
               item will be deleted */
	    if (!is_stat_data_ih (ih + 1)) {
		fsck_log ("block %lu: item %d: (%H) fixed to ", bh->b_blocknr, i, ih);
		ih->ih_key.k_dir_id = (ih + 1)->ih_key.k_dir_id;
		ih->ih_key.k_objectid = (ih + 1)->ih_key.k_objectid;
		set_offset (KEY_FORMAT_1, &ih->ih_key, 0);
		set_type (KEY_FORMAT_1, &ih->ih_key, TYPE_STAT_DATA);
		fsck_log ("(%H)\n", ih);
		dirty = 1;
	    } else if (i == 0) {
		delete_item (fs, bh, i);
		goto start_again;
	    }
	}

	/* this recovers corruptions like the below: 
	   1774 1732 0 0
	   116262638 1732 1 3
	   1774 1736 0 0 */
	if (i && is_stat_data_ih (ih - 1) && !is_stat_data_ih (ih)) {
	    if (ih->ih_key.k_objectid != (ih - 1)->ih_key.k_objectid ||
		ih->ih_key.k_dir_id != (ih - 1)->ih_key.k_dir_id ||
		get_offset (&ih->ih_key) != 1) {
		if (is_direntry_ih (ih)) {
		    fsck_log ("block %lu: item %d: no \".\" entry found in "
			      "the first item of a directory\n", bh->b_blocknr, i);
		} else {
		    fsck_log ("block %lu: item %d: (%H) fixed to ", 
			  bh->b_blocknr, i, ih);
		    ih->ih_key.k_dir_id = (ih - 1)->ih_key.k_dir_id;
		    ih->ih_key.k_objectid = (ih - 1)->ih_key.k_objectid;
		    
		    if (ih_item_len (ih - 1) == SD_SIZE) {
			/* stat data is new, therefore this item is new too */
			set_offset (KEY_FORMAT_2, &(ih->ih_key), 1);
			if (ih_entry_count (ih) != 0xffff)
			    set_type (KEY_FORMAT_2, &(ih->ih_key), TYPE_INDIRECT);
			else
			    set_type (KEY_FORMAT_2, &(ih->ih_key), TYPE_DIRECT);
			set_ih_key_format (ih, KEY_FORMAT_2);
		    } else {
			/* stat data is old, therefore this item is old too */
			set_offset (KEY_FORMAT_1, &(ih->ih_key), 1);
			if (ih_entry_count (ih) != 0xffff)
			    set_type (KEY_FORMAT_1, &(ih->ih_key), TYPE_INDIRECT);
			else
			    set_type (KEY_FORMAT_1, &(ih->ih_key), TYPE_DIRECT);
			set_ih_key_format (ih, KEY_FORMAT_1);
		    }
		    fsck_log ("%H\n", ih);
		    dirty = 1;
		}
	    }
	}

	/* FIXME: corruptions like:
	   56702 66802 1 2
	   56702 65536 0 0
	   56702 66803 1 2
	   do not get recovered (both last items will be deleted) */
	/* delete item if it is not in correct order of object items */
	if (i && not_of_one_file (&ih->ih_key, &(ih - 1)->ih_key) &&
	    !is_stat_data_ih (ih)) {
	    fsck_log ("block %lu: item %d: %H follows non stat item %H - deleted\n",
		      bh->b_blocknr, i, ih, ih - 1);
	    delete_item (fs, bh, i);
	    goto start_again;
	}

	if (i &&  comp_keys (&(ih - 1)->ih_key, &ih->ih_key) != -1) {
	    /* previous item has key not smaller than the key of currect item */
	    if (is_stat_data_ih (ih - 1) && !is_stat_data_ih (ih)) {
		/* fix key of stat data such as if it was stat data of that item */
		fsck_log ("pass0: block %lu: %d-th item %k is out of order, made a stat data of %d-th (%k)\n",
			  bh->b_blocknr, i - 1, &(ih - 1)->ih_key, i, &ih->ih_key);
		(ih - 1)->ih_key.k_dir_id = ih->ih_key.k_dir_id;
		(ih - 1)->ih_key.k_objectid = ih->ih_key.k_objectid;
		set_offset (KEY_FORMAT_1, &(ih - 1)->ih_key, 0);
		set_type (KEY_FORMAT_1, &(ih - 1)->ih_key, TYPE_STAT_DATA);
		dirty = 1;
	    } else {
		/* ok, we have to delete one of these two - decide which one */
		int retval;

		/* something will be deleted */
		dirty = 1;
		retval = upper_correct (bh, ih - 1, i - 1);
		switch (retval) {
		case 0:
		    /* delete upper item */
		    fsck_log ("pass0: block %lu: %d-th (upper) item (%k) is out of order, deleted\n",
			      bh->b_blocknr, i - 1, &(ih - 1)->ih_key);
		    delete_item (fs, bh, i - 1);
		    goto start_again;

		case 1:
		    /* delete lower item */
		    fsck_log ("pass0: block %lu: %d-th (lower) item (%k) is out of order, deleted\n",
			      bh->b_blocknr, i, &ih->ih_key);
		    delete_item (fs, bh, i);
		    goto start_again;

		default:
		    /* upper item was the first item of a node */
		}

		retval = lower_correct (bh, ih, i);
		switch (retval) {
		case 0:
		    /* delete lower item */
		    fsck_log ("pass0: block %lu: %d-th (lower) item (%k) is out of order, deleted\n",
			      bh->b_blocknr, i, &ih->ih_key);
		    delete_item (fs, bh, i);
		    goto start_again;

		case 1:
		    /* delete upper item */
		    fsck_log ("pass0: block %lu: %d-th (upper) item (%k) is out of order, deleted\n",
			      bh->b_blocknr, i - 1, &(ih - 1)->ih_key);
		    delete_item (fs, bh, i - 1);
		    goto start_again;

		default:
		    /* there wer only two items in a node, so we could not
                       decide what to delete, go and ask user */
		}
		fsck_log ("pass0: which of these items looks better (other will be deleted)?\n"
			  "%H\n%H\n", ih - 1, ih);
		if (fsck_user_confirmed (fs, "1 or 2?", "1\n", 1))
		    delete_item (fs, bh, i - 1);
		else
		    delete_item (fs, bh, i);
		goto start_again;
	    }
	}

	if (is_stat_data_ih (ih) && (ih_item_len (ih) != SD_SIZE &&
				     ih_item_len (ih) != SD_V1_SIZE)) {
	    fsck_log ("pass0: block %lu, stat data of wrong length %H - deleted\n",
		      bh, ih);
	    delete_item (fs, bh, i);
	    goto start_again;
	}

	dirty += correct_key_format (ih);

	if (is_stat_data_ih (ih)) {
	    ;/*correct_stat_data (fs, bh, i);*/
	}

	if (is_direntry_ih (ih)) {
	    verify_directory_item (fs, bh, i);
	    continue;
	}

	if (!is_indirect_ih (ih))
	    continue;
	
	ind_item = (__u32 *)B_I_PITEM (bh, ih);
	for (j = 0; j < I_UNFM_NUM (ih); j ++) {
	    unfm_ptr = le32_to_cpu (ind_item [j]);
	    if (!unfm_ptr)
		continue;
	    
	    if (fsck_mode (fs) == FSCK_ZERO_FILES) {
		/* FIXME: this is temporary mode of fsck */
		ind_item [j] = 0;
		reiserfs_bitmap_clear_bit (fsck_new_bitmap(fs), unfm_ptr);
		tmp_zeroed ++;
		dirty = 1;
		continue;
	    }

	    if (not_data_block (fs, unfm_ptr) || /* journal area or bitmap or super block */
		unfm_ptr >= SB_BLOCK_COUNT (fs)) {/* garbage in pointer */

		stats (fs)->wrong_pointers ++;
		/*
		fsck_log ("pass0: %d-th pointer (%lu) in item %k (leaf block %lu) is wrong\n",
			  j, unfm_ptr, &ih->ih_key, bh->b_blocknr);
		*/
		ind_item [j] = 0;
		dirty = 1;
		continue;
	    }
#if 0
	    if (!was_block_used (unfm_ptr)) {
	      /* this will get to a pool of allocable blocks */
	      ind_item [j] = 0;
	      dirty = 1;
	      stat_wrong_pointer_found (fs);
	      continue;
	    }
#endif
	    /* mark block in bitmaps of unformatted nodes */
	    register_unfm (unfm_ptr);
	}
    }

    /* mark all objectids in use */
    ih = B_N_PITEM_HEAD (bh, 0);
    for (i = 0; i < node_item_number (bh); i ++, ih ++) {
	mark_objectid_really_used (proper_id_map (fs), le32_to_cpu (ih->ih_key.k_dir_id));
	mark_objectid_really_used (proper_id_map (fs), le32_to_cpu (ih->ih_key.k_objectid));
    }

    if (node_item_number (bh) < 1) {
	/* pass 1 will skip this */
	stats(fs)->all_contents_removed ++;
	fsck_log ("pass0: block %lu got all items deleted\n",
		  bh->b_blocknr);
    } else {
	/* pass1 will use this bitmap */
	pass0_mark_leaf (bh->b_blocknr);

    }
    if (dirty) {
	stats(fs)->leaves_corrected ++;
	mark_buffer_dirty (bh);
    }
}


static int is_bad_sd (struct item_head * ih, char * item)
{
    struct stat_data * sd = (struct stat_data *)item;

    if (le32_to_cpu(ih->ih_key.u.k_offset_v1.k_offset) || le32_to_cpu(ih->ih_key.u.k_offset_v1.k_uniqueness)) {
	reiserfs_warning (stderr, "Bad SD? %H\n", ih);
	return 1;
    }

    if (ih_item_len (ih) == SD_V1_SIZE) {
	/* looks like old stat data */
	if (ih_key_format (ih) != KEY_FORMAT_1)
	    fsck_log ("item %H has wrong format\n", ih);
	return 0;
    }

    if (!S_ISDIR (sd_v2_mode(sd)) && !S_ISREG(sd_v2_mode(sd)) &&
	!S_ISCHR (sd_v2_mode(sd)) && !S_ISBLK(sd_v2_mode(sd)) &&
	!S_ISLNK (sd_v2_mode(sd)) && !S_ISFIFO(sd_v2_mode(sd)) &&
	!S_ISSOCK(sd_v2_mode(sd))) {	
	/*fsck_log ("file %k unexpected mode encountered 0%o\n", &ih->ih_key, sd_v2_mode(sd))*/;
    }
    return 0;
}


int is_bad_directory (struct item_head * ih, char * item, int dev, int blocksize)
{
    int i;
    char * name;
    int namelen, entrylen;
    struct reiserfs_de_head * deh = (struct reiserfs_de_head *)item;
    __u32 prev_offset = 0;
    __u16 prev_location = ih_item_len (ih);
    int min_entry_size = 1;/* we have no way to understand whether the
                              filesystem were created in 3.6 format or
                              converted to it. So, we assume that minimal name
                              length is 1 */

    if (ih_item_len (ih) / (DEH_SIZE + min_entry_size) < ih_entry_count (ih))
	/* entry count is too big */
	return 1;

    for (i = 0; i < ih_entry_count (ih); i ++, deh ++) {
	entrylen = entry_length(ih, deh, i);
	if (entrylen > REISERFS_MAX_NAME_LEN (blocksize)) {
	    return 1;
	}
	if (deh_offset (deh) <= prev_offset) {
	    return 1;
	}
	prev_offset = deh_offset (deh);

	if (deh_location(deh) + entrylen != prev_location) {
	    return 1;
	}
	prev_location = deh_location (deh);

	namelen = name_length (ih, deh, i);
	name = name_in_entry (deh, i);
	if (!is_properly_hashed (fs, name, namelen, deh_offset (deh))) {
	    return 1;
	}
    }
    return 0;
}


/* change incorrect block adresses by 0. Do not consider such item as incorrect */
static int is_bad_indirect (struct item_head * ih, char * item, int dev, int blocksize)
{
    int i;
    int bad = 0;
    int blocks;

    if (ih_item_len(ih) % UNFM_P_SIZE) {
	fsck_log ("is_bad_indirect: indirect item of %H of invalid length\n", ih);
	return 1;
    }

    blocks = SB_BLOCK_COUNT (fs);
  
    for (i = 0; i < I_UNFM_NUM (ih); i ++) {
	__u32 * ind = (__u32 *)item;

	if (le32_to_cpu (ind[i]) >= blocks) {
	    bad ++;
	    fsck_log ("is_bad_indirect: %d-th pointer of item %H looks bad (%lu)\n",
		      i, ih, le32_to_cpu (ind [i]));
	    continue;
	}
    }
    return bad;
}
예제 #10
0
/* check directory item and try to recover something */
static int verify_directory_item (reiserfs_filsys_t fs, struct buffer_head * bh,
				  int item_num)
{
    struct item_head * ih;
    struct item_head tmp;
    char * item;
    struct reiserfs_de_head * deh;
    char * name;
    int name_len;
    int bad;
    int i, j;
#if 0
    int bad_entries; /* how many bad neighboring entries */
    int total_entry_len;
    char * entries, * end;
#endif
    int dirty;
    int entry_count;
    int hash_code;
    int bad_locations;

#ifdef DEBUG_VERIFY_DENTRY
    char * direntries;
#endif


    ih = B_N_PITEM_HEAD (bh, item_num);
    item = B_I_PITEM (bh,ih);
    deh = (struct reiserfs_de_head *)item;

    dirty = 0;
    bad_locations = 0;
    entry_count = ih_entry_count (ih);


    /* check deh_location */
    for (i = 0; i < ih_entry_count (ih); i ++) {
	/* silently fix deh_state */
	if (deh [i].deh_state != (1 << DEH_Visible)) {
	    deh [i].deh_state = cpu_to_le16 (1 << DEH_Visible);
	    mark_buffer_dirty (bh);
	}
	if (dir_entry_bad_location (deh + i, ih, !i))
	    mark_de_bad_location (deh + i);
    }

#ifdef DEBUG_VERIFY_DENTRY
    direntries = getmem (ih_entry_count (ih) * sizeof (int));

    printf ("entries with bad locations: ");
    for (i = 0; i < ih_entry_count (ih); i ++) {
	if (de_bad_location (deh + i))
	    printf ("%d ", i);
    }
    printf ("\n");
#endif /* DEBUG_VERIFY_DENTRY */


    /* find entries names in which have mismatching deh_offset */
    for (i = ih_entry_count (ih) - 1; i >= 0; i --) {
	if (de_bad (deh + i))
	    /* bad location */
	    continue;

	if (i) {
	    if (deh_location (deh + i - 1) < deh_location (deh + i))
		mark_de_bad_location (deh + i - 1);
	}

	name = name_in_entry (deh + i, i);
	/* we found a name, but we not always we can get its length as
           it depends on deh_location of previous entry */
	name_len = try_to_get_name_length (ih, deh + i, i);

#ifdef DEBUG_VERIFY_DENTRY
	if (name_len == 0)
	    printf ("trying to find name length for %d-th entry\n", i);
#endif /* DEBUG_VERIFY_DENTRY */
	if (is_dot (name, name_len)) {
	    if (i != 0)
		fsck_log ("block %lu: item %d: \".\" is %d-th entry\n",
			  bh->b_blocknr, item_num, i);
	    /* check and fix "." */
	    
	    if (deh_offset (deh + i) != DOT_OFFSET) {
		set_deh_offset(&(deh[i]), DOT_OFFSET);
		mark_buffer_dirty (bh);
	    }
	    /* "." must point to the directory it is in */
	    if (not_of_one_file (&(deh[i].deh_dir_id), &(ih->ih_key))) { /* endian safe */
		fsck_log ("verify_direntry: block %lu, item %H has entry \".\" "
			  "pointing to (%K) instead of (%K)\n", 
			  bh->b_blocknr, ih,
			  &(deh[i].deh_dir_id), &(ih->ih_key));
		deh[i].deh_dir_id = ih->ih_key.k_dir_id; /* both LE */
		deh[i].deh_objectid = ih->ih_key.k_objectid; /* both LE */
		mark_buffer_dirty (bh);
	    }
	} else if (is_dot_dot (name, name_len)) {
	    if (i != 1)
		fsck_log ("block %lu: item %d: \"..\" is %d-th entry\n",
			  bh->b_blocknr, item_num, i);
	    
	    /* check and fix ".." */
	    if (deh_offset (deh + i) != DOT_DOT_OFFSET)
		set_deh_offset(&(deh[i]), DOT_DOT_OFFSET);
	} else {
	    int min_length, max_length;

	    /* check other name */

	    if (name_len == 0) {
		/* we do not know the length of name - we will try to find it */
		min_length = 1;
		max_length = item + ih_item_len (ih) - name;
	    } else
		/* we kow name length, so we will try only one name length */
		min_length = max_length = name_len;

	    for (j = min_length; j <= max_length; j ++) {
		hash_code = find_hash_in_use (name, j,
					      GET_HASH_VALUE (deh_offset (deh + i)),
					      rs_hash (fs->s_rs));
		add_hash_hit (fs, hash_code);
		if (code2func (hash_code) != 0) {
		    /* deh_offset matches to some hash of the name */
		    if (!name_len) {
			fsck_log ("pass0: block %lu, item %H: entry %d. found a name \"%.*s\" "
				  "matching to deh_offset %u. FIXME: should set deh_location "
				  "of previous entry (not ready)\n",
				  bh->b_blocknr, ih, i, j, name, deh_offset (deh + i));
			/* FIXME: if next byte is 0 we think that the name is aligned to 8 byte boundary */
			if (i) {
			    set_deh_location( &(deh[i - 1]),
                                deh_location (deh + i) +
                                ((name[j] || SB_VERSION (fs) ==
                                REISERFS_VERSION_1) ? j : ROUND_UP (j)));
			    mark_de_good_location (deh + i - 1);
			    mark_buffer_dirty (bh);
			}
		    }
		    break;
		}
	    }
	    if (j == max_length + 1) {
		/* deh_offset does not match to anything. it will be
		   deleted for now, but maybe we could just fix a
		   deh_offset if it is in ordeer */
		mark_de_bad_offset (deh + i);
	    }
	}
    } /* for */



#if 0
    /* find entries names in which have mismatching deh_offset */
    for (i = 0; i < ih_entry_count (ih); i ++) {
	if (de_bad (deh + i))
	    /* bad location */
	    continue;

	name = name_in_entry (deh + i, i);
	/* we found a name, but we not always we can get its length as
           it depends on deh_location of previous entry */
	name_len = try_to_get_name_length (ih, deh + i, i);

	if (i == 0 && is_dot (name, name_len)) {
	    
	    /* check and fix "." */
	    
	    if (deh_offset (deh + i) != DOT_OFFSET) {
		deh[i].deh_offset = cpu_to_le32 (DOT_OFFSET);
	    }
	    /* "." must point to the directory it is in */
	    if (not_of_one_file (&(deh[i].deh_dir_id), &(ih->ih_key))) {
		fsck_log ("verify_direntry: block %lu, item %H has entry \".\" "
			  "pointing to (%K) instead of (%K)\n", 
			  bh->b_blocknr, ih,
			  &(deh[i].deh_dir_id), &(ih->ih_key));
		deh[i].deh_dir_id = ih->ih_key.k_dir_id; /* both 32 bit LE */
		deh[i].deh_objectid = ih->ih_key.k_objectid; /* both 32 bit LE */
		mark_buffer_dirty (bh);
	    }
	} else if (i == 1 && is_dot_dot (name, name_len)) {
	    
	    /* check and fix ".." */

	    if (deh_offset (deh + i) != DOT_DOT_OFFSET)
		deh[i].deh_offset = cpu_to_le32 (DOT_DOT_OFFSET);
	} else {
	    int min_length, max_length;

	    /* check other name */

	    if (name_len == 0) {
		/* we do not know the length of name - we will try to find it */
		min_length = 1;
		max_length = item + ih_item_len (ih) - name;
	    } else
		/* we kow name length, so we will try only one name length */
		min_length = max_length = name_len;

	    for (j = min_length; j <= max_length; j ++) {
		hash_code = find_hash_in_use (name, j,
					      GET_HASH_VALUE (deh_offset (deh + i)),
					      rs_hash (fs->s_rs));
		add_hash_hit (fs, hash_code);
		if (code2func (hash_code) != 0) {
		    /* deh_offset matches to some hash of the name */
		    if (!name_len) {
			fsck_log ("pass0: block %lu, item %H: entry %d. found a name \"%.*s\" "
				  "matching to deh_offset %u. FIXME: should set deh_location "
				  "of previous entry (not ready)\n",
				  bh->b_blocknr, ih, i, j, name, deh_offset (deh + i));
			/* FIXME: if next byte is 0 we think that the name is aligned to 8 byte boundary */
			deh[i - 1].deh_location = cpu_to_le16 (deh_location (deh + i) +
							       ((name[j] || SB_VERSION (fs) == REISERFS_VERSION_1) ? j : ROUND_UP (j)));
		    }
		    break;
		}
	    }
	    if (j == max_length + 1) {
		/* deh_offset does not match to anything. it will be
		   deleted for now, but maybe we could just fix a
		   deh_offset if it is in ordeer */
		mark_de_bad_offset (deh + i);
	    }
	}
   }
 #endif

 #ifdef DEBUG_VERIFY_DENTRY
     printf ("entries with mismatching deh_offsets: ");
     for (i = 0; i < ih_entry_count (ih); i ++) {
       if (de_bad_offset (deh + i))
           printf ("%d ", i);
     }
     printf ("\n");
 #endif /* DEBUG_VERIFY_DENTRY */


     /* correct deh_locations such that code cutting entries will not get
        screwed up */
     {
       int prev_loc;
       int loc_fixed;


       prev_loc = ih_item_len (ih);
       for (i = 0; i < ih_entry_count (ih); i ++) {
           loc_fixed = 0;
           if (de_bad_location (deh + i)) {
               set_deh_location(&(deh[i]), prev_loc/* - 1*/);
               mark_buffer_dirty (bh);
               loc_fixed = 1;
           } else {
               if (deh_location (deh + i) >= prev_loc) {
                   set_deh_location(&(deh[i]), prev_loc/* - 1*/);
                   mark_buffer_dirty (bh);
                   loc_fixed = 1;
               }
           }

           prev_loc = deh_location (deh + i);

           if (i == ih_entry_count (ih) - 1) {
               /* last entry starts right after an array of dir entry headers */
               if (!de_bad (deh + i) &&
                   deh_location (deh + i) != (DEH_SIZE * ih_entry_count (ih))) {

                   /* free space in the directory item */
                   fsck_log ("verify_direntry: block %lu, item %H has free
pace\n",
                             bh->b_blocknr, ih);
                   cut_entry (fs, bh, item_num, ih_entry_count (ih), 0);
               }
               if (deh_location (deh + i) != (DEH_SIZE * ih_entry_count (ih)))
               {

                   set_deh_location(&(deh[i]), DEH_SIZE * ih_entry_count (ih));
                   loc_fixed = 1;
                   mark_buffer_dirty (bh);
               }
           }

 #ifdef DEBUG_VERIFY_DENTRY
           if (loc_fixed)
               direntries [i] = 1;
 #endif
       } /* for */

 #ifdef DEBUG_VERIFY_DENTRY
       printf ("entries with fixed deh_locations: ");
       for (i = 0; i < ih_entry_count (ih); i ++) {
           if (direntries [i])
               printf ("%d ", i);
       }
       printf ("\n");
 #endif /* DEBUG_VERIFY_DENTRY */

     }

 #ifdef DEBUG_VERIFY_DENTRY
     printf (" N  location name\n");
     for (i = 0; i < ih_entry_count (ih); i ++) {
       if (de_bad (deh + i) ||
           (i && de_bad (deh + i - 1)) || /* previous entry marked bad */
           (i < ih_entry_count (ih) - 1 && de_bad (deh + i + 1))) { /* next
ntry is marked bad */
           /* print only entries to be deleted and their nearest neighbors */
           printf ("%3d: %8d ", i, deh_location (deh + i));
           if (de_bad (deh + i))
               printf ("will be deleted\n");
           else
               printf ("\"%.*s\"\n", name_length (ih, deh + i, i),
                       name_in_entry (deh + i, i));
       }
     }
 #endif

     bad = 0;
     tmp = *ih;

     /* delete entries which are marked bad */
     for (i = 0; i < ih_entry_count (ih); i ++) {
       deh = B_I_DEH (bh, ih) + i;
       if (de_bad (deh)) {
           bad ++;
           if (ih_entry_count (ih) == 1) {
               delete_item (fs, bh, item_num);
               break;
           } else {
               cut_entry (fs, bh, item_num, i, 1);
           }
	   i --;
	}
    }
    
    if (bad == ih_entry_count (&tmp)) {
	fsck_log ("pass0: block %lu, item %H - all entries were deleted\n", bh->b_blocknr, &tmp);
	return 0;
    }

    deh = B_I_DEH (bh, ih);
    if (get_offset (&ih->ih_key) != deh_offset (deh)) {
	fsck_log ("verify_direntry: block %lu, item %H:  k_offset and deh_offset %u mismatched\n",
		  bh->b_blocknr, ih, deh_offset (deh));
	set_offset (KEY_FORMAT_1, &ih->ih_key, deh_offset (deh));
	mark_buffer_dirty (bh);
    }
    
    if (bad)
	fsck_log ("pass0: block %lu, item %H: %d entries were deleted of \n",
		  bh->b_blocknr, &tmp, bad);
	
    return 0;

#if 0

    /* FIXME: temporary */
    if (bad_locations > ih_entry_count (ih) / 2) {
	fsck_log ("pass0: block %u: item %d (%H) had too bad directory - deleted\n",
		  bh->b_blocknr, item_num, ih);
	delete_item (fs, bh, item_num);
	return 0;
    }

    if (!dirty)
	return 0;
    
    /* something is broken */

    fsck_log ("pass0: block %lu: %d-th item (%H) has %d bad entries..",
	      bh->b_blocknr, item_num, ih, dirty);

    if (get_offset (&ih->ih_key) == DOT_OFFSET) {
	/* first item of directory - make sure that "." and ".." are in place */
	if (deh_offset (deh) != DOT_OFFSET || name_in_entry (deh, 0)[0] != '.') {
	    set_deh_offset(deh, DOT_OFFSET);
	    name_in_entry (deh, 0)[0] = '.';
	}
	if (deh_offset (deh + 1) != DOT_DOT_OFFSET ||
	    name_in_entry (deh + 1, 1)[0] != '.' || name_in_entry (deh + 1, 1)[1] != '.') {
	    set_deh_offset((deh + 1), DOT_DOT_OFFSET);
	    name_in_entry (deh + 1, 1)[0] = '.';
	    name_in_entry (deh + 1, 1)[1] = '.';
	}
    }

    end = item + ih_item_len (ih);
    deh += ih_entry_count (ih);
    entries = (char *)deh;
    total_entry_len = ih_item_len (ih) - DEH_SIZE * ih_entry_count (ih);
    i = ih_entry_count (ih);

    bad_entries = 0;
    do {
	i --;
	deh --;
	name_len = prob_name (fs, &entries, total_entry_len, deh_offset (deh));
	if (!name_len) {
	    if (!bad_entries) {
                set_deh_location(deh, entries - item);
	    } else {
                set_deh_location(deh, deh_location((deh + 1)) + 1 );
	    }
	    bad_entries ++;
	    
	    /*fsck_log ("verify_directory_item: entry %d: in string \'%s\' there is no substring matching hash %ld\n",
	      i, bad_name (entries, total_entry_len), masked_offset);*/
	    mark_de_bad (deh);
	    continue;
	}
	bad_entries = 0;
	/*fsck_log ("verify_directory_item: entry %d: found \"%s\" name matching hash %ld\n",
	  i, bad_name (entries, name_len), masked_offset);*/
	
	/* 'entries' points now to the name which match given offset -
           so, set deh_location */
        set_deh_location(deh, entries - item);
	deh->deh_state = 0;
	mark_de_visible (deh);
	
	entries += name_len;
	total_entry_len = end - entries;
	/* skip padding zeros */
	while (!*entries) {
	    entries ++;
	    total_entry_len --;
	}
	/* 'entries' points now at the place where next (previous)
           entry should start */
    } while ((char *)deh != item);
    
    
    /* fixme: this will not work if all entries are to be deleted */
    for (i = 0; i < ih_entry_count (ih); i ++, deh ++) {
	deh = (struct reiserfs_de_head *)B_I_PITEM (bh, ih) + i;
	if (de_bad (deh)) {
	    if (ih_entry_count (ih) == 1) {
		delete_item (fs, bh, i);
		break;
	    } else {
		cut_entry (fs, bh, item_num, i);
	    }
	    i --;
	}
/*
  fsck_log ("verify_directory_item: %d-th entry is to be deleted: "
  "\"%s\" does not match to hash %lu\n", 
  i, bad_name (name_in_entry (deh, i), name_length (ih, deh, i)),
  deh_offset (deh));
*/
    }
    
    fsck_log ("%d entries were deleted\n", entry_count - ih_entry_count (ih));
    mark_buffer_dirty (bh);

    
    return 0;

#endif
}
예제 #11
0
/* recursive function processing all tree nodes */
static unsigned long move_formatted_block(unsigned long block, unsigned long bnd, int h)
{
	struct buffer_head * bh;
	struct item_head *ih;
	unsigned long new_blocknr = 0;
	int node_is_internal = 0;
	int i, j;
	
	bh = bread(fs->s_dev, block, fs->s_blocksize);
	
	if (is_leaf_node (bh)) {
		
		leaf_node_cnt++;
		
		for (i=0; i < B_NR_ITEMS(bh); i++) {
			ih = B_N_PITEM_HEAD(bh, i);
			if (is_indirect_ih(ih)) {
				__u32 * indirect;

				indirect = (__u32 *)B_I_PITEM (bh, ih);
				for (j = 0; j < I_UNFM_NUM(ih); j++) {
					unsigned long  unfm_block;

					if (indirect [j] == 0) /* hole */
						continue;
					unfm_block = move_unformatted_block(le32_to_cpu (indirect [j]), bnd, h + 1);
					if (unfm_block) {
						indirect [j] = cpu_to_le32 (unfm_block);
						mark_buffer_dirty(bh);
					}
				}
			}	
		}
	} else if (is_internal_node (bh)) { /* internal node */
		
		int_node_cnt++;
		node_is_internal = 1;
		
		for (i=0; i <= B_NR_ITEMS(bh); i++) {
			unsigned long moved_block;
			moved_block = move_formatted_block(B_N_CHILD_NUM(bh, i), bnd, h+1);
			if (moved_block) {
				set_child_block_number (bh, i, moved_block);
				mark_buffer_dirty(bh);
			}
		}	
	} else {
		die ("resize_reiserfs: block (%lu) has invalid format\n", block);
	}
	
	if (buffer_dirty(bh)) {
		mark_buffer_uptodate(bh,1);
		bwrite(bh);
	}
	
	brelse(bh);	
	
	new_blocknr = move_generic_block(block, bnd, h);
	if (new_blocknr) {
		if (node_is_internal)
			int_moved_cnt++;
		else
			leaf_moved_cnt++;
	}
	
	return new_blocknr;
}