Example #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;

}
Example #2
0
/* first calls search_by_key, then, if item is not found looks for the entry inside directory item indicated by
   search_by_key. (We assign a key to each directory item, and place multiple entries in a single directory item.)
   Fills the path to the entry, and to the entry position in the item */
int search_by_entry_key (struct super_block * sb, struct key * key, struct path * path, int * pos_in_item, int * repeat)
{
  /* search for a directory item using key of entry */
  if (search_by_key (sb, key, path, repeat, DISK_LEAF_NODE_LEVEL, READ_BLOCKS) == ITEM_FOUND) {
    *pos_in_item = 0;
    return POSITION_FOUND;
  }
#ifdef REISERFS_CHECK
  if (!PATH_LAST_POSITION (path))
    reiserfs_panic (sb, "vs-7000: search_by_entry_key: search_by_key returned item position == 0");
#endif /* REISERFS_CHECK */
  PATH_LAST_POSITION (path) --;

#ifdef REISERFS_CHECK
  {
    struct item_head * ih = B_N_PITEM_HEAD (PATH_PLAST_BUFFER (path), PATH_LAST_POSITION (path));

    if (!I_IS_DIRECTORY_ITEM (ih) || COMP_SHORT_KEYS (&(ih->ih_key), key)) {
      print_block (PATH_PLAST_BUFFER (path), 0, -1, -1);
      reiserfs_panic (sb, "vs-7005: search_by_entry_key: found item %h is not directory item or "
		      "does not belong to the same directory as key %k", ih, key);
    }
  }
#endif /* REISERFS_CHECK */

  /* binary search in directory item by third component of the key */
  return bin_search_in_dir_item (PATH_PITEM_HEAD (path), B_I_DEH (PATH_PLAST_BUFFER (path), PATH_PITEM_HEAD (path)), key, pos_in_item);
}
Example #3
0
static int reiserfs_find_entry (struct inode * dir, const char * name, int namelen, struct path * path_to_entry, struct reiserfs_dir_entry * de)
{
  struct key key_to_search;
  int repeat;
  int retval;

  if (!dir || !dir->i_sb)
    return POSITION_NOT_FOUND;

  if ((unsigned int)namelen > REISERFS_MAX_NAME_LEN (dir->i_sb->s_blocksize))
    return POSITION_NOT_FOUND;

  /* there are no entries having the same third component of key, so
     fourth key component is not used */
  copy_key (&key_to_search, INODE_PKEY (dir));
  key_to_search.k_offset = get_third_component (name, namelen);
  key_to_search.k_uniqueness = DIRENTRY_UNIQUENESS;

  while (1) {
    /* search for a directory item using the formed key */
    if (search_by_key (dir->i_sb, &key_to_search, path_to_entry, &repeat, DISK_LEAF_NODE_LEVEL, READ_BLOCKS) == ITEM_NOT_FOUND) {
      /* take previous item */
#ifdef REISERFS_CHECK
      if (!PATH_LAST_POSITION (path_to_entry))
	reiserfs_panic (dir->i_sb, "vs-7010: reiserfs_find_entry: search_by_key returned bad position == 0");
#endif /* REISERFS_CHECK */
      PATH_LAST_POSITION (path_to_entry) --;
    }
    
    de->de_bh = PATH_PLAST_BUFFER (path_to_entry);
    de->de_item_num = PATH_LAST_POSITION (path_to_entry);
    de->de_ih = B_N_PITEM_HEAD (de->de_bh, de->de_item_num);
    de->de_deh = B_I_DEH (de->de_bh, de->de_ih);

#ifdef REISERFS_CHECK
    if (!I_IS_DIRECTORY_ITEM (de->de_ih) || COMP_SHORT_KEYS (&(de->de_ih->ih_key), INODE_PKEY (dir)))
      reiserfs_panic (dir->i_sb, "vs-7020: reiserfs_find_entry: item must be an item of the same directory item as inode");
#endif /* REISERFS_CHECK */

    /* we do not check whether bin_search_in_dir_item found the given key, even if so, we still have
       to compare names */
    bin_search_in_dir_item (de->de_ih, de->de_deh, &key_to_search, &(de->de_entry_num));

    /* compare names for all entries having given hash value */
    retval = linear_search_in_dir_item (&key_to_search, de, name, namelen);
    if (retval != GOTO_PREVIOUS_ITEM)
      /* there is no need to scan directory anymore. Given entry found or does not exist */
      return retval;

    /* there is left neighboring item of this directory and given entry can be there */
    key_to_search.k_offset = de->de_ih->ih_key.k_offset - 1;
    pathrelse (path_to_entry);

  } /* while (1) */
}
Example #4
0
static void reiserfsck_check_tree (int dev, int block, int size, check_function_t comp_func)
{
    struct buffer_head * bh;
    int what_node;
    
    bh = bread (dev, block, size);
    if (bh == 0)
        reiserfs_panic("reiserfsck_check_tree: unable to read %lu block on device 0x%x\n",
                block, dev);

    if (!B_IS_IN_TREE (bh)) {
	reiserfs_panic (0, "reiserfsck_check_tree: buffer (%b %z) not in tree", bh, bh);
    }
    
    what_node = who_is_this (bh->b_data, bh->b_size);
    if (what_node != THE_LEAF && what_node != THE_INTERNAL)
	die ("Not formatted node");

    if (!is_block_used (bh->b_blocknr))
	die ("Not marked as used");

    if (is_leaf_node (bh) && is_leaf_bad_xx (bh))
	die ("Bad leaf");

    if (is_internal_node(bh) && is_internal_bad (bh))
	die ("bad internal");
    
    if (is_internal_node (bh)) {
	int i;
	struct disk_child * dc;
	
	dc = B_N_CHILD (bh, 0);
	for (i = 0; i <= B_NR_ITEMS (bh); i ++, dc ++) {
	    reiserfsck_check_tree (dev, dc_block_number(dc), size, comp_func);
	    g_dkey = B_N_PDELIM_KEY (bh, i);
	}
    } else if (is_leaf_node (bh)) {
	g_right = bh;
	if (g_left != 0 && g_dkey != 0) {
	    comp_func ();
	    brelse (g_left);
	}
	g_left = g_right;
	return;
    } else {
	reiserfs_panic ("reiserfsck_check_tree: block %lu has bad block type (%b)",
			bh->b_blocknr, bh);
    }
    brelse (bh);
}
Example #5
0
static void check_leaf_block_head (struct buffer_head * bh)
{
  struct block_head * blkh;
  int nr;

  blkh = B_BLK_HEAD (bh);
  nr = blkh_nr_item(blkh);
  if ( nr > (bh->b_size - BLKH_SIZE) / IH_SIZE)
    reiserfs_panic (0, "vs-6010: check_leaf_block_head: invalid item number %z", bh);
  if ( blkh_free_space(blkh) > 
      bh->b_size - BLKH_SIZE - IH_SIZE * nr )
    reiserfs_panic (0, "vs-6020: check_leaf_block_head: invalid free space %z", bh);
    
}
Example #6
0
static void compare_neighboring_leaves_in_pass1 (void)
{
    struct key * left = B_N_PKEY (g_left, B_NR_ITEMS (g_left) - 1);

    if (comp_keys (left, B_N_PKEY (g_right, 0)) != -1/*SECOND_GREATER*/)
	die ("compare_neighboring_leaves_in_pass1: left key is greater, that the right one");
    
    if (/*comp_keys (B_PRIGHT_DELIM_KEY (g_left), g_dkey) == FIRST_GREATER ||*/
	comp_keys (g_dkey, B_N_PKEY (g_right, 0))) {
	reiserfs_panic (0, "compare_neighboring_leaves_in_pass1: dkey %k, first key in right %k",
			g_dkey, B_N_PKEY (g_right, 0));
    }
    
    check_items (g_left);
    
    /*&&&&&&&&&&&&&&&&&&&&&&&&&&
      for (i = 0, ih = B_N_PITEM_HEAD (g_left, i); i < B_NR_ITEMS (g_left); i ++, ih ++)
      if (is_item_accessed (ih) == YES)
      die ("compare_neighboring_leaves_in_pass1: item marked as accessed in g_left");
      for (i = 0, ih = B_N_PITEM_HEAD (g_right, i); i < B_NR_ITEMS (g_right); i ++, ih ++)
      if (is_item_accessed (ih) == YES)
      die ("compare_neighboring_leaves_in_pass1: item marked as accessed in g_right");
      &&&&&&&&&&&&&&&&&&&&&&&&&&&*/
    
}
Example #7
0
static void check_internal_block_head (struct buffer_head * bh)
{
    struct block_head * blkh;
    
    blkh = B_BLK_HEAD (bh);
    if (!(B_LEVEL (bh) > DISK_LEAF_NODE_LEVEL && B_LEVEL (bh) <= MAX_HEIGHT))
	reiserfs_panic (0, "vs-6025: check_internal_block_head: invalid level %z", bh);

    if (B_NR_ITEMS (bh) > (bh->b_size - BLKH_SIZE) / IH_SIZE)
	reiserfs_panic (0, "vs-6030: check_internal_block_head: invalid item number %z", bh);

    if (B_FREE_SPACE (bh) != 
	bh->b_size - BLKH_SIZE - KEY_SIZE * B_NR_ITEMS (bh) - DC_SIZE * (B_NR_ITEMS (bh) + 1))
	reiserfs_panic (0, "vs-6040: check_internal_block_head: invalid free space %z", bh);

}
Example #8
0
static void compare_neighboring_leaves_after_all (void)
{
    struct item_head * left = B_N_PITEM_HEAD(g_left, B_NR_ITEMS (g_left) - 1);
    struct item_head * right = B_N_PITEM_HEAD(g_right, 0);
    /*  struct key * left = B_N_PKEY (g_left, B_NR_ITEMS (g_left) - 1);
	struct key * right = B_N_PKEY (g_right, 0);*/
    
    /*
      if (comp_keys (&left->ih_key, B_PRIGHT_DELIM_KEY (g_left)) != SECOND_GREATER)
      die ("compare_neighboring_leaves_after_all: invalid right delimiting key");
    */
    if (comp_keys (&left->ih_key, B_N_PKEY (g_right, 0)) != -1/*SECOND_GREATER*/)
	die ("compare_neighboring_leaves_after_all: left key is greater than the right one");
    
    if (//comp_le_keys (B_PRIGHT_DELIM_KEY (g_left), g_dkey) != KEYS_IDENTICAL ||
	comp_keys (g_dkey, B_N_PKEY (g_right, 0))) {
	reiserfs_panic (0, "compare_neighboring_leaves_after all: invalid delimiting keys from left to right (%k %k)",
			g_dkey, B_N_PKEY (g_right, 0));
    }
    
    if (!not_of_one_file (&left->ih_key, &right->ih_key)) {
	// items of one file: check offset correctness
	if (is_direct_ih (left) || is_indirect_ih (left))
	    //if (get_offset(&right->ih_key) != get_offset(&left->ih_key) + get_bytes_number (g_left, left /*B_NR_ITEMS (g_left) - 1*/, 0, CHECK_FREE_BYTES))
	    if (get_offset(&right->ih_key) != get_offset(&left->ih_key) + get_bytes_number (left, g_left->b_size))
		die ("compare_neighboring_leaves_after all: hole between items or items are overlapped");
    }
    is_there_unaccessed_items (g_left);
    
}
static void check_objectid_map(struct super_block *s, __le32 * map)
{
	if (le32_to_cpu(map[0]) != 1)
		reiserfs_panic(s, "vs-15010", "map corrupted: %lx",
			       (long unsigned int)le32_to_cpu(map[0]));

	// FIXME: add something else here
}
Example #10
0
/*
 * Utility function to force a BUG if it is called without the superblock
 * write lock held.  caller is the string printed just before calling BUG()
 */
