stree.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,882 行 · 第 1/5 页

C
1,882
字号
	    cur_index = 0 ;	    head = page_buffers(page) ;	    bh = head ;	    do {		next = bh->b_this_page ;		/* we want to unmap the buffers that contain the tail, and		** all the buffers after it (since the tail must be at the		** end of the file).  We don't want to unmap file data		** before the tail, since it might be dirty and waiting to		** reach disk		*/		cur_index += bh->b_size ;		if (cur_index > tail_index) {		    reiserfs_unmap_buffer(bh) ;		}		bh = next ;	    } while (bh != head) ;	    if ( PAGE_SIZE == bh->b_size ) {		clear_page_dirty(page);	    }	}    }}static int maybe_indirect_to_direct (struct reiserfs_transaction_handle *th, 			      struct inode * p_s_inode,			      struct page *page, 			      struct path         * p_s_path,			      const struct cpu_key      * p_s_item_key,			      loff_t         n_new_file_size,			      char                * p_c_mode			      ) {    struct super_block * p_s_sb = p_s_inode->i_sb;    int n_block_size = p_s_sb->s_blocksize;    int cut_bytes;    if (n_new_file_size != p_s_inode->i_size)	BUG ();    /* the page being sent in could be NULL if there was an i/o error    ** reading in the last block.  The user will hit problems trying to    ** read the file, but for now we just skip the indirect2direct    */    if (atomic_read(&p_s_inode->i_count) > 1 ||         !tail_has_to_be_packed (p_s_inode) || 	!page || (REISERFS_I(p_s_inode)->i_flags & i_nopack_mask)) {	// leave tail in an unformatted node		*p_c_mode = M_SKIP_BALANCING;	cut_bytes = n_block_size - (n_new_file_size & (n_block_size - 1));	pathrelse(p_s_path);	return cut_bytes;    }    /* Permorm the conversion to a direct_item. */    /*return indirect_to_direct (p_s_inode, p_s_path, p_s_item_key, n_new_file_size, p_c_mode);*/    return indirect2direct (th, p_s_inode, page, p_s_path, p_s_item_key, n_new_file_size, p_c_mode);}/* we did indirect_to_direct conversion. And we have inserted direct   item successesfully, but there were no disk space to cut unfm   pointer being converted. Therefore we have to delete inserted   direct item(s) */static void indirect_to_direct_roll_back (struct reiserfs_transaction_handle *th, struct inode * inode, struct path * path){    struct cpu_key tail_key;    int tail_len;    int removed;    make_cpu_key (&tail_key, inode, inode->i_size + 1, TYPE_DIRECT, 4);// !!!!    tail_key.key_length = 4;    tail_len = (cpu_key_k_offset (&tail_key) & (inode->i_sb->s_blocksize - 1)) - 1;    while (tail_len) {	/* look for the last byte of the tail */	if (search_for_position_by_key (inode->i_sb, &tail_key, path) == POSITION_NOT_FOUND)	    reiserfs_panic (inode->i_sb, "vs-5615: indirect_to_direct_roll_back: found invalid item");	RFALSE( path->pos_in_item != ih_item_len(PATH_PITEM_HEAD (path)) - 1,	        "vs-5616: appended bytes found");	PATH_LAST_POSITION (path) --;		removed = reiserfs_delete_item (th, path, &tail_key, inode, NULL/*unbh not needed*/);	RFALSE( removed <= 0 || removed > tail_len,	        "vs-5617: there was tail %d bytes, removed item length %d bytes",                tail_len, removed);	tail_len -= removed;	set_cpu_key_k_offset (&tail_key, cpu_key_k_offset (&tail_key) - removed);    }    reiserfs_warning (inode->i_sb, "indirect_to_direct_roll_back: indirect_to_direct conversion has been rolled back due to lack of disk space");    //mark_file_without_tail (inode);    mark_inode_dirty (inode);}/* (Truncate or cut entry) or delete object item. Returns < 0 on failure */int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th, 			    struct path * p_s_path,			    struct cpu_key * p_s_item_key,			    struct inode * p_s_inode,			    struct page *page, 			    loff_t n_new_file_size){    struct super_block * p_s_sb = p_s_inode->i_sb;    /* Every function which is going to call do_balance must first       create a tree_balance structure.  Then it must fill up this       structure by using the init_tb_struct and fix_nodes functions.       After that we can make tree balancing. */    struct tree_balance s_cut_balance;    struct item_head *p_le_ih;    int n_cut_size = 0,        /* Amount to be cut. */	n_ret_value = CARRY_ON,	n_removed = 0,     /* Number of the removed unformatted nodes. */	n_is_inode_locked = 0;    char                c_mode;            /* Mode of the balance. */    int retval2 = -1;    int quota_cut_bytes;    loff_t tail_pos = 0;        init_tb_struct(th, &s_cut_balance, p_s_inode->i_sb, p_s_path, n_cut_size);    /* Repeat this loop until we either cut the item without needing       to balance, or we fix_nodes without schedule occurring */    while ( 1 ) {	/* Determine the balance mode, position of the first byte to	   be cut, and size to be cut.  In case of the indirect item	   free unformatted nodes which are pointed to by the cut	   pointers. */      	c_mode = prepare_for_delete_or_cut(th, p_s_inode, p_s_path, p_s_item_key, &n_removed, 					   &n_cut_size, n_new_file_size);	if ( c_mode == M_CONVERT )  {	    /* convert last unformatted node to direct item or leave               tail in the unformatted node */	    RFALSE( n_ret_value != CARRY_ON, "PAP-5570: can not convert twice");	    n_ret_value = maybe_indirect_to_direct (th, p_s_inode, page, p_s_path, p_s_item_key,						    n_new_file_size, &c_mode);	    if ( c_mode == M_SKIP_BALANCING )		/* tail has been left in the unformatted node */		return n_ret_value;	    n_is_inode_locked = 1;	  	    /* removing of last unformatted node will change value we               have to return to truncate. Save it */	    retval2 = n_ret_value;	    /*retval2 = p_s_sb->s_blocksize - (n_new_file_size & (p_s_sb->s_blocksize - 1));*/	  	    /* So, we have performed the first part of the conversion:	       inserting the new direct item.  Now we are removing the	       last unformatted node pointer. Set key to search for	       it. */      	    set_cpu_key_k_type (p_s_item_key, TYPE_INDIRECT);	    p_s_item_key->key_length = 4;	    n_new_file_size -= (n_new_file_size & (p_s_sb->s_blocksize - 1));	    tail_pos = n_new_file_size;	    set_cpu_key_k_offset (p_s_item_key, n_new_file_size + 1);	    if ( search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path) == POSITION_NOT_FOUND ){		print_block (PATH_PLAST_BUFFER (p_s_path), 3, PATH_LAST_POSITION (p_s_path) - 1, PATH_LAST_POSITION (p_s_path) + 1);		reiserfs_panic(p_s_sb, "PAP-5580: reiserfs_cut_from_item: item to convert does not exist (%K)", p_s_item_key);	    }	    continue;	}	if (n_cut_size == 0) {	    pathrelse (p_s_path);	    return 0;	}	s_cut_balance.insert_size[0] = n_cut_size;		n_ret_value = fix_nodes(c_mode, &s_cut_balance, NULL, NULL);      	if ( n_ret_value != REPEAT_SEARCH )	    break;		PROC_INFO_INC( p_s_sb, cut_from_item_restarted );	n_ret_value = search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path);	if (n_ret_value == POSITION_FOUND)	    continue;	reiserfs_warning (p_s_sb, "PAP-5610: reiserfs_cut_from_item: item %K not found", p_s_item_key);	unfix_nodes (&s_cut_balance);	return (n_ret_value == IO_ERROR) ? -EIO : -ENOENT;    } /* while */      // check fix_nodes results (IO_ERROR or NO_DISK_SPACE)    if ( n_ret_value != CARRY_ON ) {	if ( n_is_inode_locked ) {	    // FIXME: this seems to be not needed: we are always able	    // to cut item	    indirect_to_direct_roll_back (th, p_s_inode, p_s_path);	}	if (n_ret_value == NO_DISK_SPACE)	    reiserfs_warning (p_s_sb, "NO_DISK_SPACE");	unfix_nodes (&s_cut_balance);	return -EIO;    }    /* go ahead and perform balancing */        RFALSE( c_mode == M_PASTE || c_mode == M_INSERT, "invalid mode");    /* Calculate number of bytes that need to be cut from the item. */    quota_cut_bytes = ( c_mode == M_DELETE ) ? ih_item_len(get_ih(p_s_path)) : -s_cut_balance.insert_size[0];    if (retval2 == -1)	n_ret_value = calc_deleted_bytes_number(&s_cut_balance, c_mode);    else	n_ret_value = retval2;    /* For direct items, we only change the quota when deleting the last    ** item.    */    p_le_ih = PATH_PITEM_HEAD (s_cut_balance.tb_path);    if (!S_ISLNK (p_s_inode->i_mode) && is_direct_le_ih(p_le_ih)) {        if (c_mode == M_DELETE &&	   (le_ih_k_offset (p_le_ih) & (p_s_sb->s_blocksize - 1)) == 1 ) {	    // FIXME: this is to keep 3.5 happy	    REISERFS_I(p_s_inode)->i_first_direct_byte = U32_MAX;	    quota_cut_bytes = p_s_sb->s_blocksize + UNFM_P_SIZE ;        } else {	    quota_cut_bytes = 0 ;	}    }#ifdef CONFIG_REISERFS_CHECK    if (n_is_inode_locked) {	struct item_head * le_ih = PATH_PITEM_HEAD (s_cut_balance.tb_path);	/* we are going to complete indirect2direct conversion. Make           sure, that we exactly remove last unformatted node pointer           of the item */	if (!is_indirect_le_ih (le_ih))	    reiserfs_panic (p_s_sb, "vs-5652: reiserfs_cut_from_item: "			    "item must be indirect %h", le_ih);	if (c_mode == M_DELETE && ih_item_len(le_ih) != UNFM_P_SIZE)	    reiserfs_panic (p_s_sb, "vs-5653: reiserfs_cut_from_item: "			    "completing indirect2direct conversion indirect item %h "			    "being deleted must be of 4 byte long", le_ih);	if (c_mode == M_CUT && s_cut_balance.insert_size[0] != -UNFM_P_SIZE) {	    reiserfs_panic (p_s_sb, "vs-5654: reiserfs_cut_from_item: "			    "can not complete indirect2direct conversion of %h (CUT, insert_size==%d)",			    le_ih, s_cut_balance.insert_size[0]);	}	/* it would be useful to make sure, that right neighboring           item is direct item of this file */    }#endif        do_balance(&s_cut_balance, NULL, NULL, c_mode);    if ( n_is_inode_locked ) {	/* we've done an indirect->direct conversion.  when the data block	** was freed, it was removed from the list of blocks that must	** be flushed before the transaction commits, make sure to	** unmap and invalidate it	*/	unmap_buffers(page, tail_pos);	REISERFS_I(p_s_inode)->i_flags &= ~i_pack_on_close_mask ;    }#ifdef REISERQUOTA_DEBUG    reiserfs_debug (p_s_inode->i_sb, "reiserquota cut_from_item(): freeing %u id=%u type=%c", quota_cut_bytes, p_s_inode->i_uid, '?');#endif    DQUOT_FREE_SPACE_NODIRTY(p_s_inode, quota_cut_bytes);    return n_ret_value;}static void truncate_directory (struct reiserfs_transaction_handle *th, struct inode * inode){    if (inode->i_nlink)	reiserfs_warning (inode->i_sb,			  "vs-5655: truncate_directory: link count != 0");    set_le_key_k_offset (KEY_FORMAT_3_5, INODE_PKEY (inode), DOT_OFFSET);    set_le_key_k_type (KEY_FORMAT_3_5, INODE_PKEY (inode), TYPE_DIRENTRY);    reiserfs_delete_solid_item (th, inode, INODE_PKEY (inode));    reiserfs_update_sd(th, inode) ;    set_le_key_k_offset (KEY_FORMAT_3_5, INODE_PKEY (inode), SD_OFFSET);    set_le_key_k_type (KEY_FORMAT_3_5, INODE_PKEY (inode), TYPE_STAT_DATA);    }/* Truncate file to the new size. Note, this must be called with a transaction   already started */void reiserfs_do_truncate (struct reiserfs_transaction_handle *th, 			   struct  inode * p_s_inode, /* ->i_size contains new                                                         size */			   struct page *page, /* up to date for last block */			   int update_timestamps  /* when it is called by						     file_release to convert						     the tail - no timestamps						     should be updated */    ) {    INITIALIZE_PATH (s_search_path);       /* Path to the current object item. */    struct item_head    * p_le_ih;         /* Pointer to an item header. */    struct cpu_key      s_item_key;     /* Key to search for a previous file item. */    loff_t         n_file_size,    /* Old file size. */	n_new_file_size;/* New file size. */    int                   n_deleted;      /* Number of deleted or truncated bytes. */    int retval;    if ( ! (S_ISREG(p_s_inode->i_mode) || S_ISDIR(p_s_inode->i_mode) || S_ISLNK(p_s_inode->i_mode)) )	return;    if (S_ISDIR(p_s_inode->i_mode)) {	// deletion of directory - no need to update timestamps	truncate_directory (th, p_s_inode);	return;    }    /* Get new file size. */    n_new_file_size = p_s_inode->i_size;    // FIXME: note, that key type is unimportant here    make_cpu_key (&s_item_key, p_s_inode, max_reiserfs_offset (p_s_inode), TYPE_DIRECT, 3);    retval = search_for_position_by_key(p_s_inode->i_sb, &s_item_key, &s_search_path);    if (retval == IO_ERROR) {	reiserfs_warning (p_s_inode->i_sb, "vs-5657: reiserfs_do_truncate: "			  "i/o failure occurred trying to truncate %K", &s_item_key);	return;    }    if (retval == POSITION_FOUND || retval == FILE_NOT_FOUND) {	pathrelse (&s_search_path);	reiserfs_warning (p_s_inode->i_sb, "PAP-5660: reiserfs_do_truncate: "			  "wrong result %d of search for %K", retval, &s_item_key);	return;    }    s_search_path.pos_in_item --;    /* Get real file size (total length of all file items) */    p_le_ih = PATH_PITEM_HEAD(&s_search_path);    if ( is_statdata_le_ih (p_le_ih) )	n_file_size = 0;    else {	loff_t offset = le_ih_k_offset (p_le_ih);	int bytes = op_bytes_number (p_le_ih,p_s_inode->i_sb->s_blocksize);	/* this may mismatch with real file size: if last direct item           had no padding zeros and last unformatted node had no free           space, this file would have this file size */	n_file_size = offset + bytes - 1;    }    /*     * are we doing a full truncate or delete, if so     * kick in the reada code     */    if (n_new_file_size == 0)        s_search_path.reada = PATH_READA | PATH_READA_BACK;    if ( n_file_size == 0 || n_file_size < n_new_file_size ) {	goto update_and_out ;    }    /* Update key to search for the last file item. */    set_cpu_key_k_offset (&s_item_key, n_file_size);    do  {	/* Cut or delete file item. */	n_deleted = reiserfs_cut_from_item(th, &s_search_path, &s_item_key, p_s_inode,  page, n_new_file_size);	if (n_deleted < 0) {	    reiserfs_warning (p_s_inode->i_sb, "vs-5665: reiserfs_do_truncate: reiserfs_cut_from_item failed");	    reiserfs_check_path(&s_search_path) ;	    return;	}	RFALSE( n_deleted > n_file_size,		"PAP-5670: reiserfs_cut_from_item: too many bytes deleted: deleted %d, file_size %lu, item_key %K",		n_deleted, n_file_size, &s_item_key);	/* Change key to s

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?