int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode,
		    struct treepath *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;	
	struct item_head ind_ih;	
	int blk_size, retval;	
	unp_t unfm_ptr;		

	BUG_ON(!th->t_trans_id);

	REISERFS_SB(sb)->s_direct2indirect++;

	blk_size = sb->s_blocksize;

	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);

	
	make_cpu_key(&end_key, inode, tail_offset, TYPE_INDIRECT, 4);

	
	if (search_for_position_by_key(sb, &end_key, path) == POSITION_FOUND) {
		reiserfs_error(sb, "PAP-14030",
			       "pasted or inserted byte exists in "
			       "the tree %K. Use fsck to repair.", &end_key);
		pathrelse(path);
		return -EIO;
	}

	p_le_ih = PATH_PITEM_HEAD(path);

	unfm_ptr = cpu_to_le32(unbh->b_blocknr);

	if (is_statdata_le_ih(p_le_ih)) {
		
		set_ih_free_space(&ind_ih, 0);	
		put_ih_item_len(&ind_ih, UNFM_P_SIZE);
		PATH_LAST_POSITION(path)++;
		retval =
		    reiserfs_insert_item(th, path, &end_key, &ind_ih, inode,
					 (char *)&unfm_ptr);
	} else {
		
		retval = reiserfs_paste_into_item(th, path, &end_key, inode,
						    (char *)&unfm_ptr,
						    UNFM_P_SIZE);
	}
	if (retval) {
		return retval;
	}
	
	

	
	make_cpu_key(&end_key, inode, max_reiserfs_offset(inode), TYPE_DIRECT,
		     4);

	while (1) {
		int tail_size;

		if (search_for_position_by_key(sb, &end_key, path) ==
		    POSITION_FOUND)
			reiserfs_panic(sb, "PAP-14050",
				       "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) & (blk_size - 1))
		    + ih_item_len(p_le_ih) - 1;

		if (!unbh->b_page || buffer_uptodate(unbh)
		    || PageUptodate(unbh->b_page)) {
			up_to_date_bh = NULL;
		} else {
			up_to_date_bh = unbh;
		}
		retval = reiserfs_delete_item(th, path, &end_key, inode,
						up_to_date_bh);

		total_tail += retval;
		if (tail_size == retval)
			
			break;

	}
	if (up_to_date_bh) {
		unsigned pgoff =
		    (tail_offset + total_tail - 1) & (PAGE_CACHE_SIZE - 1);
		char *kaddr = kmap_atomic(up_to_date_bh->b_page);
		memset(kaddr + pgoff, 0, blk_size - total_tail);
		kunmap_atomic(kaddr);
	}

	REISERFS_I(inode)->i_first_direct_byte = U32_MAX;

	return 0;
}
/* 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;
}
Пример #3
0
/*
 * path points to first direct item of the file regardless of how many of
 * them are there
 */
int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode,
		    struct treepath *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 = tp_item_head(path);
	unsigned long total_tail = 0;

	/* Key to search for the last byte of the converted item. */
	struct cpu_key end_key;

	/*
	 * new indirect item to be inserted or key
	 * of unfm pointer to be pasted
	 */
	struct item_head ind_ih;
	int blk_size;
	/* returned value for reiserfs_insert_item and clones */
	int  retval;
	/* Handle on an unformatted node that will be inserted in the tree. */
	unp_t unfm_ptr;

	BUG_ON(!th->t_trans_id);

	REISERFS_SB(sb)->s_direct2indirect++;

	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_error(sb, "PAP-14030",
			       "pasted or inserted byte exists in "
			       "the tree %K. Use fsck to repair.", &end_key);
		pathrelse(path);
		return -EIO;
	}

	p_le_ih = tp_item_head(path);

	unfm_ptr = cpu_to_le32(unbh->b_blocknr);

	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)++;
		retval =
		    reiserfs_insert_item(th, path, &end_key, &ind_ih, inode,
					 (char *)&unfm_ptr);
	} else {
		/* Paste into last indirect item of an object. */
		retval = reiserfs_paste_into_item(th, path, &end_key, inode,
						    (char *)&unfm_ptr,
						    UNFM_P_SIZE);
	}
	if (retval) {
		return 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",
				       "direct item (%K) not found", &end_key);
		p_le_ih = tp_item_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) & (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)
		    || PageUptodate(unbh->b_page)) {
			up_to_date_bh = NULL;
		} else {
			up_to_date_bh = unbh;
		}
		retval = reiserfs_delete_item(th, path, &end_key, inode,
						up_to_date_bh);

		total_tail += retval;

		/* done: file does not have direct items anymore */
		if (tail_size == retval)
			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)
	 */
	if (up_to_date_bh) {
		unsigned pgoff =
		    (tail_offset + total_tail - 1) & (PAGE_SIZE - 1);
		char *kaddr = kmap_atomic(up_to_date_bh->b_page);
		memset(kaddr + pgoff, 0, blk_size - total_tail);
		kunmap_atomic(kaddr);
	}

	REISERFS_I(inode)->i_first_direct_byte = U32_MAX;

	return 0;
}