void reiserfs_check_lock_depth(struct super_block *sb, char *caller)
{
    struct reiserfs_sb_info *sb_i = REISERFS_SB(sb);

    if (sb_i->lock_depth < 0)
        reiserfs_panic(sb, "%s called without kernel lock held %d",
                       caller);
}
Example #11
0
static int entry_points_to_object (const char * name, int len, struct reiserfs_dir_entry * de, struct inode * inode)
{
  if (!de_still_valid (name, len, de))
    return 0;

  if (inode) {
    if (!de_visible (de->de_deh))
      reiserfs_panic (0, "vs-7042: entry_points_to_object: entry must be visible");
    return (de->de_objectid == inode->i_ino) ? 1 : 0;
  }

  /* this must be added hidden entry */
  if (de_visible (de->de_deh))
    reiserfs_panic (0, "vs-7043: entry_points_to_object: entry must be visible");

  return 1;
}
Example #12
0
/* after this function de_entry_num is set correctly only if name
   found or there was no entries with given hash value */
static int linear_search_in_dir_item (struct key * key, struct reiserfs_dir_entry * de, const char * name, int namelen)
{
  int retval;
  int i;

  i = de->de_entry_num;

  if (i == I_ENTRY_COUNT (de->de_ih) ||
      GET_HASH_VALUE (de->de_deh[i].deh_offset) != GET_HASH_VALUE (key->k_offset)) {
    i --;
  }

#ifdef REISERFS_CHECK
  if (de->de_deh != B_I_DEH (de->de_bh, de->de_ih))
    reiserfs_panic (0, "vs-7010: linear_search_in_dir_item: array of entry headers not found");
#endif /* REISERFS_CHECK */

  de->de_deh += i;

  for (; i >= 0; i --, de->de_deh --) {
    if (GET_HASH_VALUE (de->de_deh->deh_offset) != GET_HASH_VALUE (key->k_offset)) {
      return POSITION_NOT_FOUND;
    }
   
    /* mark, that this generation number is used */
    if (de->de_gen_number_bit_string)
      set_bit (GET_GENERATION_NUMBER (de->de_deh->deh_offset), de->de_gen_number_bit_string);
    
    /* de_bh, de_item_num, de_ih, de_deh are already set. Set others fields */
    get_entry_attributes (de, i);
    if ((retval = try_name (de, name, namelen)) != POSITION_NOT_FOUND) {
      de->de_entry_num = i;
      return retval;
    }
  }

  if (GET_GENERATION_NUMBER (de->de_ih->ih_key.k_offset) == 0)
    return POSITION_NOT_FOUND;

#ifdef REISERFS_CHECK
  if (de->de_ih->ih_key.k_offset <= DOT_DOT_OFFSET || de->de_item_num != 0)
    reiserfs_panic (0, "vs-7015: linear_search_in_dir_item: item must be 0-th item in block (%d)", de->de_item_num);
#endif /* REISERFS_CHECK */

  return GOTO_PREVIOUS_ITEM;
}
Example #13
0
/* add new name into a directory. If it exists in a directory - do
   nothing */
int reiserfs_add_entry (reiserfs_filsys_t fs, struct key * dir, char * name,
			 struct key * key, int fsck_need)
{
    struct item_head entry_ih = {{0,}, };
    char * entry;
    int retval;
    INITIALIZE_PATH(path);
    int gen_counter;
    int item_len;
    __u32 hash;

    if (reiserfs_find_entry (fs, dir, name, &gen_counter))
	return 0;

    /* compose entry key to look for its place in the tree */
    entry_ih.ih_key.k_dir_id = cpu_to_le32 (dir->k_dir_id);
    entry_ih.ih_key.k_objectid = cpu_to_le32 (dir->k_objectid);
    hash = hash_value (fs, name) + gen_counter;
    if (!strcmp (name, "."))
	hash = DOT_OFFSET;
    if (!strcmp (name, ".."))
	hash = DOT_DOT_OFFSET;
    set_type_and_offset (KEY_FORMAT_1, &(entry_ih.ih_key),
			 hash, TYPE_DIRENTRY);
    set_ih_key_format (&entry_ih, KEY_FORMAT_1);
    set_entry_count (&entry_ih, 1);
    if (SB_VERSION (fs) == REISERFS_VERSION_2)
	item_len = DEH_SIZE + ROUND_UP (strlen (name));
    else
	item_len = DEH_SIZE + strlen (name);
    set_ih_item_len (&entry_ih, item_len);

    /* fsck may need to insert item which was not reached yet */
    set_ih_fsck_need( &entry_ih, fsck_need );

    entry = make_entry (0, name, key, get_offset (&(entry_ih.ih_key)));

    retval = _search_by_entry_key (fs, &(entry_ih.ih_key), &path);
    switch (retval) {
    case POSITION_NOT_FOUND:
	reiserfs_paste_into_item (fs, &path, entry, item_len);
	break;

    case DIRECTORY_NOT_FOUND:
        set_deh_location( (struct reiserfs_de_head *)entry, DEH_SIZE );
	reiserfs_insert_item (fs, &path, &entry_ih, entry);
	break;

    default:
	reiserfs_panic ("reiserfs_add_entry: looking for %k (inserting name \"%s\") "
			"search_by_entry_key returned %d",
			&(entry_ih.ih_key), name, retval);
    }

    freemem (entry);
    return item_len;
}
Example #14
0
/* The function is NOT SCHEDULE-SAFE! */
int search_by_entry_key(struct super_block *sb, const struct cpu_key *key,
			struct treepath *path, struct reiserfs_dir_entry *de)
{
	int retval;

	retval = search_item(sb, key, path);
	switch (retval) {
	case ITEM_NOT_FOUND:
		if (!PATH_LAST_POSITION(path)) {
			reiserfs_error(sb, "vs-7000", "search_by_key "
				       "returned item position == 0");
			pathrelse(path);
			return IO_ERROR;
		}
		PATH_LAST_POSITION(path)--;

	case ITEM_FOUND:
		break;

	case IO_ERROR:
		return retval;

	default:
		pathrelse(path);
		reiserfs_error(sb, "vs-7002", "no path to here");
		return IO_ERROR;
	}

	set_de_item_location(de, path);

#ifdef CONFIG_REISERFS_CHECK
	if (!is_direntry_le_ih(de->de_ih) ||
	    COMP_SHORT_KEYS(&de->de_ih->ih_key, key)) {
		print_block(de->de_bh, 0, -1, -1);
		reiserfs_panic(sb, "vs-7005", "found item %h is not directory "
			       "item or does not belong to the same directory "
			       "as key %K", de->de_ih, key);
	}
#endif				/* CONFIG_REISERFS_CHECK */

	/*
	 * binary search in directory item by third component of the
	 * key. sets de->de_entry_num of de
	 */
	retval = bin_search_in_dir_item(de, cpu_key_k_offset(key));
	path->pos_in_item = de->de_entry_num;
	if (retval != NAME_NOT_FOUND) {
		/*
		 * ugly, but rename needs de_bh, de_deh, de_name,
		 * de_namelen, de_objectid set
		 */
		set_de_name_and_namelen(de);
		set_de_object_key(de);
	}
	return retval;
}
Example #15
0
void reiserfs_paste_into_item (reiserfs_filsys_t fs, struct path * path,
			       const void * body, int size)
{
    struct tree_balance tb;
  
    _init_tb_struct (&tb, fs, path, size);

    if (fix_nodes (M_PASTE, &tb, 0/*ih*/) != CARRY_ON)
	reiserfs_panic ("reiserfs_paste_into_item: fix_nodes failed");

    do_balance (&tb, 0, body, M_PASTE, 0/*zero num*/);
}
Example #16
0
/* Does the buffer contain a disk block which is in the tree. */
inline int B_IS_IN_TREE (struct buffer_head * p_s_bh)
{

#ifdef CONFIG_REISERFS_CHECK
  if ( node_level (p_s_bh) > MAX_HEIGHT ) {
    reiserfs_panic(0, "PAP-1010: B_IS_IN_TREE: block (%b) has too big level (%z)",
		   p_s_bh, p_s_bh);
  }
#endif

  return ( node_level (p_s_bh) != FREE_LEVEL );
}
Example #17
0
/* Get delimiting key of the buffer at the path and its right neighbor. */
inline	struct  key * get_rkey  (
    struct path         * p_s_chk_path,
    struct super_block  * p_s_sb
    ) {
    int                   n_position,
	n_path_offset = p_s_chk_path->path_length;
    struct buffer_head  * p_s_parent;

#ifdef CONFIG_REISERFS_CHECK
    if ( n_path_offset < FIRST_PATH_ELEMENT_OFFSET )
	reiserfs_panic(p_s_sb,"PAP-5030: get_rkey: illegal offset in the path");
#endif

    while ( n_path_offset-- > FIRST_PATH_ELEMENT_OFFSET ) {

#ifdef CONFIG_REISERFS_CHECK
	if ( ! buffer_uptodate(PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)) )
	    reiserfs_panic(p_s_sb, "PAP-5040: get_rkey: parent is not uptodate");
#endif

	/* Parent at the path is not in the tree now. */
	if ( ! B_IS_IN_TREE(p_s_parent = PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)) )
	    return &MIN_KEY;
	/* Check whether position in the parrent is correct. */
	if ( (n_position = PATH_OFFSET_POSITION(p_s_chk_path, n_path_offset)) > B_NR_ITEMS(p_s_parent) )
	    return &MIN_KEY;
	/* Check whether parent at the path really points to the child. */
	if ( B_N_CHILD_NUM(p_s_parent, n_position) !=
	     PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset + 1)->b_blocknr )
	    return &MIN_KEY;
	/* Return delimiting key if position in the parent is not the last one. */
	if ( n_position != B_NR_ITEMS(p_s_parent) )
	    return B_N_PDELIM_KEY(p_s_parent, n_position);
    }
    /* Return MAX_KEY if we are in the root of the buffer tree. */
    if ( PATH_OFFSET_PBUFFER(p_s_chk_path, FIRST_PATH_ELEMENT_OFFSET)->b_blocknr ==
	 SB_ROOT_BLOCK (p_s_sb) )
	return &MAX_KEY;
    return  &MIN_KEY;
}
Example #18
0
/* Check whether a key is contained in the tree rooted from a buffer at a
   path.  This works by looking at the left and right delimiting keys for the
   buffer in the last path_element in the path.  These delimiting keys are
   stored at least one level above that buffer in the tree. If the buffer is
   the first or last node in the tree order then one of the delimiting keys
   may be absent, and in this case get_lkey and get_rkey return a special key
   which is MIN_KEY or MAX_KEY. */
