2005-04-17 05:20:36 +07:00
/*
* Copyright 2000 by Hans Reiser , licensing governed by reiserfs / README
*/
/*
* Written by Anatoly P . Pinchuk pap @ namesys . botik . ru
* Programm System Institute
* Pereslavl - Zalessky Russia
*/
/*
* This file contains functions dealing with S + tree
*
* B_IS_IN_TREE
* copy_item_head
* comp_short_keys
* comp_keys
* comp_short_le_keys
* le_key2cpu_key
* comp_le_keys
* bin_search
* get_lkey
* get_rkey
* key_in_buffer
* decrement_bcount
* decrement_counters_in_path
* reiserfs_check_path
* pathrelse_and_restore
* pathrelse
* search_by_key_reada
* search_by_key
* search_for_position_by_key
* comp_items
* prepare_for_direct_item
* prepare_for_direntry_item
* prepare_for_delete_or_cut
* calc_deleted_bytes_number
* init_tb_struct
* padd_item
* reiserfs_delete_item
* reiserfs_delete_solid_item
* reiserfs_delete_object
* maybe_indirect_to_direct
* indirect_to_direct_roll_back
* reiserfs_cut_from_item
* truncate_directory
* reiserfs_do_truncate
* reiserfs_paste_into_item
* reiserfs_insert_item
*/
# include <linux/config.h>
# include <linux/time.h>
# include <linux/string.h>
# include <linux/pagemap.h>
# include <linux/reiserfs_fs.h>
# include <linux/smp_lock.h>
# include <linux/buffer_head.h>
# include <linux/quotaops.h>
/* Does the buffer contain a disk block which is in the tree. */
2005-07-13 10:21:28 +07:00
inline int B_IS_IN_TREE ( const struct buffer_head * p_s_bh )
2005-04-17 05:20:36 +07:00
{
2005-07-13 10:21:28 +07:00
RFALSE ( B_LEVEL ( p_s_bh ) > MAX_HEIGHT ,
" PAP-1010: block (%b) has too big level (%z) " , p_s_bh , p_s_bh ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
return ( B_LEVEL ( p_s_bh ) ! = FREE_LEVEL ) ;
2005-04-17 05:20:36 +07:00
}
//
// to gets item head in le form
//
2005-07-13 10:21:28 +07:00
inline void copy_item_head ( struct item_head * p_v_to ,
const struct item_head * p_v_from )
2005-04-17 05:20:36 +07:00
{
2005-07-13 10:21:28 +07:00
memcpy ( p_v_to , p_v_from , IH_SIZE ) ;
2005-04-17 05:20:36 +07:00
}
/* k1 is pointer to on-disk structure which is stored in little-endian
form . k2 is pointer to cpu variable . For key of items of the same
object this returns 0.
Returns : - 1 if key1 < key2
0 if key1 = = key2
1 if key1 > key2 */
2005-07-13 10:21:28 +07:00
inline int comp_short_keys ( const struct reiserfs_key * le_key ,
const struct cpu_key * cpu_key )
2005-04-17 05:20:36 +07:00
{
2005-07-13 10:21:28 +07:00
__u32 n ;
n = le32_to_cpu ( le_key - > k_dir_id ) ;
if ( n < cpu_key - > on_disk_key . k_dir_id )
return - 1 ;
if ( n > cpu_key - > on_disk_key . k_dir_id )
return 1 ;
n = le32_to_cpu ( le_key - > k_objectid ) ;
if ( n < cpu_key - > on_disk_key . k_objectid )
return - 1 ;
if ( n > cpu_key - > on_disk_key . k_objectid )
return 1 ;
return 0 ;
2005-04-17 05:20:36 +07:00
}
/* k1 is pointer to on-disk structure which is stored in little-endian
form . k2 is pointer to cpu variable .
Compare keys using all 4 key fields .
Returns : - 1 if key1 < key2 0
if key1 = key2 1 if key1 > key2 */
2005-07-13 10:21:28 +07:00
static inline int comp_keys ( const struct reiserfs_key * le_key ,
const struct cpu_key * cpu_key )
2005-04-17 05:20:36 +07:00
{
2005-07-13 10:21:28 +07:00
int retval ;
retval = comp_short_keys ( le_key , cpu_key ) ;
if ( retval )
return retval ;
if ( le_key_k_offset ( le_key_version ( le_key ) , le_key ) <
cpu_key_k_offset ( cpu_key ) )
return - 1 ;
if ( le_key_k_offset ( le_key_version ( le_key ) , le_key ) >
cpu_key_k_offset ( cpu_key ) )
return 1 ;
if ( cpu_key - > key_length = = 3 )
return 0 ;
/* this part is needed only when tail conversion is in progress */
if ( le_key_k_type ( le_key_version ( le_key ) , le_key ) <
cpu_key_k_type ( cpu_key ) )
return - 1 ;
if ( le_key_k_type ( le_key_version ( le_key ) , le_key ) >
cpu_key_k_type ( cpu_key ) )
return 1 ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
return 0 ;
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
inline int comp_short_le_keys ( const struct reiserfs_key * key1 ,
const struct reiserfs_key * key2 )
2005-04-17 05:20:36 +07:00
{
2005-07-13 10:21:28 +07:00
__u32 * p_s_1_u32 , * p_s_2_u32 ;
int n_key_length = REISERFS_SHORT_KEY_LEN ;
p_s_1_u32 = ( __u32 * ) key1 ;
p_s_2_u32 = ( __u32 * ) key2 ;
for ( ; n_key_length - - ; + + p_s_1_u32 , + + p_s_2_u32 ) {
if ( le32_to_cpu ( * p_s_1_u32 ) < le32_to_cpu ( * p_s_2_u32 ) )
return - 1 ;
if ( le32_to_cpu ( * p_s_1_u32 ) > le32_to_cpu ( * p_s_2_u32 ) )
return 1 ;
}
return 0 ;
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
inline void le_key2cpu_key ( struct cpu_key * to , const struct reiserfs_key * from )
2005-04-17 05:20:36 +07:00
{
2005-07-13 10:21:28 +07:00
int version ;
to - > on_disk_key . k_dir_id = le32_to_cpu ( from - > k_dir_id ) ;
to - > on_disk_key . k_objectid = le32_to_cpu ( from - > k_objectid ) ;
// find out version of the key
version = le_key_version ( from ) ;
to - > version = version ;
to - > on_disk_key . k_offset = le_key_k_offset ( version , from ) ;
to - > on_disk_key . k_type = le_key_k_type ( version , from ) ;
2005-04-17 05:20:36 +07:00
}
// this does not say which one is bigger, it only returns 1 if keys
// are not equal, 0 otherwise
2005-07-13 10:21:28 +07:00
inline int comp_le_keys ( const struct reiserfs_key * k1 ,
const struct reiserfs_key * k2 )
2005-04-17 05:20:36 +07:00
{
2005-07-13 10:21:28 +07:00
return memcmp ( k1 , k2 , sizeof ( struct reiserfs_key ) ) ;
2005-04-17 05:20:36 +07:00
}
/**************************************************************************
* Binary search toolkit function *
* Search for an item in the array by the item key *
* Returns : 1 if found , 0 if not found ; *
* * p_n_pos = number of the searched element if found , else the *
* number of the first element that is larger than p_v_key . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* For those not familiar with binary search: n_lbound is the leftmost item that it
could be , n_rbound the rightmost item that it could be . We examine the item
halfway between n_lbound and n_rbound , and that tells us either that we can increase
n_lbound , or decrease n_rbound , or that we have found it , or if n_lbound < = n_rbound that
there are no possible items , and we have not found it . With each examination we
cut the number of possible items it could be by one more than half rounded down ,
or we find it . */
2005-07-13 10:21:28 +07:00
static inline int bin_search ( const void * p_v_key , /* Key to search for. */
const void * p_v_base , /* First item in the array. */
int p_n_num , /* Number of items in the array. */
int p_n_width , /* Item size in the array.
searched . Lest the reader be
confused , note that this is crafted
as a general function , and when it
is applied specifically to the array
of item headers in a node , p_n_width
is actually the item header size not
the item size . */
int * p_n_pos /* Number of the searched for element. */
)
{
int n_rbound , n_lbound , n_j ;
for ( n_j = ( ( n_rbound = p_n_num - 1 ) + ( n_lbound = 0 ) ) / 2 ;
n_lbound < = n_rbound ; n_j = ( n_rbound + n_lbound ) / 2 )
switch ( comp_keys
( ( struct reiserfs_key * ) ( ( char * ) p_v_base +
n_j * p_n_width ) ,
( struct cpu_key * ) p_v_key ) ) {
case - 1 :
n_lbound = n_j + 1 ;
continue ;
case 1 :
n_rbound = n_j - 1 ;
continue ;
case 0 :
* p_n_pos = n_j ;
return ITEM_FOUND ; /* Key found in the array. */
}
/* bin_search did not find given key, it returns position of key,
that is minimal and greater than the given one . */
* p_n_pos = n_lbound ;
return ITEM_NOT_FOUND ;
2005-04-17 05:20:36 +07:00
}
# ifdef CONFIG_REISERFS_CHECK
2005-07-13 10:21:28 +07:00
extern struct tree_balance * cur_tb ;
2005-04-17 05:20:36 +07:00
# endif
/* Minimal possible key. It is never in the tree. */
2005-07-13 10:21:28 +07:00
const struct reiserfs_key MIN_KEY = { 0 , 0 , { { 0 , 0 } , } } ;
2005-04-17 05:20:36 +07:00
/* Maximal possible key. It is never in the tree. */
2005-07-13 10:21:28 +07:00
static const struct reiserfs_key MAX_KEY = {
2005-05-01 22:59:18 +07:00
__constant_cpu_to_le32 ( 0xffffffff ) ,
__constant_cpu_to_le32 ( 0xffffffff ) ,
{ { __constant_cpu_to_le32 ( 0xffffffff ) ,
2005-07-13 10:21:28 +07:00
__constant_cpu_to_le32 ( 0xffffffff ) } , }
2005-05-01 22:59:18 +07:00
} ;
2005-04-17 05:20:36 +07:00
/* Get delimiting key of the buffer by looking for it in the buffers in the path, starting from the bottom
of the path , and going upwards . We must check the path ' s validity at each step . If the key is not in
the path , there is no delimiting key in the tree ( buffer is first or last buffer in tree ) , and in this
case we return a special key , either MIN_KEY or MAX_KEY . */
2005-07-13 10:21:28 +07:00
static inline const struct reiserfs_key * get_lkey ( const struct path
* p_s_chk_path ,
const struct super_block
* p_s_sb )
{
int n_position , n_path_offset = p_s_chk_path - > path_length ;
struct buffer_head * p_s_parent ;
RFALSE ( n_path_offset < FIRST_PATH_ELEMENT_OFFSET ,
" PAP-5010: invalid offset in the path " ) ;
/* While not higher in path than first element. */
while ( n_path_offset - - > FIRST_PATH_ELEMENT_OFFSET ) {
RFALSE ( ! buffer_uptodate
( PATH_OFFSET_PBUFFER ( p_s_chk_path , n_path_offset ) ) ,
" PAP-5020: parent is not uptodate " ) ;
/* 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 & MAX_KEY ;
/* Check whether position in the parent is correct. */
if ( ( n_position =
PATH_OFFSET_POSITION ( p_s_chk_path ,
n_path_offset ) ) >
B_NR_ITEMS ( p_s_parent ) )
return & MAX_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 & MAX_KEY ;
/* Return delimiting key if position in the parent is not equal to zero. */
if ( n_position )
return B_N_PDELIM_KEY ( p_s_parent , n_position - 1 ) ;
}
/* Return MIN_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 & MIN_KEY ;
return & MAX_KEY ;
2005-04-17 05:20:36 +07:00
}
/* Get delimiting key of the buffer at the path and its right neighbor. */
2005-07-13 10:21:28 +07:00
inline const struct reiserfs_key * get_rkey ( const struct path * p_s_chk_path ,
const struct super_block * p_s_sb )
{
int n_position , n_path_offset = p_s_chk_path - > path_length ;
struct buffer_head * p_s_parent ;
RFALSE ( n_path_offset < FIRST_PATH_ELEMENT_OFFSET ,
" PAP-5030: invalid offset in the path " ) ;
while ( n_path_offset - - > FIRST_PATH_ELEMENT_OFFSET ) {
RFALSE ( ! buffer_uptodate
( PATH_OFFSET_PBUFFER ( p_s_chk_path , n_path_offset ) ) ,
" PAP-5040: parent is not uptodate " ) ;
/* 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 parent 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 ;
2005-04-17 05:20:36 +07:00
}
/* 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 . */
2005-07-13 10:21:28 +07:00
static inline int key_in_buffer ( struct path * p_s_chk_path , /* Path which should be checked. */
const struct cpu_key * p_s_key , /* Key which should be checked. */
struct super_block * p_s_sb /* Super block pointer. */
)
{
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
RFALSE ( ! p_s_key | | p_s_chk_path - > path_length < FIRST_PATH_ELEMENT_OFFSET
| | p_s_chk_path - > path_length > MAX_HEIGHT ,
" PAP-5050: pointer to the key(%p) is NULL or invalid path length(%d) " ,
p_s_key , p_s_chk_path - > path_length ) ;
RFALSE ( ! PATH_PLAST_BUFFER ( p_s_chk_path ) - > b_bdev ,
" PAP-5060: device must not be NODEV " ) ;
if ( comp_keys ( get_lkey ( p_s_chk_path , p_s_sb ) , p_s_key ) = = 1 )
/* left delimiting key is bigger, that the key we look for */
return 0 ;
// if ( comp_keys(p_s_key, get_rkey(p_s_chk_path, p_s_sb)) != -1 )
if ( comp_keys ( get_rkey ( p_s_chk_path , p_s_sb ) , p_s_key ) ! = 1 )
/* p_s_key must be less than right delimitiing key */
return 0 ;
return 1 ;
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
inline void decrement_bcount ( struct buffer_head * p_s_bh )
{
if ( p_s_bh ) {
if ( atomic_read ( & ( p_s_bh - > b_count ) ) ) {
put_bh ( p_s_bh ) ;
return ;
}
reiserfs_panic ( NULL ,
" PAP-5070: decrement_bcount: trying to free free buffer %b " ,
p_s_bh ) ;
}
}
2005-04-17 05:20:36 +07:00
/* Decrement b_count field of the all buffers in the path. */
2005-07-13 10:21:28 +07:00
void decrement_counters_in_path ( struct path * p_s_search_path )
{
int n_path_offset = p_s_search_path - > path_length ;
RFALSE ( n_path_offset < ILLEGAL_PATH_ELEMENT_OFFSET | |
n_path_offset > EXTENDED_MAX_HEIGHT - 1 ,
" PAP-5080: invalid path offset of %d " , n_path_offset ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
while ( n_path_offset > ILLEGAL_PATH_ELEMENT_OFFSET ) {
struct buffer_head * bh ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
bh = PATH_OFFSET_PBUFFER ( p_s_search_path , n_path_offset - - ) ;
decrement_bcount ( bh ) ;
}
p_s_search_path - > path_length = ILLEGAL_PATH_ELEMENT_OFFSET ;
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
int reiserfs_check_path ( struct path * p )
{
RFALSE ( p - > path_length ! = ILLEGAL_PATH_ELEMENT_OFFSET ,
" path not properly relsed " ) ;
return 0 ;
}
2005-04-17 05:20:36 +07:00
/* Release all buffers in the path. Restore dirty bits clean
* * when preparing the buffer for the log
* *
* * only called from fix_nodes ( )
*/
2005-07-13 10:21:28 +07:00
void pathrelse_and_restore ( struct super_block * s , struct path * p_s_search_path )
{
int n_path_offset = p_s_search_path - > path_length ;
RFALSE ( n_path_offset < ILLEGAL_PATH_ELEMENT_OFFSET ,
" clm-4000: invalid path offset " ) ;
while ( n_path_offset > ILLEGAL_PATH_ELEMENT_OFFSET ) {
reiserfs_restore_prepared_buffer ( s ,
PATH_OFFSET_PBUFFER
( p_s_search_path ,
n_path_offset ) ) ;
brelse ( PATH_OFFSET_PBUFFER ( p_s_search_path , n_path_offset - - ) ) ;
}
p_s_search_path - > path_length = ILLEGAL_PATH_ELEMENT_OFFSET ;
2005-04-17 05:20:36 +07:00
}
/* Release all buffers in the path. */
2005-07-13 10:21:28 +07:00
void pathrelse ( struct path * p_s_search_path )
{
int n_path_offset = p_s_search_path - > path_length ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
RFALSE ( n_path_offset < ILLEGAL_PATH_ELEMENT_OFFSET ,
" PAP-5090: invalid path offset " ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
while ( n_path_offset > ILLEGAL_PATH_ELEMENT_OFFSET )
brelse ( PATH_OFFSET_PBUFFER ( p_s_search_path , n_path_offset - - ) ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
p_s_search_path - > path_length = ILLEGAL_PATH_ELEMENT_OFFSET ;
}
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
static int is_leaf ( char * buf , int blocksize , struct buffer_head * bh )
{
struct block_head * blkh ;
struct item_head * ih ;
int used_space ;
int prev_location ;
int i ;
int nr ;
blkh = ( struct block_head * ) buf ;
if ( blkh_level ( blkh ) ! = DISK_LEAF_NODE_LEVEL ) {
reiserfs_warning ( NULL ,
" is_leaf: this should be caught earlier " ) ;
return 0 ;
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
nr = blkh_nr_item ( blkh ) ;
if ( nr < 1 | | nr > ( ( blocksize - BLKH_SIZE ) / ( IH_SIZE + MIN_ITEM_LEN ) ) ) {
/* item number is too big or too small */
reiserfs_warning ( NULL , " is_leaf: nr_item seems wrong: %z " , bh ) ;
return 0 ;
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
ih = ( struct item_head * ) ( buf + BLKH_SIZE ) + nr - 1 ;
used_space = BLKH_SIZE + IH_SIZE * nr + ( blocksize - ih_location ( ih ) ) ;
if ( used_space ! = blocksize - blkh_free_space ( blkh ) ) {
/* free space does not match to calculated amount of use space */
reiserfs_warning ( NULL , " is_leaf: free space seems wrong: %z " ,
bh ) ;
return 0 ;
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
// FIXME: it is_leaf will hit performance too much - we may have
// return 1 here
/* check tables of item heads */
ih = ( struct item_head * ) ( buf + BLKH_SIZE ) ;
prev_location = blocksize ;
for ( i = 0 ; i < nr ; i + + , ih + + ) {
if ( le_ih_k_type ( ih ) = = TYPE_ANY ) {
reiserfs_warning ( NULL ,
" is_leaf: wrong item type for item %h " ,
ih ) ;
return 0 ;
}
if ( ih_location ( ih ) > = blocksize
| | ih_location ( ih ) < IH_SIZE * nr ) {
reiserfs_warning ( NULL ,
" is_leaf: item location seems wrong: %h " ,
ih ) ;
return 0 ;
}
if ( ih_item_len ( ih ) < 1
| | ih_item_len ( ih ) > MAX_ITEM_LEN ( blocksize ) ) {
reiserfs_warning ( NULL ,
" is_leaf: item length seems wrong: %h " ,
ih ) ;
return 0 ;
}
if ( prev_location - ih_location ( ih ) ! = ih_item_len ( ih ) ) {
reiserfs_warning ( NULL ,
" is_leaf: item location seems wrong (second one): %h " ,
ih ) ;
return 0 ;
}
prev_location = ih_location ( ih ) ;
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
// one may imagine much more checks
return 1 ;
2005-04-17 05:20:36 +07:00
}
/* returns 1 if buf looks like an internal node, 0 otherwise */
2005-07-13 10:21:28 +07:00
static int is_internal ( char * buf , int blocksize , struct buffer_head * bh )
2005-04-17 05:20:36 +07:00
{
2005-07-13 10:21:28 +07:00
struct block_head * blkh ;
int nr ;
int used_space ;
blkh = ( struct block_head * ) buf ;
nr = blkh_level ( blkh ) ;
if ( nr < = DISK_LEAF_NODE_LEVEL | | nr > MAX_HEIGHT ) {
/* this level is not possible for internal nodes */
reiserfs_warning ( NULL ,
" is_internal: this should be caught earlier " ) ;
return 0 ;
}
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
nr = blkh_nr_item ( blkh ) ;
if ( nr > ( blocksize - BLKH_SIZE - DC_SIZE ) / ( KEY_SIZE + DC_SIZE ) ) {
/* for internal which is not root we might check min number of keys */
reiserfs_warning ( NULL ,
" is_internal: number of key seems wrong: %z " ,
bh ) ;
return 0 ;
}
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
used_space = BLKH_SIZE + KEY_SIZE * nr + DC_SIZE * ( nr + 1 ) ;
if ( used_space ! = blocksize - blkh_free_space ( blkh ) ) {
reiserfs_warning ( NULL ,
" is_internal: free space seems wrong: %z " , bh ) ;
return 0 ;
}
// one may imagine much more checks
return 1 ;
2005-04-17 05:20:36 +07:00
}
// make sure that bh contains formatted node of reiserfs tree of
// 'level'-th level
2005-07-13 10:21:28 +07:00
static int is_tree_node ( struct buffer_head * bh , int level )
2005-04-17 05:20:36 +07:00
{
2005-07-13 10:21:28 +07:00
if ( B_LEVEL ( bh ) ! = level ) {
reiserfs_warning ( NULL ,
" is_tree_node: node level %d does not match to the expected one %d " ,
B_LEVEL ( bh ) , level ) ;
return 0 ;
}
if ( level = = DISK_LEAF_NODE_LEVEL )
return is_leaf ( bh - > b_data , bh - > b_size , bh ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
return is_internal ( bh - > b_data , bh - > b_size , bh ) ;
2005-04-17 05:20:36 +07:00
}
# define SEARCH_BY_KEY_READA 16
/* The function is NOT SCHEDULE-SAFE! */
2005-07-13 10:21:28 +07:00
static void search_by_key_reada ( struct super_block * s ,
struct buffer_head * * bh ,
unsigned long * b , int num )
2005-04-17 05:20:36 +07:00
{
2005-07-13 10:21:28 +07:00
int i , j ;
for ( i = 0 ; i < num ; i + + ) {
bh [ i ] = sb_getblk ( s , b [ i ] ) ;
}
for ( j = 0 ; j < i ; j + + ) {
/*
* note , this needs attention if we are getting rid of the BKL
* you have to make sure the prepared bit isn ' t set on this buffer
*/
if ( ! buffer_uptodate ( bh [ j ] ) )
ll_rw_block ( READA , 1 , bh + j ) ;
brelse ( bh [ j ] ) ;
}
2005-04-17 05:20:36 +07:00
}
/**************************************************************************
* Algorithm SearchByKey *
* look for item in the Disk S + Tree by its key *
* Input : p_s_sb - super block *
* p_s_key - pointer to the key to search *
* Output : ITEM_FOUND , ITEM_NOT_FOUND or IO_ERROR *
* p_s_search_path - path from the root to the needed leaf *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* This function fills up the path from the root to the leaf as it
descends the tree looking for the key . It uses reiserfs_bread to
try to find buffers in the cache given their block number . If it
does not find them in the cache it reads them from disk . For each
node search_by_key finds using reiserfs_bread it then uses
bin_search to look through that node . bin_search will find the
position of the block_number of the next node if it is looking
through an internal node . If it is looking through a leaf node
bin_search will find the position of the item which has key either
equal to given key , or which is the maximal key less than the given
key . search_by_key returns a path that must be checked for the
correctness of the top of the path but need not be checked for the
correctness of the bottom of the path */
/* The function is NOT SCHEDULE-SAFE! */
2005-07-13 10:21:28 +07:00
int search_by_key ( struct super_block * p_s_sb , const struct cpu_key * p_s_key , /* Key to search. */
struct path * p_s_search_path , /* This structure was
allocated and initialized
by the calling
function . It is filled up
by this function . */
int n_stop_level /* How far down the tree to search. To
stop at leaf level - set to
DISK_LEAF_NODE_LEVEL */
)
{
int n_block_number ;
int expected_level ;
struct buffer_head * p_s_bh ;
struct path_element * p_s_last_element ;
int n_node_level , n_retval ;
int right_neighbor_of_leaf_node ;
int fs_gen ;
struct buffer_head * reada_bh [ SEARCH_BY_KEY_READA ] ;
unsigned long reada_blocks [ SEARCH_BY_KEY_READA ] ;
int reada_count = 0 ;
2005-04-17 05:20:36 +07:00
# ifdef CONFIG_REISERFS_CHECK
2005-07-13 10:21:28 +07:00
int n_repeat_counter = 0 ;
2005-04-17 05:20:36 +07:00
# endif
2005-07-13 10:21:28 +07:00
PROC_INFO_INC ( p_s_sb , search_by_key ) ;
/* As we add each node to a path we increase its count. This means that
we must be careful to release all nodes in a path before we either
discard the path struct or re - use the path struct , as we do here . */
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
decrement_counters_in_path ( p_s_search_path ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
right_neighbor_of_leaf_node = 0 ;
/* With each iteration of this loop we search through the items in the
current node , and calculate the next current node ( next path element )
for the next iteration of this loop . . */
n_block_number = SB_ROOT_BLOCK ( p_s_sb ) ;
expected_level = - 1 ;
while ( 1 ) {
2005-04-17 05:20:36 +07:00
# ifdef CONFIG_REISERFS_CHECK
2005-07-13 10:21:28 +07:00
if ( ! ( + + n_repeat_counter % 50000 ) )
reiserfs_warning ( p_s_sb , " PAP-5100: search_by_key: %s: "
" there were %d iterations of while loop "
" looking for key %K " ,
current - > comm , n_repeat_counter ,
p_s_key ) ;
2005-04-17 05:20:36 +07:00
# endif
2005-07-13 10:21:28 +07:00
/* prep path to have another element added to it. */
p_s_last_element =
PATH_OFFSET_PELEMENT ( p_s_search_path ,
+ + p_s_search_path - > path_length ) ;
fs_gen = get_generation ( p_s_sb ) ;
/* Read the next tree node, and set the last element in the path to
have a pointer to it . */
if ( ( p_s_bh = p_s_last_element - > pe_buffer =
sb_getblk ( p_s_sb , n_block_number ) ) ) {
if ( ! buffer_uptodate ( p_s_bh ) & & reada_count > 1 ) {
search_by_key_reada ( p_s_sb , reada_bh ,
reada_blocks , reada_count ) ;
}
ll_rw_block ( READ , 1 , & p_s_bh ) ;
wait_on_buffer ( p_s_bh ) ;
if ( ! buffer_uptodate ( p_s_bh ) )
goto io_error ;
} else {
io_error :
p_s_search_path - > path_length - - ;
pathrelse ( p_s_search_path ) ;
return IO_ERROR ;
}
reada_count = 0 ;
if ( expected_level = = - 1 )
expected_level = SB_TREE_HEIGHT ( p_s_sb ) ;
expected_level - - ;
/* It is possible that schedule occurred. We must check whether the key
to search is still in the tree rooted from the current buffer . If
not then repeat search from the root . */
if ( fs_changed ( fs_gen , p_s_sb ) & &
( ! B_IS_IN_TREE ( p_s_bh ) | |
B_LEVEL ( p_s_bh ) ! = expected_level | |
! key_in_buffer ( p_s_search_path , p_s_key , p_s_sb ) ) ) {
PROC_INFO_INC ( p_s_sb , search_by_key_fs_changed ) ;
PROC_INFO_INC ( p_s_sb , search_by_key_restarted ) ;
PROC_INFO_INC ( p_s_sb ,
sbk_restarted [ expected_level - 1 ] ) ;
decrement_counters_in_path ( p_s_search_path ) ;
/* Get the root block number so that we can repeat the search
starting from the root . */
n_block_number = SB_ROOT_BLOCK ( p_s_sb ) ;
expected_level = - 1 ;
right_neighbor_of_leaf_node = 0 ;
/* repeat search from the root */
continue ;
}
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
/* only check that the key is in the buffer if p_s_key is not
equal to the MAX_KEY . Latter case is only possible in
" finish_unfinished() " processing during mount . */
RFALSE ( comp_keys ( & MAX_KEY , p_s_key ) & &
! key_in_buffer ( p_s_search_path , p_s_key , p_s_sb ) ,
" PAP-5130: key is not in the buffer " ) ;
2005-04-17 05:20:36 +07:00
# ifdef CONFIG_REISERFS_CHECK
2005-07-13 10:21:28 +07:00
if ( cur_tb ) {
print_cur_tb ( " 5140 " ) ;
reiserfs_panic ( p_s_sb ,
" PAP-5140: search_by_key: schedule occurred in do_balance! " ) ;
}
2005-04-17 05:20:36 +07:00
# endif
2005-07-13 10:21:28 +07:00
// make sure, that the node contents look like a node of
// certain level
if ( ! is_tree_node ( p_s_bh , expected_level ) ) {
reiserfs_warning ( p_s_sb , " vs-5150: search_by_key: "
" invalid format found in block %ld. Fsck? " ,
p_s_bh - > b_blocknr ) ;
pathrelse ( p_s_search_path ) ;
return IO_ERROR ;
}
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
/* ok, we have acquired next formatted node in the tree */
n_node_level = B_LEVEL ( p_s_bh ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
PROC_INFO_BH_STAT ( p_s_sb , p_s_bh , n_node_level - 1 ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
RFALSE ( n_node_level < n_stop_level ,
" vs-5152: tree level (%d) is less than stop level (%d) " ,
n_node_level , n_stop_level ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
n_retval = bin_search ( p_s_key , B_N_PITEM_HEAD ( p_s_bh , 0 ) ,
B_NR_ITEMS ( p_s_bh ) ,
( n_node_level = =
DISK_LEAF_NODE_LEVEL ) ? IH_SIZE :
KEY_SIZE ,
& ( p_s_last_element - > pe_position ) ) ;
if ( n_node_level = = n_stop_level ) {
return n_retval ;
}
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
/* we are not in the stop level */
if ( n_retval = = ITEM_FOUND )
/* item has been found, so we choose the pointer which is to the right of the found one */
p_s_last_element - > pe_position + + ;
/* if item was not found we choose the position which is to
the left of the found item . This requires no code ,
bin_search did it already . */
/* So we have chosen a position in the current node which is
an internal node . Now we calculate child block number by
position in the node . */
n_block_number =
B_N_CHILD_NUM ( p_s_bh , p_s_last_element - > pe_position ) ;
/* if we are going to read leaf nodes, try for read ahead as well */
if ( ( p_s_search_path - > reada & PATH_READA ) & &
n_node_level = = DISK_LEAF_NODE_LEVEL + 1 ) {
int pos = p_s_last_element - > pe_position ;
int limit = B_NR_ITEMS ( p_s_bh ) ;
struct reiserfs_key * le_key ;
if ( p_s_search_path - > reada & PATH_READA_BACK )
limit = 0 ;
while ( reada_count < SEARCH_BY_KEY_READA ) {
if ( pos = = limit )
break ;
reada_blocks [ reada_count + + ] =
B_N_CHILD_NUM ( p_s_bh , pos ) ;
if ( p_s_search_path - > reada & PATH_READA_BACK )
pos - - ;
else
pos + + ;
/*
* check to make sure we ' re in the same object
*/
le_key = B_N_PDELIM_KEY ( p_s_bh , pos ) ;
if ( le32_to_cpu ( le_key - > k_objectid ) ! =
p_s_key - > on_disk_key . k_objectid ) {
break ;
}
}
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
}
2005-04-17 05:20:36 +07:00
}
/* Form the path to an item and position in this item which contains
file byte defined by p_s_key . If there is no such item
corresponding to the key , we point the path to the item with
maximal key less than p_s_key , and * p_n_pos_in_item is set to one
past the last entry / byte in the item . If searching for entry in a
directory item , and it is not found , * p_n_pos_in_item is set to one
entry more than the entry with maximal key which is less than the
sought key .
Note that if there is no entry in this same node which is one more ,
then we point to an imaginary entry . for direct items , the
position is in units of bytes , for indirect items the position is
in units of blocknr entries , for directory items the position is in
units of directory entries . */
/* The function is NOT SCHEDULE-SAFE! */
2005-07-13 10:21:28 +07:00
int search_for_position_by_key ( struct super_block * p_s_sb , /* Pointer to the super block. */
const struct cpu_key * p_cpu_key , /* Key to search (cpu variable) */
struct path * p_s_search_path /* Filled up by this function. */
)
{
struct item_head * p_le_ih ; /* pointer to on-disk structure */
int n_blk_size ;
loff_t item_offset , offset ;
struct reiserfs_dir_entry de ;
int retval ;
/* If searching for directory entry. */
if ( is_direntry_cpu_key ( p_cpu_key ) )
return search_by_entry_key ( p_s_sb , p_cpu_key , p_s_search_path ,
& de ) ;
/* If not searching for directory entry. */
/* If item is found. */
retval = search_item ( p_s_sb , p_cpu_key , p_s_search_path ) ;
if ( retval = = IO_ERROR )
return retval ;
if ( retval = = ITEM_FOUND ) {
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
RFALSE ( ! ih_item_len
( B_N_PITEM_HEAD
( PATH_PLAST_BUFFER ( p_s_search_path ) ,
PATH_LAST_POSITION ( p_s_search_path ) ) ) ,
" PAP-5165: item length equals zero " ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
pos_in_item ( p_s_search_path ) = 0 ;
return POSITION_FOUND ;
}
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
RFALSE ( ! PATH_LAST_POSITION ( p_s_search_path ) ,
" PAP-5170: position equals zero " ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
/* Item is not found. Set path to the previous item. */
p_le_ih =
B_N_PITEM_HEAD ( PATH_PLAST_BUFFER ( p_s_search_path ) ,
- - PATH_LAST_POSITION ( p_s_search_path ) ) ;
n_blk_size = p_s_sb - > s_blocksize ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
if ( comp_short_keys ( & ( p_le_ih - > ih_key ) , p_cpu_key ) ) {
return FILE_NOT_FOUND ;
}
// FIXME: quite ugly this far
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
item_offset = le_ih_k_offset ( p_le_ih ) ;
offset = cpu_key_k_offset ( p_cpu_key ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
/* Needed byte is contained in the item pointed to by the path. */
if ( item_offset < = offset & &
item_offset + op_bytes_number ( p_le_ih , n_blk_size ) > offset ) {
pos_in_item ( p_s_search_path ) = offset - item_offset ;
if ( is_indirect_le_ih ( p_le_ih ) ) {
pos_in_item ( p_s_search_path ) / = n_blk_size ;
}
return POSITION_FOUND ;
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
/* Needed byte is not contained in the item pointed to by the
path . Set pos_in_item out of the item . */
if ( is_indirect_le_ih ( p_le_ih ) )
pos_in_item ( p_s_search_path ) =
ih_item_len ( p_le_ih ) / UNFM_P_SIZE ;
else
pos_in_item ( p_s_search_path ) = ih_item_len ( p_le_ih ) ;
return POSITION_NOT_FOUND ;
}
2005-04-17 05:20:36 +07:00
/* Compare given item and item pointed to by the path. */
2005-07-13 10:21:28 +07:00
int comp_items ( const struct item_head * stored_ih , const struct path * p_s_path )
2005-04-17 05:20:36 +07:00
{
2005-07-13 10:21:28 +07:00
struct buffer_head * p_s_bh ;
struct item_head * ih ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
/* Last buffer at the path is not in the tree. */
if ( ! B_IS_IN_TREE ( p_s_bh = PATH_PLAST_BUFFER ( p_s_path ) ) )
return 1 ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
/* Last path position is invalid. */
if ( PATH_LAST_POSITION ( p_s_path ) > = B_NR_ITEMS ( p_s_bh ) )
return 1 ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
/* we need only to know, whether it is the same item */
ih = get_ih ( p_s_path ) ;
return memcmp ( stored_ih , ih , IH_SIZE ) ;
2005-04-17 05:20:36 +07:00
}
/* unformatted nodes are not logged anymore, ever. This is safe
* * now
*/
# define held_by_others(bh) (atomic_read(&(bh)->b_count) > 1)
// block can not be forgotten as it is in I/O or held by someone
# define block_in_use(bh) (buffer_locked(bh) || (held_by_others(bh)))
// prepare for delete or cut of direct item
2005-07-13 10:21:28 +07:00
static inline int prepare_for_direct_item ( struct path * path ,
struct item_head * le_ih ,
struct inode * inode ,
loff_t new_file_length , int * cut_size )
2005-04-17 05:20:36 +07:00
{
2005-07-13 10:21:28 +07:00
loff_t round_len ;
if ( new_file_length = = max_reiserfs_offset ( inode ) ) {
/* item has to be deleted */
* cut_size = - ( IH_SIZE + ih_item_len ( le_ih ) ) ;
return M_DELETE ;
}
// new file gets truncated
if ( get_inode_item_key_version ( inode ) = = KEY_FORMAT_3_6 ) {
//
round_len = ROUND_UP ( new_file_length ) ;
/* this was n_new_file_length < le_ih ... */
if ( round_len < le_ih_k_offset ( le_ih ) ) {
* cut_size = - ( IH_SIZE + ih_item_len ( le_ih ) ) ;
return M_DELETE ; /* Delete this item. */
}
/* Calculate first position and size for cutting from item. */
pos_in_item ( path ) = round_len - ( le_ih_k_offset ( le_ih ) - 1 ) ;
* cut_size = - ( ih_item_len ( le_ih ) - pos_in_item ( path ) ) ;
return M_CUT ; /* Cut from this item. */
}
// old file: items may have any length
if ( new_file_length < le_ih_k_offset ( le_ih ) ) {
* cut_size = - ( IH_SIZE + ih_item_len ( le_ih ) ) ;
return M_DELETE ; /* Delete this item. */
2005-04-17 05:20:36 +07:00
}
/* Calculate first position and size for cutting from item. */
2005-07-13 10:21:28 +07:00
* cut_size = - ( ih_item_len ( le_ih ) -
( pos_in_item ( path ) =
new_file_length + 1 - le_ih_k_offset ( le_ih ) ) ) ;
return M_CUT ; /* Cut from this item. */
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
static inline int prepare_for_direntry_item ( struct path * path ,
struct item_head * le_ih ,
struct inode * inode ,
loff_t new_file_length ,
int * cut_size )
2005-04-17 05:20:36 +07:00
{
2005-07-13 10:21:28 +07:00
if ( le_ih_k_offset ( le_ih ) = = DOT_OFFSET & &
new_file_length = = max_reiserfs_offset ( inode ) ) {
RFALSE ( ih_entry_count ( le_ih ) ! = 2 ,
" PAP-5220: incorrect empty directory item (%h) " , le_ih ) ;
* cut_size = - ( IH_SIZE + ih_item_len ( le_ih ) ) ;
return M_DELETE ; /* Delete the directory item containing "." and ".." entry. */
}
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
if ( ih_entry_count ( le_ih ) = = 1 ) {
/* Delete the directory item such as there is one record only
in this item */
* cut_size = - ( IH_SIZE + ih_item_len ( le_ih ) ) ;
return M_DELETE ;
}
/* Cut one record from the directory item. */
* cut_size =
- ( DEH_SIZE +
entry_length ( get_last_bh ( path ) , le_ih , pos_in_item ( path ) ) ) ;
return M_CUT ;
}
2005-04-17 05:20:36 +07:00
/* If the path points to a directory or direct item, calculate mode and the size cut, for balance.
If the path points to an indirect item , remove some number of its unformatted nodes .
In case of file truncate calculate whether this item must be deleted / truncated or last
unformatted node of this item will be converted to a direct item .
This function returns a determination of what balance mode the calling function should employ . */
2005-07-13 10:21:28 +07:00
static char prepare_for_delete_or_cut ( struct reiserfs_transaction_handle * th , struct inode * inode , struct path * p_s_path , const struct cpu_key * p_s_item_key , int * p_n_removed , /* Number of unformatted nodes which were removed
from end of the file . */
int * p_n_cut_size , unsigned long long n_new_file_length /* MAX_KEY_OFFSET in case of delete. */
)
{
struct super_block * p_s_sb = inode - > i_sb ;
struct item_head * p_le_ih = PATH_PITEM_HEAD ( p_s_path ) ;
struct buffer_head * p_s_bh = PATH_PLAST_BUFFER ( p_s_path ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
BUG_ON ( ! th - > t_trans_id ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
/* Stat_data item. */
if ( is_statdata_le_ih ( p_le_ih ) ) {
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
RFALSE ( n_new_file_length ! = max_reiserfs_offset ( inode ) ,
" PAP-5210: mode must be M_DELETE " ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
* p_n_cut_size = - ( IH_SIZE + ih_item_len ( p_le_ih ) ) ;
return M_DELETE ;
}
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
/* Directory item. */
if ( is_direntry_le_ih ( p_le_ih ) )
return prepare_for_direntry_item ( p_s_path , p_le_ih , inode ,
n_new_file_length ,
p_n_cut_size ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
/* Direct item. */
if ( is_direct_le_ih ( p_le_ih ) )
return prepare_for_direct_item ( p_s_path , p_le_ih , inode ,
n_new_file_length , p_n_cut_size ) ;
/* Case of an indirect item. */
{
int n_unfm_number , /* Number of the item unformatted nodes. */
n_counter , n_blk_size ;
__le32 * p_n_unfm_pointer ; /* Pointer to the unformatted node number. */
__u32 tmp ;
struct item_head s_ih ; /* Item header. */
char c_mode ; /* Returned mode of the balance. */
int need_research ;
n_blk_size = p_s_sb - > s_blocksize ;
/* Search for the needed object indirect item until there are no unformatted nodes to be removed. */
do {
need_research = 0 ;
p_s_bh = PATH_PLAST_BUFFER ( p_s_path ) ;
/* Copy indirect item header to a temp variable. */
copy_item_head ( & s_ih , PATH_PITEM_HEAD ( p_s_path ) ) ;
/* Calculate number of unformatted nodes in this item. */
n_unfm_number = I_UNFM_NUM ( & s_ih ) ;
RFALSE ( ! is_indirect_le_ih ( & s_ih ) | | ! n_unfm_number | |
pos_in_item ( p_s_path ) + 1 ! = n_unfm_number ,
" PAP-5240: invalid item %h "
" n_unfm_number = %d *p_n_pos_in_item = %d " ,
& s_ih , n_unfm_number , pos_in_item ( p_s_path ) ) ;
/* Calculate balance mode and position in the item to remove unformatted nodes. */
if ( n_new_file_length = = max_reiserfs_offset ( inode ) ) { /* Case of delete. */
pos_in_item ( p_s_path ) = 0 ;
* p_n_cut_size = - ( IH_SIZE + ih_item_len ( & s_ih ) ) ;
c_mode = M_DELETE ;
} else { /* Case of truncate. */
if ( n_new_file_length < le_ih_k_offset ( & s_ih ) ) {
pos_in_item ( p_s_path ) = 0 ;
* p_n_cut_size =
- ( IH_SIZE + ih_item_len ( & s_ih ) ) ;
c_mode = M_DELETE ; /* Delete this item. */
} else {
/* indirect item must be truncated starting from *p_n_pos_in_item-th position */
pos_in_item ( p_s_path ) =
( n_new_file_length + n_blk_size -
le_ih_k_offset ( & s_ih ) ) > > p_s_sb - >
s_blocksize_bits ;
RFALSE ( pos_in_item ( p_s_path ) >
n_unfm_number ,
" PAP-5250: invalid position in the item " ) ;
/* Either convert last unformatted node of indirect item to direct item or increase
its free space . */
if ( pos_in_item ( p_s_path ) = =
n_unfm_number ) {
* p_n_cut_size = 0 ; /* Nothing to cut. */
return M_CONVERT ; /* Maybe convert last unformatted node to the direct item. */
}
/* Calculate size to cut. */
* p_n_cut_size =
- ( ih_item_len ( & s_ih ) -
pos_in_item ( p_s_path ) *
UNFM_P_SIZE ) ;
c_mode = M_CUT ; /* Cut from this indirect item. */
}
}
RFALSE ( n_unfm_number < = pos_in_item ( p_s_path ) ,
" PAP-5260: invalid position in the indirect item " ) ;
/* pointers to be cut */
n_unfm_number - = pos_in_item ( p_s_path ) ;
/* Set pointer to the last unformatted node pointer that is to be cut. */
p_n_unfm_pointer =
( __le32 * ) B_I_PITEM ( p_s_bh ,
& s_ih ) + I_UNFM_NUM ( & s_ih ) -
1 - * p_n_removed ;
/* We go through the unformatted nodes pointers of the indirect
item and look for the unformatted nodes in the cache . If we
found some of them we free it , zero corresponding indirect item
entry and log buffer containing that indirect item . For this we
need to prepare last path element for logging . If some
unformatted node has b_count > 1 we must not free this
unformatted node since it is in use . */
reiserfs_prepare_for_journal ( p_s_sb , p_s_bh , 1 ) ;
// note: path could be changed, first line in for loop takes care
// of it
for ( n_counter = * p_n_removed ;
n_counter < n_unfm_number ;
n_counter + + , p_n_unfm_pointer - - ) {
cond_resched ( ) ;
if ( item_moved ( & s_ih , p_s_path ) ) {
need_research = 1 ;
break ;
}
RFALSE ( p_n_unfm_pointer <
( __le32 * ) B_I_PITEM ( p_s_bh , & s_ih )
| | p_n_unfm_pointer >
( __le32 * ) B_I_PITEM ( p_s_bh ,
& s_ih ) +
I_UNFM_NUM ( & s_ih ) - 1 ,
" vs-5265: pointer out of range " ) ;
/* Hole, nothing to remove. */
if ( ! get_block_num ( p_n_unfm_pointer , 0 ) ) {
( * p_n_removed ) + + ;
continue ;
}
( * p_n_removed ) + + ;
tmp = get_block_num ( p_n_unfm_pointer , 0 ) ;
put_block_num ( p_n_unfm_pointer , 0 , 0 ) ;
journal_mark_dirty ( th , p_s_sb , p_s_bh ) ;
reiserfs_free_block ( th , inode , tmp , 1 ) ;
if ( item_moved ( & s_ih , p_s_path ) ) {
need_research = 1 ;
break ;
}
}
/* a trick. If the buffer has been logged, this
* * will do nothing . If we ' ve broken the loop without
* * logging it , it will restore the buffer
* *
*/
reiserfs_restore_prepared_buffer ( p_s_sb , p_s_bh ) ;
/* This loop can be optimized. */
} while ( ( * p_n_removed < n_unfm_number | | need_research ) & &
search_for_position_by_key ( p_s_sb , p_s_item_key ,
p_s_path ) = =
POSITION_FOUND ) ;
RFALSE ( * p_n_removed < n_unfm_number ,
" PAP-5310: indirect item is not found " ) ;
RFALSE ( item_moved ( & s_ih , p_s_path ) ,
" after while, comp failed, retry " ) ;
if ( c_mode = = M_CUT )
pos_in_item ( p_s_path ) * = UNFM_P_SIZE ;
return c_mode ;
}
2005-04-17 05:20:36 +07:00
}
/* Calculate number of bytes which will be deleted or cut during balance */
2005-07-13 10:21:28 +07:00
static int calc_deleted_bytes_number ( struct tree_balance * p_s_tb , char c_mode )
{
int n_del_size ;
struct item_head * p_le_ih = PATH_PITEM_HEAD ( p_s_tb - > tb_path ) ;
if ( is_statdata_le_ih ( p_le_ih ) )
return 0 ;
n_del_size =
( c_mode = =
M_DELETE ) ? ih_item_len ( p_le_ih ) : - p_s_tb - > insert_size [ 0 ] ;
if ( is_direntry_le_ih ( p_le_ih ) ) {
// return EMPTY_DIR_SIZE; /* We delete emty directoris only. */
// we can't use EMPTY_DIR_SIZE, as old format dirs have a different
// empty size. ick. FIXME, is this right?
//
return n_del_size ;
}
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
if ( is_indirect_le_ih ( p_le_ih ) )
n_del_size = ( n_del_size / UNFM_P_SIZE ) * ( PATH_PLAST_BUFFER ( p_s_tb - > tb_path ) - > b_size ) ; // - get_ih_free_space (p_le_ih);
return n_del_size ;
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
static void init_tb_struct ( struct reiserfs_transaction_handle * th ,
struct tree_balance * p_s_tb ,
struct super_block * p_s_sb ,
struct path * p_s_path , int n_size )
{
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
BUG_ON ( ! th - > t_trans_id ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
memset ( p_s_tb , ' \0 ' , sizeof ( struct tree_balance ) ) ;
p_s_tb - > transaction_handle = th ;
p_s_tb - > tb_sb = p_s_sb ;
p_s_tb - > tb_path = p_s_path ;
PATH_OFFSET_PBUFFER ( p_s_path , ILLEGAL_PATH_ELEMENT_OFFSET ) = NULL ;
PATH_OFFSET_POSITION ( p_s_path , ILLEGAL_PATH_ELEMENT_OFFSET ) = 0 ;
p_s_tb - > insert_size [ 0 ] = n_size ;
}
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
void padd_item ( char * item , int total_length , int length )
2005-04-17 05:20:36 +07:00
{
2005-07-13 10:21:28 +07:00
int i ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
for ( i = total_length ; i > length ; )
item [ - - i ] = 0 ;
2005-04-17 05:20:36 +07:00
}
# ifdef REISERQUOTA_DEBUG
char key2type ( struct reiserfs_key * ih )
{
2005-07-13 10:21:28 +07:00
if ( is_direntry_le_key ( 2 , ih ) )
return ' d ' ;
if ( is_direct_le_key ( 2 , ih ) )
return ' D ' ;
if ( is_indirect_le_key ( 2 , ih ) )
return ' i ' ;
if ( is_statdata_le_key ( 2 , ih ) )
return ' s ' ;
return ' u ' ;
2005-04-17 05:20:36 +07:00
}
char head2type ( struct item_head * ih )
{
2005-07-13 10:21:28 +07:00
if ( is_direntry_le_ih ( ih ) )
return ' d ' ;
if ( is_direct_le_ih ( ih ) )
return ' D ' ;
if ( is_indirect_le_ih ( ih ) )
return ' i ' ;
if ( is_statdata_le_ih ( ih ) )
return ' s ' ;
return ' u ' ;
2005-04-17 05:20:36 +07:00
}
# endif
/* Delete object item. */
2005-07-13 10:21:28 +07:00
int reiserfs_delete_item ( struct reiserfs_transaction_handle * th , struct path * p_s_path , /* Path to the deleted item. */
const struct cpu_key * p_s_item_key , /* Key to search for the deleted item. */
struct inode * p_s_inode , /* inode is here just to update i_blocks and quotas */
struct buffer_head * p_s_un_bh )
{ /* NULL or unformatted node pointer. */
struct super_block * p_s_sb = p_s_inode - > i_sb ;
struct tree_balance s_del_balance ;
struct item_head s_ih ;
struct item_head * q_ih ;
int quota_cut_bytes ;
int n_ret_value , n_del_size , n_removed ;
2005-04-17 05:20:36 +07:00
# ifdef CONFIG_REISERFS_CHECK
2005-07-13 10:21:28 +07:00
char c_mode ;
int n_iter = 0 ;
2005-04-17 05:20:36 +07:00
# endif
2005-07-13 10:21:28 +07:00
BUG_ON ( ! th - > t_trans_id ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
init_tb_struct ( th , & s_del_balance , p_s_sb , p_s_path ,
0 /*size is unknown */ ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
while ( 1 ) {
n_removed = 0 ;
2005-04-17 05:20:36 +07:00
# ifdef CONFIG_REISERFS_CHECK
2005-07-13 10:21:28 +07:00
n_iter + + ;
c_mode =
2005-04-17 05:20:36 +07:00
# endif
2005-07-13 10:21:28 +07:00
prepare_for_delete_or_cut ( th , p_s_inode , p_s_path ,
p_s_item_key , & n_removed ,
& n_del_size ,
max_reiserfs_offset ( p_s_inode ) ) ;
RFALSE ( c_mode ! = M_DELETE , " PAP-5320: mode must be M_DELETE " ) ;
copy_item_head ( & s_ih , PATH_PITEM_HEAD ( p_s_path ) ) ;
s_del_balance . insert_size [ 0 ] = n_del_size ;
n_ret_value = fix_nodes ( M_DELETE , & s_del_balance , NULL , NULL ) ;
if ( n_ret_value ! = REPEAT_SEARCH )
break ;
PROC_INFO_INC ( p_s_sb , delete_item_restarted ) ;
// file system changed, repeat search
n_ret_value =
search_for_position_by_key ( p_s_sb , p_s_item_key , p_s_path ) ;
if ( n_ret_value = = IO_ERROR )
break ;
if ( n_ret_value = = FILE_NOT_FOUND ) {
reiserfs_warning ( p_s_sb ,
" vs-5340: reiserfs_delete_item: "
" no items of the file %K found " ,
p_s_item_key ) ;
break ;
}
} /* while (1) */
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
if ( n_ret_value ! = CARRY_ON ) {
unfix_nodes ( & s_del_balance ) ;
return 0 ;
}
// reiserfs_delete_item returns item length when success
n_ret_value = calc_deleted_bytes_number ( & s_del_balance , M_DELETE ) ;
q_ih = get_ih ( p_s_path ) ;
quota_cut_bytes = ih_item_len ( q_ih ) ;
/* hack so the quota code doesn't have to guess if the file
* * has a tail . On tail insert , we allocate quota for 1 unformatted node .
* * We test the offset because the tail might have been
* * split into multiple items , and we only want to decrement for
* * the unfm node once
*/
if ( ! S_ISLNK ( p_s_inode - > i_mode ) & & is_direct_le_ih ( q_ih ) ) {
if ( ( le_ih_k_offset ( q_ih ) & ( p_s_sb - > s_blocksize - 1 ) ) = = 1 ) {
quota_cut_bytes = p_s_sb - > s_blocksize + UNFM_P_SIZE ;
} else {
quota_cut_bytes = 0 ;
}
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
if ( p_s_un_bh ) {
int off ;
char * data ;
/* We are in direct2indirect conversion, so move tail contents
to the unformatted node */
/* note, we do the copy before preparing the buffer because we
* * don ' t care about the contents of the unformatted node yet .
* * the only thing we really care about is the direct item ' s data
* * is in the unformatted node .
* *
* * Otherwise , we would have to call reiserfs_prepare_for_journal on
* * the unformatted node , which might schedule , meaning we ' d have to
* * loop all the way back up to the start of the while loop .
* *
* * The unformatted node must be dirtied later on . We can ' t be
* * sure here if the entire tail has been deleted yet .
* *
* * p_s_un_bh is from the page cache ( all unformatted nodes are
* * from the page cache ) and might be a highmem page . So , we
* * can ' t use p_s_un_bh - > b_data .
* * - clm
*/
data = kmap_atomic ( p_s_un_bh - > b_page , KM_USER0 ) ;
off = ( ( le_ih_k_offset ( & s_ih ) - 1 ) & ( PAGE_CACHE_SIZE - 1 ) ) ;
memcpy ( data + off ,
B_I_PITEM ( PATH_PLAST_BUFFER ( p_s_path ) , & s_ih ) ,
n_ret_value ) ;
kunmap_atomic ( data , KM_USER0 ) ;
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
/* Perform balancing after all resources have been collected at once. */
do_balance ( & s_del_balance , NULL , NULL , M_DELETE ) ;
2005-04-17 05:20:36 +07:00
# ifdef REISERQUOTA_DEBUG
2005-07-13 10:21:28 +07:00
reiserfs_debug ( p_s_sb , REISERFS_DEBUG_CODE ,
" reiserquota delete_item(): freeing %u, id=%u type=%c " ,
quota_cut_bytes , p_s_inode - > i_uid , head2type ( & s_ih ) ) ;
2005-04-17 05:20:36 +07:00
# endif
2005-07-13 10:21:28 +07:00
DQUOT_FREE_SPACE_NODIRTY ( p_s_inode , quota_cut_bytes ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
/* Return deleted body length */
return n_ret_value ;
2005-04-17 05:20:36 +07:00
}
/* Summary Of Mechanisms For Handling Collisions Between Processes:
deletion of the body of the object is performed by iput ( ) , with the
result that if multiple processes are operating on a file , the
deletion of the body of the file is deferred until the last process
that has an open inode performs its iput ( ) .
writes and truncates are protected from collisions by use of
semaphores .
creates , linking , and mknod are protected from collisions with other
processes by making the reiserfs_add_entry ( ) the last step in the
creation , and then rolling back all changes if there was a collision .
- Hans
*/
/* this deletes item which never gets split */
2005-07-13 10:21:28 +07:00
void reiserfs_delete_solid_item ( struct reiserfs_transaction_handle * th ,
struct inode * inode , struct reiserfs_key * key )
2005-04-17 05:20:36 +07:00
{
2005-07-13 10:21:28 +07:00
struct tree_balance tb ;
INITIALIZE_PATH ( path ) ;
int item_len = 0 ;
int tb_init = 0 ;
struct cpu_key cpu_key ;
int retval ;
int quota_cut_bytes = 0 ;
BUG_ON ( ! th - > t_trans_id ) ;
le_key2cpu_key ( & cpu_key , key ) ;
while ( 1 ) {
retval = search_item ( th - > t_super , & cpu_key , & path ) ;
if ( retval = = IO_ERROR ) {
reiserfs_warning ( th - > t_super ,
" vs-5350: reiserfs_delete_solid_item: "
" i/o failure occurred trying to delete %K " ,
& cpu_key ) ;
break ;
}
if ( retval ! = ITEM_FOUND ) {
pathrelse ( & path ) ;
// No need for a warning, if there is just no free space to insert '..' item into the newly-created subdir
if ( !
( ( unsigned long long )
GET_HASH_VALUE ( le_key_k_offset
( le_key_version ( key ) , key ) ) = = 0
& & ( unsigned long long )
GET_GENERATION_NUMBER ( le_key_k_offset
( le_key_version ( key ) ,
key ) ) = = 1 ) )
reiserfs_warning ( th - > t_super ,
" vs-5355: reiserfs_delete_solid_item: %k not found " ,
key ) ;
break ;
}
if ( ! tb_init ) {
tb_init = 1 ;
item_len = ih_item_len ( PATH_PITEM_HEAD ( & path ) ) ;
init_tb_struct ( th , & tb , th - > t_super , & path ,
- ( IH_SIZE + item_len ) ) ;
}
quota_cut_bytes = ih_item_len ( PATH_PITEM_HEAD ( & path ) ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
retval = fix_nodes ( M_DELETE , & tb , NULL , NULL ) ;
if ( retval = = REPEAT_SEARCH ) {
PROC_INFO_INC ( th - > t_super , delete_solid_item_restarted ) ;
continue ;
}
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
if ( retval = = CARRY_ON ) {
do_balance ( & tb , NULL , NULL , M_DELETE ) ;
if ( inode ) { /* Should we count quota for item? (we don't count quotas for save-links) */
2005-04-17 05:20:36 +07:00
# ifdef REISERQUOTA_DEBUG
2005-07-13 10:21:28 +07:00
reiserfs_debug ( th - > t_super , REISERFS_DEBUG_CODE ,
" reiserquota delete_solid_item(): freeing %u id=%u type=%c " ,
quota_cut_bytes , inode - > i_uid ,
key2type ( key ) ) ;
2005-04-17 05:20:36 +07:00
# endif
2005-07-13 10:21:28 +07:00
DQUOT_FREE_SPACE_NODIRTY ( inode ,
quota_cut_bytes ) ;
}
break ;
}
// IO_ERROR, NO_DISK_SPACE, etc
reiserfs_warning ( th - > t_super ,
" vs-5360: reiserfs_delete_solid_item: "
" could not delete %K due to fix_nodes failure " ,
& cpu_key ) ;
unfix_nodes ( & tb ) ;
break ;
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
reiserfs_check_path ( & path ) ;
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
int reiserfs_delete_object ( struct reiserfs_transaction_handle * th ,
struct inode * inode )
2005-04-17 05:20:36 +07:00
{
2005-07-13 10:21:28 +07:00
int err ;
inode - > i_size = 0 ;
BUG_ON ( ! th - > t_trans_id ) ;
/* for directory this deletes item containing "." and ".." */
err =
reiserfs_do_truncate ( th , inode , NULL , 0 /*no timestamp updates */ ) ;
if ( err )
return err ;
2005-04-17 05:20:36 +07:00
# if defined( USE_INODE_GENERATION_COUNTER )
2005-07-13 10:21:28 +07:00
if ( ! old_format_only ( th - > t_super ) ) {
__le32 * inode_generation ;
inode_generation =
& REISERFS_SB ( th - > t_super ) - > s_rs - > s_inode_generation ;
* inode_generation =
cpu_to_le32 ( le32_to_cpu ( * inode_generation ) + 1 ) ;
}
2005-04-17 05:20:36 +07:00
/* USE_INODE_GENERATION_COUNTER */
# endif
2005-07-13 10:21:28 +07:00
reiserfs_delete_solid_item ( th , inode , INODE_PKEY ( inode ) ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
return err ;
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
static void unmap_buffers ( struct page * page , loff_t pos )
{
struct buffer_head * bh ;
struct buffer_head * head ;
struct buffer_head * next ;
unsigned long tail_index ;
unsigned long cur_index ;
if ( page ) {
if ( page_has_buffers ( page ) ) {
tail_index = pos & ( PAGE_CACHE_SIZE - 1 ) ;
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 ) ;
}
2005-04-17 05:20:36 +07:00
}
}
}
2005-07-13 10:21:28 +07:00
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 ;
BUG_ON ( ! th - > t_trans_id ) ;
if ( n_new_file_size ! = p_s_inode - > i_size )
BUG ( ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
/* 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 ) ;
}
2005-04-17 05:20:36 +07:00
/* 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 ) */
2005-07-13 10:21:28 +07:00
static void indirect_to_direct_roll_back ( struct reiserfs_transaction_handle * th ,
struct inode * inode , struct path * path )
2005-04-17 05:20:36 +07:00
{
2005-07-13 10:21:28 +07:00
struct cpu_key tail_key ;
int tail_len ;
int removed ;
BUG_ON ( ! th - > t_trans_id ) ;
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 ) ;
2005-04-17 05:20:36 +07:00
}
/* (Truncate or cut entry) or delete object item. Returns < 0 on failure */
2005-07-13 10:21:28 +07:00
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 )
2005-04-17 05:20:36 +07:00
{
2005-07-13 10:21:28 +07:00
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 ;
BUG_ON ( ! th - > t_trans_id ) ;
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 ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
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 ;
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
/* 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 ;
}
2005-04-17 05:20:36 +07:00
}
# ifdef CONFIG_REISERFS_CHECK
2005-07-13 10:21:28 +07:00
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 */
2005-04-17 05:20:36 +07:00
}
# endif
2005-07-13 10:21:28 +07:00
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 ;
}
2005-04-17 05:20:36 +07:00
# ifdef REISERQUOTA_DEBUG
2005-07-13 10:21:28 +07:00
reiserfs_debug ( p_s_inode - > i_sb , REISERFS_DEBUG_CODE ,
" reiserquota cut_from_item(): freeing %u id=%u type=%c " ,
quota_cut_bytes , p_s_inode - > i_uid , ' ? ' ) ;
2005-04-17 05:20:36 +07:00
# endif
2005-07-13 10:21:28 +07:00
DQUOT_FREE_SPACE_NODIRTY ( p_s_inode , quota_cut_bytes ) ;
return n_ret_value ;
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
static void truncate_directory ( struct reiserfs_transaction_handle * th ,
struct inode * inode )
2005-04-17 05:20:36 +07:00
{
2005-07-13 10:21:28 +07:00
BUG_ON ( ! th - > t_trans_id ) ;
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 ) ;
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
/* Truncate file to the new size. Note, this must be called with a transaction
already started */
int 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 ;
int err = 0 ;
BUG_ON ( ! th - > t_trans_id ) ;
if ( !
( S_ISREG ( p_s_inode - > i_mode ) | | S_ISDIR ( p_s_inode - > i_mode )
| | S_ISLNK ( p_s_inode - > i_mode ) ) )
return 0 ;
if ( S_ISDIR ( p_s_inode - > i_mode ) ) {
// deletion of directory - no need to update timestamps
truncate_directory ( th , p_s_inode ) ;
return 0 ;
}
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
/* Get new file size. */
n_new_file_size = p_s_inode - > i_size ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
// 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 ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
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 ) ;
err = - EIO ;
goto out ;
}
if ( retval = = POSITION_FOUND | | retval = = FILE_NOT_FOUND ) {
reiserfs_warning ( p_s_inode - > i_sb ,
" PAP-5660: reiserfs_do_truncate: "
" wrong result %d of search for %K " , retval ,
& s_item_key ) ;
err = - EIO ;
goto out ;
}
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
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 ;
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
/* 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 0 ;
}
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
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 ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
/* Change key to search the last file item. */
n_file_size - = n_deleted ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
set_cpu_key_k_offset ( & s_item_key , n_file_size ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
/* While there are bytes to truncate and previous file item is presented in the tree. */
/*
* * This loop could take a really long time , and could log
* * many more blocks than a transaction can hold . So , we do a polite
* * journal end here , and if the transaction needs ending , we make
* * sure the file is consistent before ending the current trans
* * and starting a new one
*/
if ( journal_transaction_should_end ( th , th - > t_blocks_allocated ) ) {
int orig_len_alloc = th - > t_blocks_allocated ;
decrement_counters_in_path ( & s_search_path ) ;
if ( update_timestamps ) {
p_s_inode - > i_mtime = p_s_inode - > i_ctime =
CURRENT_TIME_SEC ;
}
reiserfs_update_sd ( th , p_s_inode ) ;
err = journal_end ( th , p_s_inode - > i_sb , orig_len_alloc ) ;
if ( err )
goto out ;
err = journal_begin ( th , p_s_inode - > i_sb ,
JOURNAL_PER_BALANCE_CNT * 6 ) ;
if ( err )
goto out ;
reiserfs_update_inode_transaction ( p_s_inode ) ;
}
} while ( n_file_size > ROUND_UP ( n_new_file_size ) & &
search_for_position_by_key ( p_s_inode - > i_sb , & s_item_key ,
& s_search_path ) = = POSITION_FOUND ) ;
RFALSE ( n_file_size > ROUND_UP ( n_new_file_size ) ,
" PAP-5680: truncate did not finish: new_file_size %Ld, current %Ld, oid %d " ,
n_new_file_size , n_file_size , s_item_key . on_disk_key . k_objectid ) ;
update_and_out :
if ( update_timestamps ) {
// this is truncate, not file closing
p_s_inode - > i_mtime = p_s_inode - > i_ctime = CURRENT_TIME_SEC ;
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
reiserfs_update_sd ( th , p_s_inode ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
out :
pathrelse ( & s_search_path ) ;
return err ;
}
2005-04-17 05:20:36 +07:00
# ifdef CONFIG_REISERFS_CHECK
// this makes sure, that we __append__, not overwrite or add holes
2005-07-13 10:21:28 +07:00
static void check_research_for_paste ( struct path * path ,
const struct cpu_key * p_s_key )
2005-04-17 05:20:36 +07:00
{
2005-07-13 10:21:28 +07:00
struct item_head * found_ih = get_ih ( path ) ;
if ( is_direct_le_ih ( found_ih ) ) {
if ( le_ih_k_offset ( found_ih ) +
op_bytes_number ( found_ih ,
get_last_bh ( path ) - > b_size ) ! =
cpu_key_k_offset ( p_s_key )
| | op_bytes_number ( found_ih ,
get_last_bh ( path ) - > b_size ) ! =
pos_in_item ( path ) )
reiserfs_panic ( NULL ,
" PAP-5720: check_research_for_paste: "
" found direct item %h or position (%d) does not match to key %K " ,
found_ih , pos_in_item ( path ) , p_s_key ) ;
}
if ( is_indirect_le_ih ( found_ih ) ) {
if ( le_ih_k_offset ( found_ih ) +
op_bytes_number ( found_ih ,
get_last_bh ( path ) - > b_size ) ! =
cpu_key_k_offset ( p_s_key )
| | I_UNFM_NUM ( found_ih ) ! = pos_in_item ( path )
| | get_ih_free_space ( found_ih ) ! = 0 )
reiserfs_panic ( NULL ,
" PAP-5730: check_research_for_paste: "
" found indirect item (%h) or position (%d) does not match to key (%K) " ,
found_ih , pos_in_item ( path ) , p_s_key ) ;
}
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
# endif /* config reiserfs check */
2005-04-17 05:20:36 +07:00
/* Paste bytes to the existing item. Returns bytes number pasted into the item. */
2005-07-13 10:21:28 +07:00
int reiserfs_paste_into_item ( struct reiserfs_transaction_handle * th , struct path * p_s_search_path , /* Path to the pasted item. */
const struct cpu_key * p_s_key , /* Key to search for the needed item. */
struct inode * inode , /* Inode item belongs to */
const char * p_c_body , /* Pointer to the bytes to paste. */
int n_pasted_size )
{ /* Size of pasted bytes. */
struct tree_balance s_paste_balance ;
int retval ;
int fs_gen ;
BUG_ON ( ! th - > t_trans_id ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
fs_gen = get_generation ( inode - > i_sb ) ;
2005-04-17 05:20:36 +07:00
# ifdef REISERQUOTA_DEBUG
2005-07-13 10:21:28 +07:00
reiserfs_debug ( inode - > i_sb , REISERFS_DEBUG_CODE ,
" reiserquota paste_into_item(): allocating %u id=%u type=%c " ,
n_pasted_size , inode - > i_uid ,
key2type ( & ( p_s_key - > on_disk_key ) ) ) ;
2005-04-17 05:20:36 +07:00
# endif
2005-07-13 10:21:28 +07:00
if ( DQUOT_ALLOC_SPACE_NODIRTY ( inode , n_pasted_size ) ) {
pathrelse ( p_s_search_path ) ;
return - EDQUOT ;
}
init_tb_struct ( th , & s_paste_balance , th - > t_super , p_s_search_path ,
n_pasted_size ) ;
2005-04-17 05:20:36 +07:00
# ifdef DISPLACE_NEW_PACKING_LOCALITIES
2005-07-13 10:21:28 +07:00
s_paste_balance . key = p_s_key - > on_disk_key ;
2005-04-17 05:20:36 +07:00
# endif
2005-07-13 10:21:28 +07:00
/* DQUOT_* can schedule, must check before the fix_nodes */
if ( fs_changed ( fs_gen , inode - > i_sb ) ) {
goto search_again ;
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
while ( ( retval =
fix_nodes ( M_PASTE , & s_paste_balance , NULL ,
p_c_body ) ) = = REPEAT_SEARCH ) {
search_again :
/* file system changed while we were in the fix_nodes */
PROC_INFO_INC ( th - > t_super , paste_into_item_restarted ) ;
retval =
search_for_position_by_key ( th - > t_super , p_s_key ,
p_s_search_path ) ;
if ( retval = = IO_ERROR ) {
retval = - EIO ;
goto error_out ;
}
if ( retval = = POSITION_FOUND ) {
reiserfs_warning ( inode - > i_sb ,
" PAP-5710: reiserfs_paste_into_item: entry or pasted byte (%K) exists " ,
p_s_key ) ;
retval = - EEXIST ;
goto error_out ;
}
2005-04-17 05:20:36 +07:00
# ifdef CONFIG_REISERFS_CHECK
2005-07-13 10:21:28 +07:00
check_research_for_paste ( p_s_search_path , p_s_key ) ;
2005-04-17 05:20:36 +07:00
# endif
2005-07-13 10:21:28 +07:00
}
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
/* Perform balancing after all resources are collected by fix_nodes, and
accessing them will not risk triggering schedule . */
if ( retval = = CARRY_ON ) {
do_balance ( & s_paste_balance , NULL /*ih */ , p_c_body , M_PASTE ) ;
return 0 ;
}
retval = ( retval = = NO_DISK_SPACE ) ? - ENOSPC : - EIO ;
error_out :
/* this also releases the path */
unfix_nodes ( & s_paste_balance ) ;
2005-04-17 05:20:36 +07:00
# ifdef REISERQUOTA_DEBUG
2005-07-13 10:21:28 +07:00
reiserfs_debug ( inode - > i_sb , REISERFS_DEBUG_CODE ,
" reiserquota paste_into_item(): freeing %u id=%u type=%c " ,
n_pasted_size , inode - > i_uid ,
key2type ( & ( p_s_key - > on_disk_key ) ) ) ;
2005-04-17 05:20:36 +07:00
# endif
2005-07-13 10:21:28 +07:00
DQUOT_FREE_SPACE_NODIRTY ( inode , n_pasted_size ) ;
return retval ;
2005-04-17 05:20:36 +07:00
}
/* Insert new item into the buffer at the path. */
2005-07-13 10:21:28 +07:00
int reiserfs_insert_item ( struct reiserfs_transaction_handle * th , struct path * p_s_path , /* Path to the inserteded item. */
const struct cpu_key * key , struct item_head * p_s_ih , /* Pointer to the item header to insert. */
struct inode * inode , const char * p_c_body )
{ /* Pointer to the bytes to insert. */
struct tree_balance s_ins_balance ;
int retval ;
int fs_gen = 0 ;
int quota_bytes = 0 ;
BUG_ON ( ! th - > t_trans_id ) ;
if ( inode ) { /* Do we count quotas for item? */
fs_gen = get_generation ( inode - > i_sb ) ;
quota_bytes = ih_item_len ( p_s_ih ) ;
/* hack so the quota code doesn't have to guess if the file has
* * a tail , links are always tails , so there ' s no guessing needed
*/
if ( ! S_ISLNK ( inode - > i_mode ) & & is_direct_le_ih ( p_s_ih ) ) {
quota_bytes = inode - > i_sb - > s_blocksize + UNFM_P_SIZE ;
}
2005-04-17 05:20:36 +07:00
# ifdef REISERQUOTA_DEBUG
2005-07-13 10:21:28 +07:00
reiserfs_debug ( inode - > i_sb , REISERFS_DEBUG_CODE ,
" reiserquota insert_item(): allocating %u id=%u type=%c " ,
quota_bytes , inode - > i_uid , head2type ( p_s_ih ) ) ;
2005-04-17 05:20:36 +07:00
# endif
2005-07-13 10:21:28 +07:00
/* We can't dirty inode here. It would be immediately written but
* appropriate stat item isn ' t inserted yet . . . */
if ( DQUOT_ALLOC_SPACE_NODIRTY ( inode , quota_bytes ) ) {
pathrelse ( p_s_path ) ;
return - EDQUOT ;
}
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
init_tb_struct ( th , & s_ins_balance , th - > t_super , p_s_path ,
IH_SIZE + ih_item_len ( p_s_ih ) ) ;
2005-04-17 05:20:36 +07:00
# ifdef DISPLACE_NEW_PACKING_LOCALITIES
2005-07-13 10:21:28 +07:00
s_ins_balance . key = key - > on_disk_key ;
2005-04-17 05:20:36 +07:00
# endif
2005-07-13 10:21:28 +07:00
/* DQUOT_* can schedule, must check to be sure calling fix_nodes is safe */
if ( inode & & fs_changed ( fs_gen , inode - > i_sb ) ) {
goto search_again ;
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
while ( ( retval =
fix_nodes ( M_INSERT , & s_ins_balance , p_s_ih ,
p_c_body ) ) = = REPEAT_SEARCH ) {
search_again :
/* file system changed while we were in the fix_nodes */
PROC_INFO_INC ( th - > t_super , insert_item_restarted ) ;
retval = search_item ( th - > t_super , key , p_s_path ) ;
if ( retval = = IO_ERROR ) {
retval = - EIO ;
goto error_out ;
}
if ( retval = = ITEM_FOUND ) {
reiserfs_warning ( th - > t_super ,
" PAP-5760: reiserfs_insert_item: "
" key %K already exists in the tree " ,
key ) ;
retval = - EEXIST ;
goto error_out ;
}
2005-04-17 05:20:36 +07:00
}
2005-07-13 10:21:28 +07:00
/* make balancing after all resources will be collected at a time */
if ( retval = = CARRY_ON ) {
do_balance ( & s_ins_balance , p_s_ih , p_c_body , M_INSERT ) ;
return 0 ;
}
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
retval = ( retval = = NO_DISK_SPACE ) ? - ENOSPC : - EIO ;
error_out :
/* also releases the path */
unfix_nodes ( & s_ins_balance ) ;
2005-04-17 05:20:36 +07:00
# ifdef REISERQUOTA_DEBUG
2005-07-13 10:21:28 +07:00
reiserfs_debug ( th - > t_super , REISERFS_DEBUG_CODE ,
" reiserquota insert_item(): freeing %u id=%u type=%c " ,
quota_bytes , inode - > i_uid , head2type ( p_s_ih ) ) ;
2005-04-17 05:20:36 +07:00
# endif
2005-07-13 10:21:28 +07:00
if ( inode )
DQUOT_FREE_SPACE_NODIRTY ( inode , quota_bytes ) ;
return retval ;
2005-04-17 05:20:36 +07:00
}