static  inline  int key_in_buffer (
    struct path         * p_s_chk_path, /* Path which should be checked.  */
    struct key          * p_s_key,      /* Key which should be checked.   */
    struct super_block  * p_s_sb        /* Super block pointer.           */
    ) {

#ifdef CONFIG_REISERFS_CHECK
    if ( ! p_s_key || p_s_chk_path->path_length < FIRST_PATH_ELEMENT_OFFSET ||
	 p_s_chk_path->path_length > MAX_HEIGHT )
	reiserfs_panic(p_s_sb, "PAP-5050: key_in_buffer:  pointer to the key(%p) is NULL or illegal path length(%d)",
		       p_s_key, p_s_chk_path->path_length);
  
    if ( PATH_PLAST_BUFFER(p_s_chk_path)->b_dev == NODEV )
	reiserfs_panic(p_s_sb, "PAP-5060: key_in_buffer: device must not be NODEV");
#endif

    if ( COMP_KEYS(get_lkey(p_s_chk_path, p_s_sb), p_s_key) == 1 )
	return 0;
    if ( COMP_KEYS(p_s_key, get_rkey(p_s_chk_path, p_s_sb)) != -1 )
	return 0;
    return 1;
}
Example #19
0
/* Release all buffers in the path. */
void  pathrelse (struct path * p_s_search_path) 
{
    int n_path_offset = p_s_search_path->path_length;
    
#ifdef CONFIG_REISERFS_CHECK
    if ( n_path_offset < ILLEGAL_PATH_ELEMENT_OFFSET )
	reiserfs_panic(NULL, "PAP-5090: pathrelse: illegal path offset");
#endif
    
    while ( n_path_offset > ILLEGAL_PATH_ELEMENT_OFFSET ) 
	brelse(PATH_OFFSET_PBUFFER(p_s_search_path, n_path_offset--));

    p_s_search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
}
Example #20
0
static char * vi_type (struct virtual_item * vi)
{
    static char *types[]={"directory", "direct", "indirect", "stat data"};

    if (vi->vi_type & VI_TYPE_STAT_DATA)
	return types[3];
    if (vi->vi_type & VI_TYPE_INDIRECT)
	return types[2];
    if (vi->vi_type & VI_TYPE_DIRECT)
	return types[1];
    if (vi->vi_type & VI_TYPE_DIRECTORY)
	return types[0];

    reiserfs_panic ("vi_type: 6000: unknown type (0x%x)", vi->vi_type);
    return NULL;
}
Example #21
0
static void reiserfsck_check_cached_tree (int dev, int block, int size)
{
    struct buffer_head * bh;
    int what_node;

    bh =  find_buffer(dev, block, size);
    if (bh == 0)
	return;
    if (!buffer_uptodate (bh)) {
	die ("reiserfsck_check_cached_tree: found notuptodate buffer");
    }

    bh->b_count ++;
    
    if (!B_IS_IN_TREE (bh)) {
	die ("reiserfsck_check_cached_tree: buffer (%b %z) not in tree", bh, bh);
    }

    what_node = who_is_this (bh->b_data, bh->b_size);
    if ((what_node != THE_LEAF && what_node != THE_INTERNAL) ||
	!is_block_used (bh->b_blocknr) ||
	(is_leaf_node (bh) && is_leaf_bad (bh)) ||
	(is_internal_node(bh) && is_internal_bad (bh)))
	die ("reiserfsck_check_cached_tree: bad node in the tree");
    if (is_internal_node (bh)) {
	int i;
	struct disk_child * dc;
	
	dc = B_N_CHILD (bh, 0);
	for (i = 0; i <= B_NR_ITEMS (bh); i ++, dc ++) {
	    reiserfsck_check_cached_tree (dev, dc_block_number(dc), size);
	    g_dkey = B_N_PDELIM_KEY (bh, i);
	}
    } else if (is_leaf_node (bh)) {
	brelse (bh);
	return;
    } else {
	reiserfs_panic ("reiserfsck_check_cached_tree: block %lu has bad block type (%b)",
			bh->b_blocknr, bh);
    }
    brelse (bh);
}
Example #22
0
/*
 * process, that is going to call fix_nodes/do_balance must hold only
 * one path. If it holds 2 or more, it can get into endless waiting in
 * get_empty_nodes or its clones
 */
static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry,
			   struct inode *new_dir, struct dentry *new_dentry)
{
	int retval;
	INITIALIZE_PATH(old_entry_path);
	INITIALIZE_PATH(new_entry_path);
	INITIALIZE_PATH(dot_dot_entry_path);
	struct item_head new_entry_ih, old_entry_ih, dot_dot_ih;
	struct reiserfs_dir_entry old_de, new_de, dot_dot_de;
	struct inode *old_inode, *new_dentry_inode;
	struct reiserfs_transaction_handle th;
	int jbegin_count;
	umode_t old_inode_mode;
	unsigned long savelink = 1;
	struct timespec ctime;

	/* three balancings: (1) old name removal, (2) new name insertion
	   and (3) maybe "save" link insertion
	   stat data updates: (1) old directory,
	   (2) new directory and (3) maybe old object stat data (when it is
	   directory) and (4) maybe stat data of object to which new entry
	   pointed initially and (5) maybe block containing ".." of
	   renamed directory
	   quota updates: two parent directories */
	jbegin_count =
	    JOURNAL_PER_BALANCE_CNT * 3 + 5 +
	    4 * REISERFS_QUOTA_TRANS_BLOCKS(old_dir->i_sb);

	dquot_initialize(old_dir);
	dquot_initialize(new_dir);

	old_inode = old_dentry->d_inode;
	new_dentry_inode = new_dentry->d_inode;

	// make sure, that oldname still exists and points to an object we
	// are going to rename
	old_de.de_gen_number_bit_string = NULL;
	reiserfs_write_lock(old_dir->i_sb);
	retval =
	    reiserfs_find_entry(old_dir, old_dentry->d_name.name,
				old_dentry->d_name.len, &old_entry_path,
				&old_de);
	pathrelse(&old_entry_path);
	if (retval == IO_ERROR) {
		reiserfs_write_unlock(old_dir->i_sb);
		return -EIO;
	}

	if (retval != NAME_FOUND || old_de.de_objectid != old_inode->i_ino) {
		reiserfs_write_unlock(old_dir->i_sb);
		return -ENOENT;
	}

	old_inode_mode = old_inode->i_mode;
	if (S_ISDIR(old_inode_mode)) {
		// make sure, that directory being renamed has correct ".."
		// and that its new parent directory has not too many links
		// already

		if (new_dentry_inode) {
			if (!reiserfs_empty_dir(new_dentry_inode)) {
				reiserfs_write_unlock(old_dir->i_sb);
				return -ENOTEMPTY;
			}
		}

		/* directory is renamed, its parent directory will be changed,
		 ** so find ".." entry
		 */
		dot_dot_de.de_gen_number_bit_string = NULL;
		retval =
		    reiserfs_find_entry(old_inode, "..", 2, &dot_dot_entry_path,
					&dot_dot_de);
		pathrelse(&dot_dot_entry_path);
		if (retval != NAME_FOUND) {
			reiserfs_write_unlock(old_dir->i_sb);
			return -EIO;
		}

		/* inode number of .. must equal old_dir->i_ino */
		if (dot_dot_de.de_objectid != old_dir->i_ino) {
			reiserfs_write_unlock(old_dir->i_sb);
			return -EIO;
		}
	}

	retval = journal_begin(&th, old_dir->i_sb, jbegin_count);
	if (retval) {
		reiserfs_write_unlock(old_dir->i_sb);
		return retval;
	}

	/* add new entry (or find the existing one) */
	retval =
	    reiserfs_add_entry(&th, new_dir, new_dentry->d_name.name,
			       new_dentry->d_name.len, old_inode, 0);
	if (retval == -EEXIST) {
		if (!new_dentry_inode) {
			reiserfs_panic(old_dir->i_sb, "vs-7050",
				       "new entry is found, new inode == 0");
		}
	} else if (retval) {
		int err = journal_end(&th, old_dir->i_sb, jbegin_count);
		reiserfs_write_unlock(old_dir->i_sb);
		return err ? err : retval;
	}

	reiserfs_update_inode_transaction(old_dir);
	reiserfs_update_inode_transaction(new_dir);

	/* this makes it so an fsync on an open fd for the old name will
	 ** commit the rename operation
	 */
	reiserfs_update_inode_transaction(old_inode);

	if (new_dentry_inode)
		reiserfs_update_inode_transaction(new_dentry_inode);

	while (1) {
		// look for old name using corresponding entry key (found by reiserfs_find_entry)
		if ((retval =
		     search_by_entry_key(new_dir->i_sb, &old_de.de_entry_key,
					 &old_entry_path,
					 &old_de)) != NAME_FOUND) {
			pathrelse(&old_entry_path);
			journal_end(&th, old_dir->i_sb, jbegin_count);
			reiserfs_write_unlock(old_dir->i_sb);
			return -EIO;
		}

		copy_item_head(&old_entry_ih, get_ih(&old_entry_path));

		reiserfs_prepare_for_journal(old_inode->i_sb, old_de.de_bh, 1);

		// look for new name by reiserfs_find_entry
		new_de.de_gen_number_bit_string = NULL;
		retval =
		    reiserfs_find_entry(new_dir, new_dentry->d_name.name,
					new_dentry->d_name.len, &new_entry_path,
					&new_de);
		// reiserfs_add_entry should not return IO_ERROR, because it is called with essentially same parameters from
		// reiserfs_add_entry above, and we'll catch any i/o errors before we get here.
		if (retval != NAME_FOUND_INVISIBLE && retval != NAME_FOUND) {
			pathrelse(&new_entry_path);
			pathrelse(&old_entry_path);
			journal_end(&th, old_dir->i_sb, jbegin_count);
			reiserfs_write_unlock(old_dir->i_sb);
			return -EIO;
		}

		copy_item_head(&new_entry_ih, get_ih(&new_entry_path));

		reiserfs_prepare_for_journal(old_inode->i_sb, new_de.de_bh, 1);

		if (S_ISDIR(old_inode->i_mode)) {
			if ((retval =
			     search_by_entry_key(new_dir->i_sb,
						 &dot_dot_de.de_entry_key,
						 &dot_dot_entry_path,
						 &dot_dot_de)) != NAME_FOUND) {
				pathrelse(&dot_dot_entry_path);
				pathrelse(&new_entry_path);
				pathrelse(&old_entry_path);
				journal_end(&th, old_dir->i_sb, jbegin_count);
				reiserfs_write_unlock(old_dir->i_sb);
				return -EIO;
			}
			copy_item_head(&dot_dot_ih,
				       get_ih(&dot_dot_entry_path));
			// node containing ".." gets into transaction
			reiserfs_prepare_for_journal(old_inode->i_sb,
						     dot_dot_de.de_bh, 1);
		}
		/* we should check seals here, not do
		   this stuff, yes? Then, having
		   gathered everything into RAM we
		   should lock the buffers, yes?  -Hans */
		/* probably.  our rename needs to hold more
		 ** than one path at once.  The seals would
		 ** have to be written to deal with multi-path
		 ** issues -chris
		 */
		/* sanity checking before doing the rename - avoid races many
		 ** of the above checks could have scheduled.  We have to be
		 ** sure our items haven't been shifted by another process.
		 */
		if (item_moved(&new_entry_ih, &new_entry_path) ||
		    !entry_points_to_object(new_dentry->d_name.name,
					    new_dentry->d_name.len,
					    &new_de, new_dentry_inode) ||
		    item_moved(&old_entry_ih, &old_entry_path) ||
		    !entry_points_to_object(old_dentry->d_name.name,
					    old_dentry->d_name.len,
					    &old_de, old_inode)) {
			reiserfs_restore_prepared_buffer(old_inode->i_sb,
							 new_de.de_bh);
			reiserfs_restore_prepared_buffer(old_inode->i_sb,
							 old_de.de_bh);
			if (S_ISDIR(old_inode_mode))
				reiserfs_restore_prepared_buffer(old_inode->
								 i_sb,
								 dot_dot_de.
								 de_bh);
			continue;
		}
		if (S_ISDIR(old_inode_mode)) {
			if (item_moved(&dot_dot_ih, &dot_dot_entry_path) ||
			    !entry_points_to_object("..", 2, &dot_dot_de,
						    old_dir)) {
				reiserfs_restore_prepared_buffer(old_inode->
								 i_sb,
								 old_de.de_bh);
				reiserfs_restore_prepared_buffer(old_inode->
								 i_sb,
								 new_de.de_bh);
				reiserfs_restore_prepared_buffer(old_inode->
								 i_sb,
								 dot_dot_de.
								 de_bh);
				continue;
			}
		}

		RFALSE(S_ISDIR(old_inode_mode) &&
		       !buffer_journal_prepared(dot_dot_de.de_bh), "");

		break;
	}

	/* ok, all the changes can be done in one fell swoop when we
	   have claimed all the buffers needed. */

	mark_de_visible(new_de.de_deh + new_de.de_entry_num);
	set_ino_in_dir_entry(&new_de, INODE_PKEY(old_inode));
	journal_mark_dirty(&th, old_dir->i_sb, new_de.de_bh);

	mark_de_hidden(old_de.de_deh + old_de.de_entry_num);
	journal_mark_dirty(&th, old_dir->i_sb, old_de.de_bh);
	ctime = CURRENT_TIME_SEC;
	old_dir->i_ctime = old_dir->i_mtime = ctime;
	new_dir->i_ctime = new_dir->i_mtime = ctime;
	/* thanks to Alex Adriaanse <*****@*****.**> for patch which adds ctime update of
	   renamed object */
	old_inode->i_ctime = ctime;

	if (new_dentry_inode) {
		// adjust link number of the victim
		if (S_ISDIR(new_dentry_inode->i_mode)) {
			clear_nlink(new_dentry_inode);
		} else {
			drop_nlink(new_dentry_inode);
		}
		new_dentry_inode->i_ctime = ctime;
		savelink = new_dentry_inode->i_nlink;
	}

	if (S_ISDIR(old_inode_mode)) {
		/* adjust ".." of renamed directory */
		set_ino_in_dir_entry(&dot_dot_de, INODE_PKEY(new_dir));
		journal_mark_dirty(&th, new_dir->i_sb, dot_dot_de.de_bh);

		if (!new_dentry_inode)
			/* there (in new_dir) was no directory, so it got new link
			   (".."  of renamed directory) */
			INC_DIR_INODE_NLINK(new_dir);

		/* old directory lost one link - ".. " of renamed directory */
		DEC_DIR_INODE_NLINK(old_dir);
	}
	// looks like in 2.3.99pre3 brelse is atomic. so we can use pathrelse
	pathrelse(&new_entry_path);
	pathrelse(&dot_dot_entry_path);

	// FIXME: this reiserfs_cut_from_item's return value may screw up
	// anybody, but it will panic if will not be able to find the
	// entry. This needs one more clean up
	if (reiserfs_cut_from_item
	    (&th, &old_entry_path, &(old_de.de_entry_key), old_dir, NULL,
	     0) < 0)
		reiserfs_error(old_dir->i_sb, "vs-7060",
			       "couldn't not cut old name. Fsck later?");

	old_dir->i_size -= DEH_SIZE + old_de.de_entrylen;

	reiserfs_update_sd(&th, old_dir);
	reiserfs_update_sd(&th, new_dir);
	reiserfs_update_sd(&th, old_inode);

	if (new_dentry_inode) {
		if (savelink == 0)
			add_save_link(&th, new_dentry_inode,
				      0 /* not truncate */ );
		reiserfs_update_sd(&th, new_dentry_inode);
	}

	retval = journal_end(&th, old_dir->i_sb, jbegin_count);
	reiserfs_write_unlock(old_dir->i_sb);
	return retval;
}
Example #23
0
/* 
 * process, that is going to call fix_nodes/do_balance must hold only
 * one path. If it holds 2 or more, it can get into endless waiting in
 * get_empty_nodes or its clones 
 */
static int do_reiserfs_rename (struct reiserfs_transaction_handle *th, struct inode * old_dir, struct dentry *old_dentry,
			       struct inode * new_dir, struct dentry *new_dentry)
{
  int retval;
  struct path old_entry_path, new_entry_path, dot_dot_entry_path;
  struct reiserfs_dir_entry old_de, new_de, dot_dot_de;
  struct inode * old_inode, * new_inode;
  int new_entry_added = 0;

  init_path (&old_entry_path);
  init_path (&new_entry_path);
  init_path (&dot_dot_entry_path);
  goto start_up;

try_again:
  current->policy |= SCHED_YIELD;
  schedule();
	
start_up:
  old_inode = new_inode = NULL;
  dot_dot_de.de_bh = 0;
  new_de.de_bh = 0;

  /* 
   * look for the old name in old directory 
   */
  retval = -ENOENT;
  old_de.de_gen_number_bit_string = 0;
  if (reiserfs_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_entry_path, &old_de) == POSITION_NOT_FOUND)
    goto end_rename;

  pathrelse (&old_entry_path);

  old_inode = old_dentry->d_inode;
  retval = -EPERM;

  if ((old_dir->i_mode & S_ISVTX) && 
      current->fsuid != old_inode->i_uid &&
      current->fsuid != old_dir->i_uid && !fsuser())
    goto end_rename;

  new_inode = new_dentry->d_inode;

  /* look for the new entry in target directory */
  new_de.de_gen_number_bit_string = 0;
  if (reiserfs_find_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_entry_path, &new_de) == POSITION_FOUND) {
    if (!new_inode) {
      printk ("do_reiserfs_rename: new entry found, inode == 0 though\n");
    }
    /* this entry already exists, we can just set key of object */
    new_entry_added = 1;
  } else {
#ifdef REISERFS_CHECK
    if (new_entry_added) {
      if (new_de.de_namelen != new_dentry->d_name.len || memcmp (new_de.de_name, new_dentry->d_name.name, new_de.de_namelen) ||
	  de_visible (new_de.de_deh))
	reiserfs_panic (old_dir->i_sb, "vs-7045: reiserfs_rename: suspicious entry found");
    }
#endif /* REISERFS_CHECK */
  }
  pathrelse (&new_entry_path);


  if (new_inode == old_inode) {
    retval = 0;
    goto end_rename;
  }

  if (new_inode && S_ISDIR(new_inode->i_mode)) {
    /* new name exists and points to directory */
    retval = -EISDIR;
    if (!S_ISDIR(old_inode->i_mode))
      goto end_rename;
    retval = -EINVAL;
    if (is_subdir (new_dentry, old_dentry))
      goto end_rename;
    retval = -ENOTEMPTY;
    if (!reiserfs_empty_dir (new_inode))
      goto end_rename;
    retval = -EBUSY;
    if (new_inode->i_count > 1)
      goto end_rename;
  }

  retval = -EPERM;
  if (new_inode && (new_dir->i_mode & S_ISVTX) && 
      current->fsuid != new_inode->i_uid &&
      current->fsuid != new_dir->i_uid && !fsuser())
    goto end_rename;

  if (S_ISDIR(old_inode->i_mode)) {
    /* old name points to directory */
    retval = -ENOTDIR;
    if (new_inode && !S_ISDIR(new_inode->i_mode))
      goto end_rename;

    retval = -EINVAL;
    if (is_subdir(new_dentry, old_dentry))
      goto end_rename;

    retval = -EIO;
    /* directory is renamed, its parent directory will be changed, so find ".." entry */
    dot_dot_de.de_gen_number_bit_string = 0;
    if (reiserfs_find_entry (old_inode, "..", 2, &dot_dot_entry_path, &dot_dot_de) == POSITION_NOT_FOUND)
      goto end_rename;
    if (dot_dot_de.de_objectid != old_dir->i_ino)
      goto end_rename;
    pathrelse (&dot_dot_entry_path);

    retval = -EMLINK;
    if (!new_inode && new_dir->i_nlink >= REISERFS_LINK_MAX)
      goto end_rename;
  }
  
  if (new_entry_added == 0) {
    /* add new entry if we did not do it, but do not mark it as visible */
    retval = reiserfs_add_entry (th, new_dir, new_dentry->d_name.name, new_dentry->d_name.len, INODE_PKEY (old_inode), &new_de, 0);
    if (retval)
      goto end_rename;
    if_in_ram_update_sd (th, new_dir);
    new_entry_added = 1;
    goto try_again;
  }


  /* 
   * look for old name, new name and ".." when renaming directories again
   */
  if (reiserfs_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_entry_path, &old_de) == POSITION_NOT_FOUND)
    reiserfs_panic (old_dir->i_sb, "vs-7050: reiserfs_rename: old name not found");
  if (reiserfs_find_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_entry_path, &new_de) == POSITION_NOT_FOUND)
    reiserfs_panic (old_dir->i_sb, "vs-7055: reiserfs_rename: new name not found");
  if (S_ISDIR(old_inode->i_mode) && reiserfs_find_entry (old_inode, "..", 2, &dot_dot_entry_path, &dot_dot_de) == POSITION_NOT_FOUND)
    reiserfs_panic (old_dir->i_sb, "vs-7060: reiserfs_rename: \"..\" name not found");
 

  /* sanity checking before doing the rename - avoid races */
  if (!entry_points_to_object (new_dentry->d_name.name, new_dentry->d_name.len, &new_de, new_inode))
    goto try_again;
  if (!entry_points_to_object (old_dentry->d_name.name, old_dentry->d_name.len, &old_de, old_inode))
    /* go to re-looking for old entry */
    goto try_again;

  if (S_ISDIR(old_inode->i_mode) && !entry_points_to_object ("..", 2, &dot_dot_de, old_dir))
    /* go to re-looking for ".." entry of renamed directory */
    goto try_again;
  
  /* ok, all the changes can be done in one fell swoop when we have
     claimed all the buffers needed.*/

  /* make old name hidden */
  mark_de_hidden (old_de.de_deh);
  journal_mark_dirty(th, old_dir->i_sb, old_de.de_bh) ;

  /* make new name visible and set key of old object (if entry
     existed, it is already visible, if not, key is correct already) */
  mark_de_visible (new_de.de_deh);
  new_de.de_deh->deh_dir_id = INODE_PKEY (old_inode)->k_dir_id;
  new_de.de_deh->deh_objectid = INODE_PKEY (old_inode)->k_objectid;
  journal_mark_dirty(th, old_dir->i_sb, new_de.de_bh) ;

  old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
  if_in_ram_update_sd (th, old_dir);

  new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
  if_in_ram_update_sd (th, new_dir);

  if (new_inode) {
    new_inode->i_nlink--;
    new_inode->i_ctime = CURRENT_TIME;
    if_in_ram_update_sd (th, new_inode);
  }
  if (dot_dot_de.de_bh) {
    set_ino_in_dir_entry (&dot_dot_de, INODE_PKEY (new_dir));
    journal_mark_dirty(th, old_dir->i_sb, dot_dot_de.de_bh) ;
    old_dir->i_nlink--;
    if_in_ram_update_sd (th, old_dir);
    if (new_inode) {
      new_inode->i_nlink--;
      if_in_ram_update_sd (th, new_inode);
    } else {
      new_dir->i_nlink++;
      if_in_ram_update_sd (th, new_dir);
    }
  }

  /* ok, renaming done */
  decrement_counters_in_path (&new_entry_path);
  decrement_counters_in_path (&dot_dot_entry_path);

  /* remove old name (it is hidden now) */
  if (reiserfs_cut_from_item (th, old_dir, old_dir->i_sb, &old_entry_path, &(old_de.de_entry_num),
			      &(old_de.de_entry_key), 0, PRESERVE_RENAMING) == 0)
    printk ("reiserfs_rename: could not remove old name\n");
  else {
    old_dir->i_size -= DEH_SIZE + old_de.de_entrylen;
    old_dir->i_blocks = old_dir->i_size / 512 + ((old_dir->i_size % 512) ? 1 : 0);
    if_in_ram_update_sd (th, old_dir);
  }

  /* Update the dcache */
  d_move(old_dentry, new_dentry);
  retval = 0;

end_rename:
  pathrelse (&old_entry_path);
  return retval;
}
Example #24
0
/* Delete insert_num node pointers together with their left items
 * and balance current node.*/
static void balance_internal_when_delete(struct tree_balance *tb,
					 int h, int child_pos)
{
	int insert_num;
	int n;
	struct buffer_head *tbSh = PATH_H_PBUFFER(tb->tb_path, h);
	struct buffer_info bi;

	insert_num = tb->insert_size[h] / ((int)(DC_SIZE + KEY_SIZE));

	/* delete child-node-pointer(s) together with their left item(s) */
	bi.tb = tb;
	bi.bi_bh = tbSh;
	bi.bi_parent = PATH_H_PPARENT(tb->tb_path, h);
	bi.bi_position = PATH_H_POSITION(tb->tb_path, h + 1);

	internal_delete_childs(&bi, child_pos, -insert_num);

	RFALSE(tb->blknum[h] > 1,
	       "tb->blknum[%d]=%d when insert_size < 0", h, tb->blknum[h]);

	n = B_NR_ITEMS(tbSh);

	if (tb->lnum[h] == 0 && tb->rnum[h] == 0) {
		if (tb->blknum[h] == 0) {
			/* node S[h] (root of the tree) is empty now */
			struct buffer_head *new_root;

			RFALSE(n
			       || B_FREE_SPACE(tbSh) !=
			       MAX_CHILD_SIZE(tbSh) - DC_SIZE,
			       "buffer must have only 0 keys (%d)", n);
			RFALSE(bi.bi_parent, "root has parent (%p)",
			       bi.bi_parent);

			/* choose a new root */
			if (!tb->L[h - 1] || !B_NR_ITEMS(tb->L[h - 1]))
				new_root = tb->R[h - 1];
			else
				new_root = tb->L[h - 1];
			/* switch super block's tree root block number to the new value */
			PUT_SB_ROOT_BLOCK(tb->tb_sb, new_root->b_blocknr);
			//REISERFS_SB(tb->tb_sb)->s_rs->s_tree_height --;
			PUT_SB_TREE_HEIGHT(tb->tb_sb,
					   SB_TREE_HEIGHT(tb->tb_sb) - 1);

			do_balance_mark_sb_dirty(tb,
						 REISERFS_SB(tb->tb_sb)->s_sbh,
						 1);
			/*&&&&&&&&&&&&&&&&&&&&&& */
			if (h > 1)
				/* use check_internal if new root is an internal node */
				check_internal(new_root);
			/*&&&&&&&&&&&&&&&&&&&&&& */

			/* do what is needed for buffer thrown from tree */
			reiserfs_invalidate_buffer(tb, tbSh);
			return;
		}
		return;
	}

	if (tb->L[h] && tb->lnum[h] == -B_NR_ITEMS(tb->L[h]) - 1) {	/* join S[h] with L[h] */

		RFALSE(tb->rnum[h] != 0,
		       "invalid tb->rnum[%d]==%d when joining S[h] with L[h]",
		       h, tb->rnum[h]);

		internal_shift_left(INTERNAL_SHIFT_FROM_S_TO_L, tb, h, n + 1);
		reiserfs_invalidate_buffer(tb, tbSh);

		return;
	}

	if (tb->R[h] && tb->rnum[h] == -B_NR_ITEMS(tb->R[h]) - 1) {	/* join S[h] with R[h] */
		RFALSE(tb->lnum[h] != 0,
		       "invalid tb->lnum[%d]==%d when joining S[h] with R[h]",
		       h, tb->lnum[h]);

		internal_shift_right(INTERNAL_SHIFT_FROM_S_TO_R, tb, h, n + 1);

		reiserfs_invalidate_buffer(tb, tbSh);
		return;
	}

	if (tb->lnum[h] < 0) {	/* borrow from left neighbor L[h] */
		RFALSE(tb->rnum[h] != 0,
		       "wrong tb->rnum[%d]==%d when borrow from L[h]", h,
		       tb->rnum[h]);
		/*internal_shift_right (tb, h, tb->L[h], tb->CFL[h], tb->lkey[h], tb->S[h], -tb->lnum[h]); */
		internal_shift_right(INTERNAL_SHIFT_FROM_L_TO_S, tb, h,
				     -tb->lnum[h]);
		return;
	}

	if (tb->rnum[h] < 0) {	/* borrow from right neighbor R[h] */
		RFALSE(tb->lnum[h] != 0,
		       "invalid tb->lnum[%d]==%d when borrow from R[h]",
		       h, tb->lnum[h]);
		internal_shift_left(INTERNAL_SHIFT_FROM_R_TO_S, tb, h, -tb->rnum[h]);	/*tb->S[h], tb->CFR[h], tb->rkey[h], tb->R[h], -tb->rnum[h]); */
		return;
	}

	if (tb->lnum[h] > 0) {	/* split S[h] into two parts and put them into neighbors */
		RFALSE(tb->rnum[h] == 0 || tb->lnum[h] + tb->rnum[h] != n + 1,
		       "invalid tb->lnum[%d]==%d or tb->rnum[%d]==%d when S[h](item number == %d) is split between them",
		       h, tb->lnum[h], h, tb->rnum[h], n);

		internal_shift_left(INTERNAL_SHIFT_FROM_S_TO_L, tb, h, tb->lnum[h]);	/*tb->L[h], tb->CFL[h], tb->lkey[h], tb->S[h], tb->lnum[h]); */
		internal_shift_right(INTERNAL_SHIFT_FROM_S_TO_R, tb, h,
				     tb->rnum[h]);

		reiserfs_invalidate_buffer(tb, tbSh);

		return;
	}
	reiserfs_panic(tb->tb_sb, "ibalance-2",
		       "unexpected tb->lnum[%d]==%d or tb->rnum[%d]==%d",
		       h, tb->lnum[h], h, tb->rnum[h]);
}
Example #25
0
/* add entry to the directory (entry can be hidden). Does not mark dir
   inode dirty, do it after successesfull call to it */
static int reiserfs_add_entry (struct reiserfs_transaction_handle *th, struct inode * dir, 
                               const char * name, int namelen, struct key * object_key, struct reiserfs_dir_entry * de,
			       int visible
			       )
{
  struct key entry_key;
  char * buffer;
  int buflen;
  struct reiserfs_de_head * deh;
  struct path path;
  char bit_string [MAX_GEN_NUMBER / 8 + 1];
  int gen_number;
  int repeat;
#ifdef REISERFS_ALIGNED
  int aligned_namelen = (namelen+3) & ~3;
#endif

  init_path (&path);

  if (!dir || !dir->i_sb)
    return -ENOENT;

  if ((unsigned int)namelen > REISERFS_MAX_NAME_LEN (dir->i_sb->s_blocksize))
    return -ENAMETOOLONG;

  /* each entry has unique key. compose it */
  copy_key (&entry_key, INODE_PKEY(dir));
  entry_key.k_offset = get_third_component (name, namelen);
  entry_key.k_uniqueness = DIRENTRY_UNIQUENESS;

  /* get memory for composing the entry */
#ifdef REISERFS_ALIGNED
  buflen = DEH_SIZE + aligned_namelen;
#else
  buflen = DEH_SIZE + namelen;
#endif
  buffer = reiserfs_kmalloc (buflen, GFP_KERNEL, dir->i_sb);
  if (buffer == 0)
    return -ENOMEM;

  /* fill buffer : directory entry head, name[, dir objectid | , stat data | ,stat data, dir objectid ] */
  deh = (struct reiserfs_de_head *)buffer;
  deh->deh_location = 0;
  deh->deh_offset = entry_key.k_offset;
  deh->deh_state = 0;
  /* put key (ino analog) to de */
  deh->deh_dir_id = object_key->k_dir_id;
  deh->deh_objectid = object_key->k_objectid;

  /* copy name */
#ifdef REISERFS_ALIGNED
  memset( (char*)(deh+1), '\0', aligned_namelen );
#endif
  memcpy ((char *)(deh + 1), name, namelen);

  /* entry is ready to be pasted into tree, set 'visibility' and 'stat data in entry' attributes */
  mark_de_without_sd (deh);
  visible ? mark_de_visible (deh) : mark_de_hidden (deh);

  /* find the proper place for the new entry */
  memset (bit_string, 0, sizeof (bit_string));
  de->de_gen_number_bit_string = bit_string;
  if (reiserfs_find_entry (dir, name, namelen, &path, de) == POSITION_FOUND) {
    reiserfs_panic (dir->i_sb, "vs-7030: reiserfs_add_entry: entry with this key %k already exists",
		    &entry_key);
  }

  if (find_first_nonzero_bit (bit_string, MAX_GEN_NUMBER + 1) < MAX_GEN_NUMBER + 1) {
    /* there are few names with given hash value */
    gen_number = find_first_zero_bit (bit_string, MAX_GEN_NUMBER + 1);
    if (gen_number > MAX_GEN_NUMBER) {
      /* there is no free generation number */
      reiserfs_kfree (buffer, buflen, dir->i_sb);
      pathrelse (&path);
      return -EHASHCOLLISION;
    }
    /* adjust offset of directory enrty */
    deh->deh_offset = SET_GENERATION_NUMBER (deh->deh_offset, gen_number);
    entry_key.k_offset = deh->deh_offset;

    /* find place for new entry */
    if (search_by_entry_key (dir->i_sb, &entry_key, &path, &(de->de_entry_num), &repeat)) {
      reiserfs_panic (dir->i_sb, "reiserfs_add_entry: 7032: entry with this key (%k) already exists", &entry_key);
    }
  } else {
    deh->deh_offset = SET_GENERATION_NUMBER (deh->deh_offset, 0);
    entry_key.k_offset = deh->deh_offset;    
  }
  
  /* perform the insertion of the entry that we have prepared */
  if (reiserfs_paste_into_item (th, dir->i_sb, &path, &(de->de_entry_num), &entry_key, buffer, 
                                buflen, REISERFS_KERNEL_MEM, 0) == -1) {
    reiserfs_kfree (buffer, buflen, dir->i_sb);
    return -ENOSPC;
  }

  reiserfs_kfree (buffer, buflen, dir->i_sb);
  dir->i_size += buflen;
  dir->i_mtime = dir->i_ctime = CURRENT_TIME;

  return 0;
}
Example #26
0
/* returns 0 if name is not found in a directory and objectid of
   pointed object otherwise and returns minimal not used generation
   counter.  dies if found object is not a directory. */
int reiserfs_find_entry (reiserfs_filsys_t fs, struct key * dir, char * name, 
			 int * min_gen_counter)
{
    struct key entry_key;
    int retval;
    int i;
    INITIALIZE_PATH (path);
    struct item_head * ih;
    struct reiserfs_de_head * deh;
    struct key * rdkey;
    __u32 hash;

    entry_key.k_dir_id = cpu_to_le32(dir->k_dir_id);
    entry_key.k_objectid = cpu_to_le32(dir->k_objectid);
    hash = hash_value (fs, name);
    set_type_and_offset (KEY_FORMAT_1, &entry_key, hash, TYPE_DIRENTRY);    
    *min_gen_counter = 0;

    if (_search_by_entry_key (fs, &entry_key, &path) == DIRECTORY_NOT_FOUND) {
	pathrelse (&path);
	return 0;
    }

    do {
	ih = get_ih (&path);
	deh = B_I_DEH (get_bh (&path), ih) + path.pos_in_item;
	for (i = path.pos_in_item; i < ih_entry_count (ih); i ++, deh ++) {
	    if (GET_HASH_VALUE (deh_offset (deh)) != GET_HASH_VALUE (hash)) {
		/* all entries having the same hash were scanned */
		pathrelse (&path);
		return 0;
	    }

	    if (GET_GENERATION_NUMBER (deh_offset (deh)) == *min_gen_counter)
		(*min_gen_counter) ++;

	    if (!memcmp (name_in_entry (deh, i), name, strlen (name))) {
		pathrelse (&path);
		return deh_objectid (deh) ? deh_objectid (deh) : 1;
	    }
	}

	rdkey = _get_rkey (&path);
	if (!rdkey || not_of_one_file (rdkey, dir)) {
	    pathrelse (&path);
	    return 0;
	}
	
	if (!is_direntry_key (rdkey))
	    reiserfs_panic ("reiserfs_find_entry: can not find name in broken directory yet");

	/* next item is the item of the directory we are looking name in */
	if (GET_HASH_VALUE (get_offset (rdkey)) != hash) {
	    /* but there is no names with given hash */
	    pathrelse (&path);
	    return 0;
	}

	/* first name of that item may be a name we are looking for */
	entry_key = *rdkey;
	pathrelse (&path);
	retval = _search_by_entry_key (fs, &entry_key, &path);
	if (retval != POSITION_FOUND)
	    reiserfs_panic ("reiserfs_find_entry: wrong delimiting key in the tree");

    } while (1);
    
    return 0;
}
Example #27
0
static void internal_define_dest_src_infos(int shift_mode,
					   struct tree_balance *tb,
					   int h,
					   struct buffer_info *dest_bi,
					   struct buffer_info *src_bi,
					   int *d_key, struct buffer_head **cf)
{
	memset(dest_bi, 0, sizeof(struct buffer_info));
	memset(src_bi, 0, sizeof(struct buffer_info));
	/* define dest, src, dest parent, dest position */
	switch (shift_mode) {
	case INTERNAL_SHIFT_FROM_S_TO_L:	/* used in internal_shift_left */
		src_bi->tb = tb;
		src_bi->bi_bh = PATH_H_PBUFFER(tb->tb_path, h);
		src_bi->bi_parent = PATH_H_PPARENT(tb->tb_path, h);
		src_bi->bi_position = PATH_H_POSITION(tb->tb_path, h + 1);
		dest_bi->tb = tb;
		dest_bi->bi_bh = tb->L[h];
		dest_bi->bi_parent = tb->FL[h];
		dest_bi->bi_position = get_left_neighbor_position(tb, h);
		*d_key = tb->lkey[h];
		*cf = tb->CFL[h];
		break;
	case INTERNAL_SHIFT_FROM_L_TO_S:
		src_bi->tb = tb;
		src_bi->bi_bh = tb->L[h];
		src_bi->bi_parent = tb->FL[h];
		src_bi->bi_position = get_left_neighbor_position(tb, h);
		dest_bi->tb = tb;
		dest_bi->bi_bh = PATH_H_PBUFFER(tb->tb_path, h);
		dest_bi->bi_parent = PATH_H_PPARENT(tb->tb_path, h);
		dest_bi->bi_position = PATH_H_POSITION(tb->tb_path, h + 1);	/* dest position is analog of dest->b_item_order */
		*d_key = tb->lkey[h];
		*cf = tb->CFL[h];
		break;

	case INTERNAL_SHIFT_FROM_R_TO_S:	/* used in internal_shift_left */
		src_bi->tb = tb;
		src_bi->bi_bh = tb->R[h];
		src_bi->bi_parent = tb->FR[h];
		src_bi->bi_position = get_right_neighbor_position(tb, h);
		dest_bi->tb = tb;
		dest_bi->bi_bh = PATH_H_PBUFFER(tb->tb_path, h);
		dest_bi->bi_parent = PATH_H_PPARENT(tb->tb_path, h);
		dest_bi->bi_position = PATH_H_POSITION(tb->tb_path, h + 1);
		*d_key = tb->rkey[h];
		*cf = tb->CFR[h];
		break;

	case INTERNAL_SHIFT_FROM_S_TO_R:
		src_bi->tb = tb;
		src_bi->bi_bh = PATH_H_PBUFFER(tb->tb_path, h);
		src_bi->bi_parent = PATH_H_PPARENT(tb->tb_path, h);
		src_bi->bi_position = PATH_H_POSITION(tb->tb_path, h + 1);
		dest_bi->tb = tb;
		dest_bi->bi_bh = tb->R[h];
		dest_bi->bi_parent = tb->FR[h];
		dest_bi->bi_position = get_right_neighbor_position(tb, h);
		*d_key = tb->rkey[h];
		*cf = tb->CFR[h];
		break;

	case INTERNAL_INSERT_TO_L:
		dest_bi->tb = tb;
		dest_bi->bi_bh = tb->L[h];
		dest_bi->bi_parent = tb->FL[h];
		dest_bi->bi_position = get_left_neighbor_position(tb, h);
		break;

	case INTERNAL_INSERT_TO_S:
		dest_bi->tb = tb;
		dest_bi->bi_bh = PATH_H_PBUFFER(tb->tb_path, h);
		dest_bi->bi_parent = PATH_H_PPARENT(tb->tb_path, h);
		dest_bi->bi_position = PATH_H_POSITION(tb->tb_path, h + 1);
		break;

	case INTERNAL_INSERT_TO_R:
		dest_bi->tb = tb;
		dest_bi->bi_bh = tb->R[h];
		dest_bi->bi_parent = tb->FR[h];
		dest_bi->bi_position = get_right_neighbor_position(tb, h);
		break;

	default:
		reiserfs_panic(tb->tb_sb, "ibalance-1",
			       "shift type is unknown (%d)",
			       shift_mode);
	}
}
/* path points to first direct item of the file regarless of how many of
   them are there */
int direct2indirect (struct reiserfs_transaction_handle *th, struct inode * inode, 
		     struct path * path, struct buffer_head * unbh,
		     loff_t tail_offset)
{
    struct super_block * sb = inode->i_sb;
    struct buffer_head *up_to_date_bh ;
    struct item_head * p_le_ih = PATH_PITEM_HEAD (path);
    unsigned long total_tail = 0 ;
    struct cpu_key end_key;  /* Key to search for the last byte of the
				converted item. */
    struct item_head ind_ih; /* new indirect item to be inserted or
                                key of unfm pointer to be pasted */
    int	n_blk_size,
      n_retval;	  /* returned value for reiserfs_insert_item and clones */
    struct unfm_nodeinfo unfm_ptr;  /* Handle on an unformatted node
				       that will be inserted in the
				       tree. */


    sb->u.reiserfs_sb.s_direct2indirect ++;

    n_blk_size = sb->s_blocksize;

    /* and key to search for append or insert pointer to the new
       unformatted node. */
    copy_item_head (&ind_ih, p_le_ih);
    set_le_ih_k_offset (&ind_ih, tail_offset);
    set_le_ih_k_type (&ind_ih, TYPE_INDIRECT);

    /* Set the key to search for the place for new unfm pointer */
    make_cpu_key (&end_key, inode, tail_offset, TYPE_INDIRECT, 4);

    // FIXME: we could avoid this 
    if ( search_for_position_by_key (sb, &end_key, path) == POSITION_FOUND ) {
	reiserfs_warning ("PAP-14030: direct2indirect: "
			"pasted or inserted byte exists in the tree %K. "
			"Use fsck to repair.\n", &end_key);
	pathrelse(path);
	return -EIO;
    }
    
    p_le_ih = PATH_PITEM_HEAD (path);

    unfm_ptr.unfm_nodenum = cpu_to_le32 (unbh->b_blocknr);
    unfm_ptr.unfm_freespace = 0; // ???
    
    if ( is_statdata_le_ih (p_le_ih) )  {
	/* Insert new indirect item. */
	set_ih_free_space (&ind_ih, 0); /* delete at nearest future */
        put_ih_item_len( &ind_ih, UNFM_P_SIZE );
	PATH_LAST_POSITION (path)++;
	n_retval = reiserfs_insert_item (th, path, &end_key, &ind_ih, 
					 (char *)&unfm_ptr);
    } else {
	/* Paste into last indirect item of an object. */
	n_retval = reiserfs_paste_into_item(th, path, &end_key,
					    (char *)&unfm_ptr, UNFM_P_SIZE);
    }
    if ( n_retval ) {
	return n_retval;
    }

    // note: from here there are two keys which have matching first
    // three key components. They only differ by the fourth one.


    /* Set the key to search for the direct items of the file */
    make_cpu_key (&end_key, inode, max_reiserfs_offset (inode), TYPE_DIRECT, 4);

    /* Move bytes from the direct items to the new unformatted node
       and delete them. */
    while (1)  {
	int tail_size;

	/* end_key.k_offset is set so, that we will always have found
           last item of the file */
	if ( search_for_position_by_key (sb, &end_key, path) == POSITION_FOUND )
	    reiserfs_panic (sb, "PAP-14050: direct2indirect: "
			    "direct item (%K) not found", &end_key);
	p_le_ih = PATH_PITEM_HEAD (path);
	RFALSE( !is_direct_le_ih (p_le_ih),
	        "vs-14055: direct item expected(%K), found %h",
                &end_key, p_le_ih);
        tail_size = (le_ih_k_offset (p_le_ih) & (n_blk_size - 1))
            + ih_item_len(p_le_ih) - 1;

	/* we only send the unbh pointer if the buffer is not up to date.
	** this avoids overwriting good data from writepage() with old data
	** from the disk or buffer cache
	** Special case: unbh->b_page will be NULL if we are coming through
	** DIRECT_IO handler here.
	*/
	if ( !unbh->b_page || buffer_uptodate(unbh) || Page_Uptodate(unbh->b_page)) {
	    up_to_date_bh = NULL ;
	} else {
	    up_to_date_bh = unbh ;
	}
	n_retval = reiserfs_delete_item (th, path, &end_key, inode, 
	                                 up_to_date_bh) ;

	total_tail += n_retval ;
	if (tail_size == n_retval)
	    // done: file does not have direct items anymore
	    break;

    }
    /* if we've copied bytes from disk into the page, we need to zero
    ** out the unused part of the block (it was not up to date before)
    ** the page is still kmapped (by whoever called reiserfs_get_block)
    */
    if (up_to_date_bh) {
        unsigned pgoff = (tail_offset + total_tail - 1) & (PAGE_CACHE_SIZE - 1);
	memset(page_address(unbh->b_page) + pgoff, 0, n_blk_size - total_tail) ;
    }

    inode->u.reiserfs_i.i_first_direct_byte = U32_MAX;

    reiserfs_update_tail_transaction(inode);
    return 0;
}
Example #29
0
int balance_internal(struct tree_balance *tb,	/* tree_balance structure               */
		     int h,	/* level of the tree                    */
		     int child_pos, struct item_head *insert_key,	/* key for insertion on higher level    */
		     struct buffer_head **insert_ptr	/* node for insertion on higher level */
    )
    /* if inserting/pasting
       {
       child_pos is the position of the node-pointer in S[h] that        *
       pointed to S[h-1] before balancing of the h-1 level;              *
       this means that new pointers and items must be inserted AFTER *
       child_pos
       }
       else
       {
       it is the position of the leftmost pointer that must be deleted (together with
       its corresponding key to the left of the pointer)
       as a result of the previous level's balancing.
       }
     */
{
	struct buffer_head *tbSh = PATH_H_PBUFFER(tb->tb_path, h);
	struct buffer_info bi;
	int order;		/* we return this: it is 0 if there is no S[h], else it is tb->S[h]->b_item_order */
	int insert_num, n, k;
	struct buffer_head *S_new;
	struct item_head new_insert_key;
	struct buffer_head *new_insert_ptr = NULL;
	struct item_head *new_insert_key_addr = insert_key;

	RFALSE(h < 1, "h (%d) can not be < 1 on internal level", h);

	PROC_INFO_INC(tb->tb_sb, balance_at[h]);

	order =
	    (tbSh) ? PATH_H_POSITION(tb->tb_path,
				     h + 1) /*tb->S[h]->b_item_order */ : 0;

	/* Using insert_size[h] calculate the number insert_num of items
	   that must be inserted to or deleted from S[h]. */
	insert_num = tb->insert_size[h] / ((int)(KEY_SIZE + DC_SIZE));

	/* Check whether insert_num is proper * */
	RFALSE(insert_num < -2 || insert_num > 2,
	       "incorrect number of items inserted to the internal node (%d)",
	       insert_num);
	RFALSE(h > 1 && (insert_num > 1 || insert_num < -1),
	       "incorrect number of items (%d) inserted to the internal node on a level (h=%d) higher than last internal level",
	       insert_num, h);

	/* Make balance in case insert_num < 0 */
	if (insert_num < 0) {
		balance_internal_when_delete(tb, h, child_pos);
		return order;
	}

	k = 0;
	if (tb->lnum[h] > 0) {
		/* shift lnum[h] items from S[h] to the left neighbor L[h].
		   check how many of new items fall into L[h] or CFL[h] after
		   shifting */
		n = B_NR_ITEMS(tb->L[h]);	/* number of items in L[h] */
		if (tb->lnum[h] <= child_pos) {
			/* new items don't fall into L[h] or CFL[h] */
			internal_shift_left(INTERNAL_SHIFT_FROM_S_TO_L, tb, h,
					    tb->lnum[h]);
			/*internal_shift_left (tb->L[h],tb->CFL[h],tb->lkey[h],tbSh,tb->lnum[h]); */
			child_pos -= tb->lnum[h];
		} else if (tb->lnum[h] > child_pos + insert_num) {
			/* all new items fall into L[h] */
			internal_shift_left(INTERNAL_SHIFT_FROM_S_TO_L, tb, h,
					    tb->lnum[h] - insert_num);
			/*                  internal_shift_left(tb->L[h],tb->CFL[h],tb->lkey[h],tbSh,
			   tb->lnum[h]-insert_num);
			 */
			/* insert insert_num keys and node-pointers into L[h] */
			bi.tb = tb;
			bi.bi_bh = tb->L[h];
			bi.bi_parent = tb->FL[h];
			bi.bi_position = get_left_neighbor_position(tb, h);
			internal_insert_childs(&bi,
					       /*tb->L[h], tb->S[h-1]->b_next */
					       n + child_pos + 1,
					       insert_num, insert_key,
					       insert_ptr);

			insert_num = 0;
		} else {
			struct disk_child *dc;

			/* some items fall into L[h] or CFL[h], but some don't fall */
			internal_shift1_left(tb, h, child_pos + 1);
			/* calculate number of new items that fall into L[h] */
			k = tb->lnum[h] - child_pos - 1;
			bi.tb = tb;
			bi.bi_bh = tb->L[h];
			bi.bi_parent = tb->FL[h];
			bi.bi_position = get_left_neighbor_position(tb, h);
			internal_insert_childs(&bi,
					       /*tb->L[h], tb->S[h-1]->b_next, */
					       n + child_pos + 1, k,
					       insert_key, insert_ptr);

			replace_lkey(tb, h, insert_key + k);

			/* replace the first node-ptr in S[h] by node-ptr to insert_ptr[k] */
			dc = B_N_CHILD(tbSh, 0);
			put_dc_size(dc,
				    MAX_CHILD_SIZE(insert_ptr[k]) -
				    B_FREE_SPACE(insert_ptr[k]));
			put_dc_block_number(dc, insert_ptr[k]->b_blocknr);

			do_balance_mark_internal_dirty(tb, tbSh, 0);

			k++;
			insert_key += k;
			insert_ptr += k;
			insert_num -= k;
			child_pos = 0;
		}
	}
	/* tb->lnum[h] > 0 */
	if (tb->rnum[h] > 0) {
		/*shift rnum[h] items from S[h] to the right neighbor R[h] */
		/* check how many of new items fall into R or CFR after shifting */
		n = B_NR_ITEMS(tbSh);	/* number of items in S[h] */
		if (n - tb->rnum[h] >= child_pos)
			/* new items fall into S[h] */
			/*internal_shift_right(tb,h,tbSh,tb->CFR[h],tb->rkey[h],tb->R[h],tb->rnum[h]); */
			internal_shift_right(INTERNAL_SHIFT_FROM_S_TO_R, tb, h,
					     tb->rnum[h]);
		else if (n + insert_num - tb->rnum[h] < child_pos) {
			/* all new items fall into R[h] */
			/*internal_shift_right(tb,h,tbSh,tb->CFR[h],tb->rkey[h],tb->R[h],
			   tb->rnum[h] - insert_num); */
			internal_shift_right(INTERNAL_SHIFT_FROM_S_TO_R, tb, h,
					     tb->rnum[h] - insert_num);

			/* insert insert_num keys and node-pointers into R[h] */
			bi.tb = tb;
			bi.bi_bh = tb->R[h];
			bi.bi_parent = tb->FR[h];
			bi.bi_position = get_right_neighbor_position(tb, h);
			internal_insert_childs(&bi,
					       /*tb->R[h],tb->S[h-1]->b_next */
					       child_pos - n - insert_num +
					       tb->rnum[h] - 1,
					       insert_num, insert_key,
					       insert_ptr);
			insert_num = 0;
		} else {
			struct disk_child *dc;

			/* one of the items falls into CFR[h] */
			internal_shift1_right(tb, h, n - child_pos + 1);
			/* calculate number of new items that fall into R[h] */
			k = tb->rnum[h] - n + child_pos - 1;
			bi.tb = tb;
			bi.bi_bh = tb->R[h];
			bi.bi_parent = tb->FR[h];
			bi.bi_position = get_right_neighbor_position(tb, h);
			internal_insert_childs(&bi,
					       /*tb->R[h], tb->R[h]->b_child, */
					       0, k, insert_key + 1,
					       insert_ptr + 1);

			replace_rkey(tb, h, insert_key + insert_num - k - 1);

			/* replace the first node-ptr in R[h] by node-ptr insert_ptr[insert_num-k-1] */
			dc = B_N_CHILD(tb->R[h], 0);
			put_dc_size(dc,
				    MAX_CHILD_SIZE(insert_ptr
						   [insert_num - k - 1]) -
				    B_FREE_SPACE(insert_ptr
						 [insert_num - k - 1]));
			put_dc_block_number(dc,
					    insert_ptr[insert_num - k -
						       1]->b_blocknr);

			do_balance_mark_internal_dirty(tb, tb->R[h], 0);

			insert_num -= (k + 1);
		}
	}

    /** Fill new node that appears instead of S[h] **/
	RFALSE(tb->blknum[h] > 2, "blknum can not be > 2 for internal level");
	RFALSE(tb->blknum[h] < 0, "blknum can not be < 0");

	if (!tb->blknum[h]) {	/* node S[h] is empty now */
		RFALSE(!tbSh, "S[h] is equal NULL");

		/* do what is needed for buffer thrown from tree */
		reiserfs_invalidate_buffer(tb, tbSh);
		return order;
	}

	if (!tbSh) {
		/* create new root */
		struct disk_child *dc;
		struct buffer_head *tbSh_1 = PATH_H_PBUFFER(tb->tb_path, h - 1);
		struct block_head *blkh;

		if (tb->blknum[h] != 1)
			reiserfs_panic(NULL, "ibalance-3", "One new node "
				       "required for creating the new root");
		/* S[h] = empty buffer from the list FEB. */
		tbSh = get_FEB(tb);
		blkh = B_BLK_HEAD(tbSh);
		set_blkh_level(blkh, h + 1);

		/* Put the unique node-pointer to S[h] that points to S[h-1]. */

		dc = B_N_CHILD(tbSh, 0);
		put_dc_block_number(dc, tbSh_1->b_blocknr);
		put_dc_size(dc,
			    (MAX_CHILD_SIZE(tbSh_1) - B_FREE_SPACE(tbSh_1)));

		tb->insert_size[h] -= DC_SIZE;
		set_blkh_free_space(blkh, blkh_free_space(blkh) - DC_SIZE);

		do_balance_mark_internal_dirty(tb, tbSh, 0);

		/*&&&&&&&&&&&&&&&&&&&&&&&& */
		check_internal(tbSh);
		/*&&&&&&&&&&&&&&&&&&&&&&&& */

		/* put new root into path structure */
		PATH_OFFSET_PBUFFER(tb->tb_path, ILLEGAL_PATH_ELEMENT_OFFSET) =
		    tbSh;

		/* Change root in structure super block. */
		PUT_SB_ROOT_BLOCK(tb->tb_sb, tbSh->b_blocknr);
		PUT_SB_TREE_HEIGHT(tb->tb_sb, SB_TREE_HEIGHT(tb->tb_sb) + 1);
		do_balance_mark_sb_dirty(tb, REISERFS_SB(tb->tb_sb)->s_sbh, 1);
	}

	if (tb->blknum[h] == 2) {
		int snum;
		struct buffer_info dest_bi, src_bi;

		/* S_new = free buffer from list FEB */
		S_new = get_FEB(tb);

		set_blkh_level(B_BLK_HEAD(S_new), h + 1);

		dest_bi.tb = tb;
		dest_bi.bi_bh = S_new;
		dest_bi.bi_parent = NULL;
		dest_bi.bi_position = 0;
		src_bi.tb = tb;
		src_bi.bi_bh = tbSh;
		src_bi.bi_parent = PATH_H_PPARENT(tb->tb_path, h);
		src_bi.bi_position = PATH_H_POSITION(tb->tb_path, h + 1);

		n = B_NR_ITEMS(tbSh);	/* number of items in S[h] */
		snum = (insert_num + n + 1) / 2;
		if (n - snum >= child_pos) {
			/* new items don't fall into S_new */
			/*  store the delimiting key for the next level */
			/* new_insert_key = (n - snum)'th key in S[h] */
			memcpy(&new_insert_key, B_N_PDELIM_KEY(tbSh, n - snum),
			       KEY_SIZE);
			/* last parameter is del_par */
			internal_move_pointers_items(&dest_bi, &src_bi,
						     LAST_TO_FIRST, snum, 0);
			/*            internal_move_pointers_items(S_new, tbSh, LAST_TO_FIRST, snum, 0); */
		} else if (n + insert_num - snum < child_pos) {
			/* all new items fall into S_new */
			/*  store the delimiting key for the next level */
			/* new_insert_key = (n + insert_item - snum)'th key in S[h] */
			memcpy(&new_insert_key,
			       B_N_PDELIM_KEY(tbSh, n + insert_num - snum),
			       KEY_SIZE);
			/* last parameter is del_par */
			internal_move_pointers_items(&dest_bi, &src_bi,
						     LAST_TO_FIRST,
						     snum - insert_num, 0);
			/*                  internal_move_pointers_items(S_new,tbSh,1,snum - insert_num,0); */

			/* insert insert_num keys and node-pointers into S_new */
			internal_insert_childs(&dest_bi,
					       /*S_new,tb->S[h-1]->b_next, */
					       child_pos - n - insert_num +
					       snum - 1,
					       insert_num, insert_key,
					       insert_ptr);

			insert_num = 0;
		} else {
			struct disk_child *dc;

			/* some items fall into S_new, but some don't fall */
			/* last parameter is del_par */
			internal_move_pointers_items(&dest_bi, &src_bi,
						     LAST_TO_FIRST,
						     n - child_pos + 1, 1);
			/*                  internal_move_pointers_items(S_new,tbSh,1,n - child_pos + 1,1); */
			/* calculate number of new items that fall into S_new */
			k = snum - n + child_pos - 1;

			internal_insert_childs(&dest_bi, /*S_new, */ 0, k,
					       insert_key + 1, insert_ptr + 1);

			/* new_insert_key = insert_key[insert_num - k - 1] */
			memcpy(&new_insert_key, insert_key + insert_num - k - 1,
			       KEY_SIZE);
			/* replace first node-ptr in S_new by node-ptr to insert_ptr[insert_num-k-1] */

			dc = B_N_CHILD(S_new, 0);
			put_dc_size(dc,
				    (MAX_CHILD_SIZE
				     (insert_ptr[insert_num - k - 1]) -
				     B_FREE_SPACE(insert_ptr
						  [insert_num - k - 1])));
			put_dc_block_number(dc,
					    insert_ptr[insert_num - k -
						       1]->b_blocknr);

			do_balance_mark_internal_dirty(tb, S_new, 0);

			insert_num -= (k + 1);
		}
		/* new_insert_ptr = node_pointer to S_new */
		new_insert_ptr = S_new;

		RFALSE(!buffer_journaled(S_new) || buffer_journal_dirty(S_new)
		       || buffer_dirty(S_new), "cm-00001: bad S_new (%b)",
		       S_new);

		// S_new is released in unfix_nodes
	}

	n = B_NR_ITEMS(tbSh);	/*number of items in S[h] */

	if (0 <= child_pos && child_pos <= n && insert_num > 0) {
		bi.tb = tb;
		bi.bi_bh = tbSh;
		bi.bi_parent = PATH_H_PPARENT(tb->tb_path, h);
		bi.bi_position = PATH_H_POSITION(tb->tb_path, h + 1);
		internal_insert_childs(&bi,	/*tbSh, */
				       /*          ( tb->S[h-1]->b_parent == tb->S[h] ) ? tb->S[h-1]->b_next :  tb->S[h]->b_child->b_next, */
				       child_pos, insert_num, insert_key,
				       insert_ptr);
	}

	memcpy(new_insert_key_addr, &new_insert_key, KEY_SIZE);
	insert_ptr[0] = new_insert_ptr;

	return order;
}
/* this first locks inode (neither reads nor sync are permitted),
   reads tail through page cache, insert direct item. When direct item
   inserted successfully inode is left locked. Return value is always
   what we expect from it (number of cut bytes). But when tail remains
   in the unformatted node, we set mode to SKIP_BALANCING and unlock
   inode */
int indirect2direct (struct reiserfs_transaction_handle *th, 
		     struct inode * p_s_inode,
		     struct page *page, 
		     struct path * p_s_path, /* path to the indirect item. */
		     const struct cpu_key * p_s_item_key, /* Key to look for unformatted node pointer to be cut. */
		     loff_t n_new_file_size, /* New file size. */
		     char * p_c_mode)
{
    struct super_block * p_s_sb = p_s_inode->i_sb;
    struct item_head      s_ih;
    unsigned long n_block_size = p_s_sb->s_blocksize;
    char * tail;
    int tail_len, round_tail_len;
    loff_t pos, pos1; /* position of first byte of the tail */
    struct cpu_key key;

    p_s_sb->u.reiserfs_sb.s_indirect2direct ++;

    *p_c_mode = M_SKIP_BALANCING;

    /* store item head path points to. */
    copy_item_head (&s_ih, PATH_PITEM_HEAD(p_s_path));

    tail_len = (n_new_file_size & (n_block_size - 1));
    if (get_inode_sd_version (p_s_inode) == STAT_DATA_V2)
	round_tail_len = ROUND_UP (tail_len);
    else
	round_tail_len = tail_len;

    pos = le_ih_k_offset (&s_ih) - 1 + (ih_item_len(&s_ih) / UNFM_P_SIZE - 1) * p_s_sb->s_blocksize;
    pos1 = pos;

    // we are protected by i_sem. The tail can not disapper, not
    // append can be done either
    // we are in truncate or packing tail in file_release

    tail = (char *)kmap(page) ; /* this can schedule */

    if (path_changed (&s_ih, p_s_path)) {
	/* re-search indirect item */
	if ( search_for_position_by_key (p_s_sb, p_s_item_key, p_s_path) == POSITION_NOT_FOUND )
	    reiserfs_panic(p_s_sb, "PAP-5520: indirect2direct: "
			   "item to be converted %K does not exist", p_s_item_key);
	copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path));
#ifdef CONFIG_REISERFS_CHECK
	pos = le_ih_k_offset (&s_ih) - 1 + 
	    (ih_item_len(&s_ih) / UNFM_P_SIZE - 1) * p_s_sb->s_blocksize;
	if (pos != pos1)
	    reiserfs_panic (p_s_sb, "vs-5530: indirect2direct: "
			    "tail position changed while we were reading it");
#endif
    }


    /* Set direct item header to insert. */
    make_le_item_head (&s_ih, 0, get_inode_item_key_version (p_s_inode), pos1 + 1,
		       TYPE_DIRECT, round_tail_len, 0xffff/*ih_free_space*/);

    /* we want a pointer to the first byte of the tail in the page.
    ** the page was locked and this part of the page was up to date when
    ** indirect2direct was called, so we know the bytes are still valid
    */
    tail = tail + (pos & (PAGE_CACHE_SIZE - 1)) ;

    PATH_LAST_POSITION(p_s_path)++;

    key = *p_s_item_key;
    set_cpu_key_k_type (&key, TYPE_DIRECT);
    key.key_length = 4;
    /* Insert tail as new direct item in the tree */
    if ( reiserfs_insert_item(th, p_s_path, &key, &s_ih,
			      tail ? tail : NULL) < 0 ) {
	/* No disk memory. So we can not convert last unformatted node
	   to the direct item.  In this case we used to adjust
	   indirect items's ih_free_space. Now ih_free_space is not
	   used, it would be ideal to write zeros to corresponding
	   unformatted node. For now i_size is considered as guard for
	   going out of file size */
	kunmap(page) ;
	return n_block_size - round_tail_len;
    }
    kunmap(page) ;

    /* this will invalidate all the buffers in the page after
    ** pos1
    */
    unmap_buffers(page, pos1) ;

    // note: we have now the same as in above direct2indirect
    // conversion: there are two keys which have matching first three
    // key components. They only differ by the fouhth one.

    /* We have inserted new direct item and must remove last
       unformatted node. */
    p_s_inode->i_blocks += (p_s_sb->s_blocksize / 512);
    *p_c_mode = M_CUT;

    /* we store position of first direct item in the in-core inode */
    //mark_file_with_tail (p_s_inode, pos1 + 1);
    p_s_inode->u.reiserfs_i.i_first_direct_byte = pos1 + 1;

    return n_block_size - round_tail_len;
}