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
* 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/time.h>
# include <linux/string.h>
# include <linux/pagemap.h>
# include <linux/reiserfs_fs.h>
# include <linux/buffer_head.h>
# include <linux/quotaops.h>
/* Does the buffer contain a disk block which is in the tree. */
2009-03-31 01:02:46 +07:00
inline int B_IS_IN_TREE ( const struct buffer_head * bh )
2005-04-17 05:20:36 +07:00
{
2009-03-31 01:02:46 +07:00
RFALSE ( B_LEVEL ( bh ) > MAX_HEIGHT ,
" PAP-1010: block (%b) has too big level (%z) " , bh , bh ) ;
2005-04-17 05:20:36 +07:00
2009-03-31 01:02:46 +07:00
return ( B_LEVEL ( bh ) ! = FREE_LEVEL ) ;
2005-04-17 05:20:36 +07:00
}
//
// to gets item head in le form
//
2009-03-31 01:02:49 +07:00
inline void copy_item_head ( struct item_head * to ,
const struct item_head * from )
2005-04-17 05:20:36 +07:00
{
2009-03-31 01:02:49 +07:00
memcpy ( to , 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.
2009-03-31 01:02:44 +07:00
Returns : - 1 if key1 < key2
2005-04-17 05:20:36 +07:00
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
{
2009-03-31 01:02:49 +07:00
__u32 * k1_u32 , * k2_u32 ;
2009-03-31 01:02:50 +07:00
int key_length = REISERFS_SHORT_KEY_LEN ;
2005-07-13 10:21:28 +07:00
2009-03-31 01:02:49 +07:00
k1_u32 = ( __u32 * ) key1 ;
k2_u32 = ( __u32 * ) key2 ;
2009-03-31 01:02:50 +07:00
for ( ; key_length - - ; + + k1_u32 , + + k2_u32 ) {
2009-03-31 01:02:49 +07:00
if ( le32_to_cpu ( * k1_u32 ) < le32_to_cpu ( * k2_u32 ) )
2005-07-13 10:21:28 +07:00
return - 1 ;
2009-03-31 01:02:49 +07:00
if ( le32_to_cpu ( * k1_u32 ) > le32_to_cpu ( * k2_u32 ) )
2005-07-13 10:21:28 +07:00
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 ; *
2009-03-31 01:02:49 +07:00
* * pos = number of the searched element if found , else the *
* number of the first element that is larger than key . *
2005-04-17 05:20:36 +07:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-03-31 01:02:50 +07:00
/* For those not familiar with binary search: lbound is the leftmost item that it
could be , rbound the rightmost item that it could be . We examine the item
halfway between lbound and rbound , and that tells us either that we can increase
lbound , or decrease rbound , or that we have found it , or if lbound < = rbound that
2005-04-17 05:20:36 +07:00
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 . */
2009-03-31 01:02:49 +07:00
static inline int bin_search ( const void * key , /* Key to search for. */
const void * base , /* First item in the array. */
int num , /* Number of items in the array. */
int 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 , width
is actually the item header size not
the item size . */
int * pos /* Number of the searched for element. */
2005-07-13 10:21:28 +07:00
)
{
2009-03-31 01:02:50 +07:00
int rbound , lbound , j ;
2005-07-13 10:21:28 +07:00
2009-03-31 01:02:50 +07:00
for ( j = ( ( rbound = num - 1 ) + ( lbound = 0 ) ) / 2 ;
lbound < = rbound ; j = ( rbound + lbound ) / 2 )
2005-07-13 10:21:28 +07:00
switch ( comp_keys
2009-03-31 01:02:50 +07:00
( ( struct reiserfs_key * ) ( ( char * ) base + j * width ) ,
2009-03-31 01:02:49 +07:00
( struct cpu_key * ) key ) ) {
2005-07-13 10:21:28 +07:00
case - 1 :
2009-03-31 01:02:50 +07:00
lbound = j + 1 ;
2005-07-13 10:21:28 +07:00
continue ;
case 1 :
2009-03-31 01:02:50 +07:00
rbound = j - 1 ;
2005-07-13 10:21:28 +07:00
continue ;
case 0 :
2009-03-31 01:02:50 +07:00
* pos = j ;
2005-07-13 10:21:28 +07:00
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 . */
2009-03-31 01:02:50 +07:00
* pos = lbound ;
2005-07-13 10:21:28 +07:00
return ITEM_NOT_FOUND ;
2005-04-17 05:20:36 +07:00
}
/* 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 . */
2009-03-31 01:02:50 +07:00
static inline const struct reiserfs_key * get_lkey ( const struct treepath * chk_path ,
const struct super_block * sb )
2005-07-13 10:21:28 +07:00
{
2009-03-31 01:02:50 +07:00
int position , path_offset = chk_path - > path_length ;
2009-03-31 01:02:49 +07:00
struct buffer_head * parent ;
2005-07-13 10:21:28 +07:00
2009-03-31 01:02:50 +07:00
RFALSE ( path_offset < FIRST_PATH_ELEMENT_OFFSET ,
2005-07-13 10:21:28 +07:00
" PAP-5010: invalid offset in the path " ) ;
/* While not higher in path than first element. */
2009-03-31 01:02:50 +07:00
while ( path_offset - - > FIRST_PATH_ELEMENT_OFFSET ) {
2005-07-13 10:21:28 +07:00
RFALSE ( ! buffer_uptodate
2009-03-31 01:02:50 +07:00
( PATH_OFFSET_PBUFFER ( chk_path , path_offset ) ) ,
2005-07-13 10:21:28 +07:00
" PAP-5020: parent is not uptodate " ) ;
/* Parent at the path is not in the tree now. */
if ( ! B_IS_IN_TREE
2009-03-31 01:02:49 +07:00
( parent =
2009-03-31 01:02:50 +07:00
PATH_OFFSET_PBUFFER ( chk_path , path_offset ) ) )
2005-07-13 10:21:28 +07:00
return & MAX_KEY ;
/* Check whether position in the parent is correct. */
2009-03-31 01:02:50 +07:00
if ( ( position =
2009-03-31 01:02:49 +07:00
PATH_OFFSET_POSITION ( chk_path ,
2009-03-31 01:02:50 +07:00
path_offset ) ) >
2009-03-31 01:02:49 +07:00
B_NR_ITEMS ( parent ) )
2005-07-13 10:21:28 +07:00
return & MAX_KEY ;
/* Check whether parent at the path really points to the child. */
2009-03-31 01:02:50 +07:00
if ( B_N_CHILD_NUM ( parent , position ) ! =
2009-03-31 01:02:49 +07:00
PATH_OFFSET_PBUFFER ( chk_path ,
2009-03-31 01:02:50 +07:00
path_offset + 1 ) - > b_blocknr )
2005-07-13 10:21:28 +07:00
return & MAX_KEY ;
/* Return delimiting key if position in the parent is not equal to zero. */
2009-03-31 01:02:50 +07:00
if ( position )
return B_N_PDELIM_KEY ( parent , position - 1 ) ;
2005-07-13 10:21:28 +07:00
}
/* Return MIN_KEY if we are in the root of the buffer tree. */
2009-03-31 01:02:49 +07:00
if ( PATH_OFFSET_PBUFFER ( chk_path , FIRST_PATH_ELEMENT_OFFSET ) - >
2009-03-31 01:02:45 +07:00
b_blocknr = = SB_ROOT_BLOCK ( sb ) )
2005-07-13 10:21:28 +07:00
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. */
2009-03-31 01:02:49 +07:00
inline const struct reiserfs_key * get_rkey ( const struct treepath * chk_path ,
2009-03-31 01:02:45 +07:00
const struct super_block * sb )
2005-07-13 10:21:28 +07:00
{
2009-03-31 01:02:50 +07:00
int position , path_offset = chk_path - > path_length ;
2009-03-31 01:02:49 +07:00
struct buffer_head * parent ;
2005-07-13 10:21:28 +07:00
2009-03-31 01:02:50 +07:00
RFALSE ( path_offset < FIRST_PATH_ELEMENT_OFFSET ,
2005-07-13 10:21:28 +07:00
" PAP-5030: invalid offset in the path " ) ;
2009-03-31 01:02:50 +07:00
while ( path_offset - - > FIRST_PATH_ELEMENT_OFFSET ) {
2005-07-13 10:21:28 +07:00
RFALSE ( ! buffer_uptodate
2009-03-31 01:02:50 +07:00
( PATH_OFFSET_PBUFFER ( chk_path , path_offset ) ) ,
2005-07-13 10:21:28 +07:00
" PAP-5040: parent is not uptodate " ) ;
/* Parent at the path is not in the tree now. */
if ( ! B_IS_IN_TREE
2009-03-31 01:02:49 +07:00
( parent =
2009-03-31 01:02:50 +07:00
PATH_OFFSET_PBUFFER ( chk_path , path_offset ) ) )
2005-07-13 10:21:28 +07:00
return & MIN_KEY ;
/* Check whether position in the parent is correct. */
2009-03-31 01:02:50 +07:00
if ( ( position =
2009-03-31 01:02:49 +07:00
PATH_OFFSET_POSITION ( chk_path ,
2009-03-31 01:02:50 +07:00
path_offset ) ) >
2009-03-31 01:02:49 +07:00
B_NR_ITEMS ( parent ) )
2005-07-13 10:21:28 +07:00
return & MIN_KEY ;
/* Check whether parent at the path really points to the child. */
2009-03-31 01:02:50 +07:00
if ( B_N_CHILD_NUM ( parent , position ) ! =
2009-03-31 01:02:49 +07:00
PATH_OFFSET_PBUFFER ( chk_path ,
2009-03-31 01:02:50 +07:00
path_offset + 1 ) - > b_blocknr )
2005-07-13 10:21:28 +07:00
return & MIN_KEY ;
/* Return delimiting key if position in the parent is not the last one. */
2009-03-31 01:02:50 +07:00
if ( position ! = B_NR_ITEMS ( parent ) )
return B_N_PDELIM_KEY ( parent , position ) ;
2005-07-13 10:21:28 +07:00
}
/* Return MAX_KEY if we are in the root of the buffer tree. */
2009-03-31 01:02:49 +07:00
if ( PATH_OFFSET_PBUFFER ( chk_path , FIRST_PATH_ELEMENT_OFFSET ) - >
2009-03-31 01:02:45 +07:00
b_blocknr = = SB_ROOT_BLOCK ( sb ) )
2005-07-13 10:21:28 +07:00
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 . */
2009-03-31 01:02:49 +07:00
static inline int key_in_buffer ( struct treepath * chk_path , /* Path which should be checked. */
const struct cpu_key * key , /* Key which should be checked. */
struct super_block * sb
2005-07-13 10:21:28 +07:00
)
{
2005-04-17 05:20:36 +07:00
2009-03-31 01:02:49 +07:00
RFALSE ( ! key | | chk_path - > path_length < FIRST_PATH_ELEMENT_OFFSET
| | chk_path - > path_length > MAX_HEIGHT ,
2005-07-13 10:21:28 +07:00
" PAP-5050: pointer to the key(%p) is NULL or invalid path length(%d) " ,
2009-03-31 01:02:49 +07:00
key , chk_path - > path_length ) ;
RFALSE ( ! PATH_PLAST_BUFFER ( chk_path ) - > b_bdev ,
2005-07-13 10:21:28 +07:00
" PAP-5060: device must not be NODEV " ) ;
2009-03-31 01:02:49 +07:00
if ( comp_keys ( get_lkey ( chk_path , sb ) , key ) = = 1 )
2005-07-13 10:21:28 +07:00
/* left delimiting key is bigger, that the key we look for */
return 0 ;
2009-03-31 01:02:49 +07:00
/* if ( comp_keys(key, get_rkey(chk_path, sb)) != -1 ) */
if ( comp_keys ( get_rkey ( chk_path , sb ) , key ) ! = 1 )
/* key must be less than right delimitiing key */
2005-07-13 10:21:28 +07:00
return 0 ;
return 1 ;
2005-04-17 05:20:36 +07:00
}
2006-12-08 17:36:32 +07:00
int reiserfs_check_path ( struct treepath * p )
2005-07-13 10:21:28 +07:00
{
RFALSE ( p - > path_length ! = ILLEGAL_PATH_ELEMENT_OFFSET ,
" path not properly relsed " ) ;
return 0 ;
}
2005-04-17 05:20:36 +07:00
2009-03-31 01:02:43 +07:00
/* Drop the reference to each buffer in a path and restore
* dirty bits clean when preparing the buffer for the log .
* This version should only be called from fix_nodes ( ) */
void pathrelse_and_restore ( struct super_block * sb ,
2009-03-31 01:02:49 +07:00
struct treepath * search_path )
2005-07-13 10:21:28 +07:00
{
2009-03-31 01:02:50 +07:00
int path_offset = search_path - > path_length ;
2005-07-13 10:21:28 +07:00
2009-03-31 01:02:50 +07:00
RFALSE ( path_offset < ILLEGAL_PATH_ELEMENT_OFFSET ,
2005-07-13 10:21:28 +07:00
" clm-4000: invalid path offset " ) ;
2009-03-31 01:02:50 +07:00
while ( path_offset > ILLEGAL_PATH_ELEMENT_OFFSET ) {
2009-03-31 01:02:43 +07:00
struct buffer_head * bh ;
2009-03-31 01:02:50 +07:00
bh = PATH_OFFSET_PBUFFER ( search_path , path_offset - - ) ;
2009-03-31 01:02:43 +07:00
reiserfs_restore_prepared_buffer ( sb , bh ) ;
brelse ( bh ) ;
2005-07-13 10:21:28 +07:00
}
2009-03-31 01:02:49 +07:00
search_path - > path_length = ILLEGAL_PATH_ELEMENT_OFFSET ;
2005-04-17 05:20:36 +07:00
}
2009-03-31 01:02:43 +07:00
/* Drop the reference to each buffer in a path */
2009-03-31 01:02:49 +07:00
void pathrelse ( struct treepath * search_path )
2005-07-13 10:21:28 +07:00
{
2009-03-31 01:02:50 +07:00
int path_offset = search_path - > path_length ;
2005-04-17 05:20:36 +07:00
2009-03-31 01:02:50 +07:00
RFALSE ( path_offset < ILLEGAL_PATH_ELEMENT_OFFSET ,
2005-07-13 10:21:28 +07:00
" PAP-5090: invalid path offset " ) ;
2005-04-17 05:20:36 +07:00
2009-03-31 01:02:50 +07:00
while ( path_offset > ILLEGAL_PATH_ELEMENT_OFFSET )
brelse ( PATH_OFFSET_PBUFFER ( search_path , path_offset - - ) ) ;
2005-04-17 05:20:36 +07:00
2009-03-31 01:02:49 +07:00
search_path - > path_length = ILLEGAL_PATH_ELEMENT_OFFSET ;
2005-07-13 10:21:28 +07:00
}
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 ) {
2009-03-31 01:02:21 +07:00
reiserfs_warning ( NULL , " reiserfs-5080 " ,
" this should be caught earlier " ) ;
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
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 */
2009-03-31 01:02:21 +07:00
reiserfs_warning ( NULL , " reiserfs-5081 " ,
" nr_item seems wrong: %z " , bh ) ;
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
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 */
2009-03-31 01:02:21 +07:00
reiserfs_warning ( NULL , " reiserfs-5082 " ,
" free space seems wrong: %z " , bh ) ;
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
// 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 ) {
2009-03-31 01:02:21 +07:00
reiserfs_warning ( NULL , " reiserfs-5083 " ,
" wrong item type for item %h " ,
2005-07-13 10:21:28 +07:00
ih ) ;
return 0 ;
}
if ( ih_location ( ih ) > = blocksize
| | ih_location ( ih ) < IH_SIZE * nr ) {
2009-03-31 01:02:21 +07:00
reiserfs_warning ( NULL , " reiserfs-5084 " ,
" item location seems wrong: %h " ,
2005-07-13 10:21:28 +07:00
ih ) ;
return 0 ;
}
if ( ih_item_len ( ih ) < 1
| | ih_item_len ( ih ) > MAX_ITEM_LEN ( blocksize ) ) {
2009-03-31 01:02:21 +07:00
reiserfs_warning ( NULL , " reiserfs-5085 " ,
" item length seems wrong: %h " ,
2005-07-13 10:21:28 +07:00
ih ) ;
return 0 ;
}
if ( prev_location - ih_location ( ih ) ! = ih_item_len ( ih ) ) {
2009-03-31 01:02:21 +07:00
reiserfs_warning ( NULL , " reiserfs-5086 " ,
" item location seems wrong "
" (second one): %h " , ih ) ;
2005-07-13 10:21:28 +07:00
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 */
2009-03-31 01:02:21 +07:00
reiserfs_warning ( NULL , " reiserfs-5087 " ,
" this should be caught earlier " ) ;
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
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 */
2009-03-31 01:02:21 +07:00
reiserfs_warning ( NULL , " reiserfs-5088 " ,
" number of key seems wrong: %z " , bh ) ;
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
used_space = BLKH_SIZE + KEY_SIZE * nr + DC_SIZE * ( nr + 1 ) ;
if ( used_space ! = blocksize - blkh_free_space ( blkh ) ) {
2009-03-31 01:02:21 +07:00
reiserfs_warning ( NULL , " reiserfs-5089 " ,
" free space seems wrong: %z " , bh ) ;
2005-07-13 10:21:28 +07:00
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 ) {
2009-03-31 01:02:21 +07:00
reiserfs_warning ( NULL , " reiserfs-5090 " , " node level %d does "
" not match to the expected one %d " ,
2005-07-13 10:21:28 +07:00
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
2009-05-14 07:56:39 +07:00
/*
* The function is NOT SCHEDULE - SAFE !
* It might unlock the write lock if we needed to wait for a block
* to be read . Note that in this case it won ' t recover the lock to avoid
* high contention resulting from too much lock requests , especially
* the caller ( search_by_key ) will perform other schedule - unsafe
* operations just after calling this function .
*
* @ return true if we have unlocked
*/
static bool search_by_key_reada ( struct super_block * s ,
2005-07-13 10:21:28 +07:00
struct buffer_head * * bh ,
2007-10-19 13:39:25 +07:00
b_blocknr_t * b , int num )
2005-04-17 05:20:36 +07:00
{
2005-07-13 10:21:28 +07:00
int i , j ;
2009-05-14 07:56:39 +07:00
bool unlocked = false ;
2005-07-13 10:21:28 +07:00
for ( i = 0 ; i < num ; i + + ) {
bh [ i ] = sb_getblk ( s , b [ i ] ) ;
}
2009-05-08 19:21:33 +07:00
/*
* We are going to read some blocks on which we
* have a reference . It ' s safe , though we might be
* reading blocks concurrently changed if we release
* the lock . But it ' s still fine because we check later
* if the tree changed
*/
2005-07-13 10:21:28 +07:00
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
*/
2009-05-14 07:56:39 +07:00
if ( ! buffer_uptodate ( bh [ j ] ) ) {
if ( ! unlocked ) {
reiserfs_write_unlock ( s ) ;
unlocked = true ;
}
2005-07-13 10:21:28 +07:00
ll_rw_block ( READA , 1 , bh + j ) ;
2009-05-14 07:56:39 +07:00
}
2005-07-13 10:21:28 +07:00
brelse ( bh [ j ] ) ;
}
2009-05-14 07:56:39 +07:00
return unlocked ;
2005-04-17 05:20:36 +07:00
}
/**************************************************************************
* Algorithm SearchByKey *
* look for item in the Disk S + Tree by its key *
2009-03-31 01:02:45 +07:00
* Input : sb - super block *
2009-03-31 01:02:49 +07:00
* key - pointer to the key to search *
2005-04-17 05:20:36 +07:00
* Output : ITEM_FOUND , ITEM_NOT_FOUND or IO_ERROR *
2009-03-31 01:02:49 +07:00
* search_path - path from the root to the needed leaf *
2005-04-17 05:20:36 +07:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* 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! */
2009-03-31 01:02:49 +07:00
int search_by_key ( struct super_block * sb , const struct cpu_key * key , /* Key to search. */
struct treepath * search_path , /* This structure was
2005-07-13 10:21:28 +07:00
allocated and initialized
by the calling
function . It is filled up
by this function . */
2009-03-31 01:02:50 +07:00
int stop_level /* How far down the tree to search. To
2005-07-13 10:21:28 +07:00
stop at leaf level - set to
DISK_LEAF_NODE_LEVEL */
)
{
2009-03-31 01:02:50 +07:00
b_blocknr_t block_number ;
2005-07-13 10:21:28 +07:00
int expected_level ;
2009-03-31 01:02:46 +07:00
struct buffer_head * bh ;
2009-03-31 01:02:49 +07:00
struct path_element * last_element ;
2009-03-31 01:02:50 +07:00
int node_level , retval ;
2005-07-13 10:21:28 +07:00
int right_neighbor_of_leaf_node ;
int fs_gen ;
struct buffer_head * reada_bh [ SEARCH_BY_KEY_READA ] ;
2007-10-19 13:39:25 +07:00
b_blocknr_t reada_blocks [ SEARCH_BY_KEY_READA ] ;
2005-07-13 10:21:28 +07:00
int reada_count = 0 ;
2005-04-17 05:20:36 +07:00
# ifdef CONFIG_REISERFS_CHECK
2009-03-31 01:02:50 +07:00
int repeat_counter = 0 ;
2005-04-17 05:20:36 +07:00
# endif
2009-03-31 01:02:45 +07:00
PROC_INFO_INC ( sb , search_by_key ) ;
2005-07-13 10:21:28 +07:00
/* 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
2009-03-31 01:02:49 +07:00
pathrelse ( 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 . . */
2009-03-31 01:02:50 +07:00
block_number = SB_ROOT_BLOCK ( sb ) ;
2005-07-13 10:21:28 +07:00
expected_level = - 1 ;
while ( 1 ) {
2005-04-17 05:20:36 +07:00
# ifdef CONFIG_REISERFS_CHECK
2009-03-31 01:02:50 +07:00
if ( ! ( + + repeat_counter % 50000 ) )
2009-03-31 01:02:45 +07:00
reiserfs_warning ( sb , " PAP-5100 " ,
2009-03-31 01:02:21 +07:00
" %s: there were %d iterations of "
" while loop looking for key %K " ,
2009-03-31 01:02:50 +07:00
current - > comm , repeat_counter ,
2009-03-31 01:02:49 +07:00
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. */
2009-03-31 01:02:49 +07:00
last_element =
PATH_OFFSET_PELEMENT ( search_path ,
+ + search_path - > path_length ) ;
2009-03-31 01:02:45 +07:00
fs_gen = get_generation ( sb ) ;
2005-07-13 10:21:28 +07:00
/* Read the next tree node, and set the last element in the path to
have a pointer to it . */
2009-03-31 01:02:49 +07:00
if ( ( bh = last_element - > pe_buffer =
2009-03-31 01:02:50 +07:00
sb_getblk ( sb , block_number ) ) ) {
2009-05-14 07:56:39 +07:00
bool unlocked = false ;
2009-03-31 01:02:46 +07:00
if ( ! buffer_uptodate ( bh ) & & reada_count > 1 )
2009-05-14 07:56:39 +07:00
/* may unlock the write lock */
unlocked = search_by_key_reada ( sb , reada_bh ,
2005-07-13 10:21:28 +07:00
reada_blocks , reada_count ) ;
2009-05-14 07:56:39 +07:00
/*
* If we haven ' t already unlocked the write lock ,
* then we need to do that here before reading
* the current block
*/
if ( ! buffer_uptodate ( bh ) & & ! unlocked ) {
2009-05-08 19:21:33 +07:00
reiserfs_write_unlock ( sb ) ;
2009-05-14 07:56:39 +07:00
unlocked = true ;
}
2009-03-31 01:02:46 +07:00
ll_rw_block ( READ , 1 , & bh ) ;
wait_on_buffer ( bh ) ;
2009-05-14 07:56:39 +07:00
if ( unlocked )
reiserfs_write_lock ( sb ) ;
2009-03-31 01:02:46 +07:00
if ( ! buffer_uptodate ( bh ) )
2005-07-13 10:21:28 +07:00
goto io_error ;
} else {
io_error :
2009-03-31 01:02:49 +07:00
search_path - > path_length - - ;
pathrelse ( search_path ) ;
2005-07-13 10:21:28 +07:00
return IO_ERROR ;
}
reada_count = 0 ;
if ( expected_level = = - 1 )
2009-03-31 01:02:45 +07:00
expected_level = SB_TREE_HEIGHT ( sb ) ;
2005-07-13 10:21:28 +07:00
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 . */
2009-03-31 01:02:45 +07:00
if ( fs_changed ( fs_gen , sb ) & &
2009-03-31 01:02:46 +07:00
( ! B_IS_IN_TREE ( bh ) | |
B_LEVEL ( bh ) ! = expected_level | |
2009-03-31 01:02:49 +07:00
! key_in_buffer ( search_path , key , sb ) ) ) {
2009-03-31 01:02:45 +07:00
PROC_INFO_INC ( sb , search_by_key_fs_changed ) ;
PROC_INFO_INC ( sb , search_by_key_restarted ) ;
PROC_INFO_INC ( sb ,
2005-07-13 10:21:28 +07:00
sbk_restarted [ expected_level - 1 ] ) ;
2009-03-31 01:02:49 +07:00
pathrelse ( search_path ) ;
2005-07-13 10:21:28 +07:00
/* Get the root block number so that we can repeat the search
starting from the root . */
2009-03-31 01:02:50 +07:00
block_number = SB_ROOT_BLOCK ( sb ) ;
2005-07-13 10:21:28 +07:00
expected_level = - 1 ;
right_neighbor_of_leaf_node = 0 ;
/* repeat search from the root */
continue ;
}
2005-04-17 05:20:36 +07:00
2009-03-31 01:02:49 +07:00
/* only check that the key is in the buffer if key is not
2005-07-13 10:21:28 +07:00
equal to the MAX_KEY . Latter case is only possible in
" finish_unfinished() " processing during mount . */
2009-03-31 01:02:49 +07:00
RFALSE ( comp_keys ( & MAX_KEY , key ) & &
! key_in_buffer ( search_path , key , sb ) ,
2005-07-13 10:21:28 +07:00
" PAP-5130: key is not in the buffer " ) ;
2005-04-17 05:20:36 +07:00
# ifdef CONFIG_REISERFS_CHECK
kill-the-bkl/reiserfs: move the concurrent tree accesses checks per superblock
When do_balance() balances the tree, a trick is performed to
provide the ability for other tree writers/readers to check whether
do_balance() is executing concurrently (requires CONFIG_REISERFS_CHECK).
This is done to protect concurrent accesses to the tree. The trick
is the following:
When do_balance is called, a unique global variable called cur_tb
takes a pointer to the current tree to be rebalanced.
Once do_balance finishes its work, cur_tb takes the NULL value.
Then, concurrent tree readers/writers just have to check the value
of cur_tb to ensure do_balance isn't executing concurrently.
If it is, then it proves that schedule() occured on do_balance(),
which then relaxed the bkl that protected the tree.
Now that the bkl has be turned into a mutex, this check is still
fine even though do_balance() becomes preemptible: the write lock
will not be automatically released on schedule(), so the tree is
still protected.
But this is only fine if we have a single reiserfs mountpoint.
Indeed, because the bkl is a global lock, it didn't allowed
concurrent executions between a tree reader/writer in a mount point
and a do_balance() on another tree from another mountpoint.
So assuming all these readers/writers weren't supposed to be
reentrant, the current check now sometimes detect false positives with
the current per-superblock mutex which allows this reentrancy.
This patch keeps the concurrent tree accesses check but moves it
per superblock, so that only trees from a same mount point are
checked to be not accessed concurrently.
[ Impact: fix spurious panic while running several reiserfs mount-points ]
Cc: Jeff Mahoney <jeffm@suse.com>
Cc: Chris Mason <chris.mason@oracle.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Alexander Beregalov <a.beregalov@gmail.com>
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
2009-05-17 00:10:38 +07:00
if ( REISERFS_SB ( sb ) - > cur_tb ) {
2005-07-13 10:21:28 +07:00
print_cur_tb ( " 5140 " ) ;
2009-03-31 01:02:45 +07:00
reiserfs_panic ( sb , " PAP-5140 " ,
2009-03-31 01:02:25 +07:00
" schedule occurred in do_balance! " ) ;
2005-07-13 10:21:28 +07:00
}
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
2009-03-31 01:02:46 +07:00
if ( ! is_tree_node ( bh , expected_level ) ) {
2009-03-31 01:02:45 +07:00
reiserfs_error ( sb , " vs-5150 " ,
2009-03-31 01:02:28 +07:00
" invalid format found in block %ld. "
2009-03-31 01:02:46 +07:00
" Fsck? " , bh - > b_blocknr ) ;
2009-03-31 01:02:49 +07:00
pathrelse ( search_path ) ;
2005-07-13 10:21:28 +07:00
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 */
2009-03-31 01:02:50 +07:00
node_level = B_LEVEL ( bh ) ;
2005-04-17 05:20:36 +07:00
2009-03-31 01:02:50 +07:00
PROC_INFO_BH_STAT ( sb , bh , node_level - 1 ) ;
2005-04-17 05:20:36 +07:00
2009-03-31 01:02:50 +07:00
RFALSE ( node_level < stop_level ,
2005-07-13 10:21:28 +07:00
" vs-5152: tree level (%d) is less than stop level (%d) " ,
2009-03-31 01:02:50 +07:00
node_level , stop_level ) ;
2005-04-17 05:20:36 +07:00
2009-03-31 01:02:50 +07:00
retval = bin_search ( key , B_N_PITEM_HEAD ( bh , 0 ) ,
2009-03-31 01:02:46 +07:00
B_NR_ITEMS ( bh ) ,
2009-03-31 01:02:50 +07:00
( node_level = =
2005-07-13 10:21:28 +07:00
DISK_LEAF_NODE_LEVEL ) ? IH_SIZE :
KEY_SIZE ,
2009-03-31 01:02:49 +07:00
& ( last_element - > pe_position ) ) ;
2009-03-31 01:02:50 +07:00
if ( node_level = = stop_level ) {
return retval ;
2005-07-13 10:21:28 +07:00
}
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
/* we are not in the stop level */
2009-03-31 01:02:50 +07:00
if ( retval = = ITEM_FOUND )
2005-07-13 10:21:28 +07:00
/* item has been found, so we choose the pointer which is to the right of the found one */
2009-03-31 01:02:49 +07:00
last_element - > pe_position + + ;
2005-07-13 10:21:28 +07:00
/* 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 . */
2009-03-31 01:02:50 +07:00
block_number =
2009-03-31 01:02:49 +07:00
B_N_CHILD_NUM ( bh , last_element - > pe_position ) ;
2005-07-13 10:21:28 +07:00
/* if we are going to read leaf nodes, try for read ahead as well */
2009-03-31 01:02:49 +07:00
if ( ( search_path - > reada & PATH_READA ) & &
2009-03-31 01:02:50 +07:00
node_level = = DISK_LEAF_NODE_LEVEL + 1 ) {
2009-03-31 01:02:49 +07:00
int pos = last_element - > pe_position ;
2009-03-31 01:02:46 +07:00
int limit = B_NR_ITEMS ( bh ) ;
2005-07-13 10:21:28 +07:00
struct reiserfs_key * le_key ;
2009-03-31 01:02:49 +07:00
if ( search_path - > reada & PATH_READA_BACK )
2005-07-13 10:21:28 +07:00
limit = 0 ;
while ( reada_count < SEARCH_BY_KEY_READA ) {
if ( pos = = limit )
break ;
reada_blocks [ reada_count + + ] =
2009-03-31 01:02:46 +07:00
B_N_CHILD_NUM ( bh , pos ) ;
2009-03-31 01:02:49 +07:00
if ( search_path - > reada & PATH_READA_BACK )
2005-07-13 10:21:28 +07:00
pos - - ;
else
pos + + ;
/*
* check to make sure we ' re in the same object
*/
2009-03-31 01:02:46 +07:00
le_key = B_N_PDELIM_KEY ( bh , pos ) ;
2005-07-13 10:21:28 +07:00
if ( le32_to_cpu ( le_key - > k_objectid ) ! =
2009-03-31 01:02:49 +07:00
key - > on_disk_key . k_objectid ) {
2005-07-13 10:21:28 +07:00
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
2009-03-31 01:02:49 +07:00
file byte defined by key . If there is no such item
2005-04-17 05:20:36 +07:00
corresponding to the key , we point the path to the item with
2009-03-31 01:02:49 +07:00
maximal key less than key , and * pos_in_item is set to one
2005-04-17 05:20:36 +07:00
past the last entry / byte in the item . If searching for entry in a
2009-03-31 01:02:49 +07:00
directory item , and it is not found , * pos_in_item is set to one
2005-04-17 05:20:36 +07:00
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! */
2009-03-31 01:02:45 +07:00
int search_for_position_by_key ( struct super_block * sb , /* Pointer to the super block. */
2005-07-13 10:21:28 +07:00
const struct cpu_key * p_cpu_key , /* Key to search (cpu variable) */
2009-03-31 01:02:49 +07:00
struct treepath * search_path /* Filled up by this function. */
2005-07-13 10:21:28 +07:00
)
{
struct item_head * p_le_ih ; /* pointer to on-disk structure */
2009-03-31 01:02:50 +07:00
int blk_size ;
2005-07-13 10:21:28 +07:00
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 ) )
2009-03-31 01:02:49 +07:00
return search_by_entry_key ( sb , p_cpu_key , search_path ,
2005-07-13 10:21:28 +07:00
& de ) ;
/* If not searching for directory entry. */
/* If item is found. */
2009-03-31 01:02:49 +07:00
retval = search_item ( sb , p_cpu_key , search_path ) ;
2005-07-13 10:21:28 +07:00
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
2009-03-31 01:02:49 +07:00
( PATH_PLAST_BUFFER ( search_path ) ,
PATH_LAST_POSITION ( search_path ) ) ) ,
2005-07-13 10:21:28 +07:00
" PAP-5165: item length equals zero " ) ;
2005-04-17 05:20:36 +07:00
2009-03-31 01:02:49 +07:00
pos_in_item ( search_path ) = 0 ;
2005-07-13 10:21:28 +07:00
return POSITION_FOUND ;
}
2005-04-17 05:20:36 +07:00
2009-03-31 01:02:49 +07:00
RFALSE ( ! PATH_LAST_POSITION ( search_path ) ,
2005-07-13 10:21:28 +07:00
" 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 =
2009-03-31 01:02:49 +07:00
B_N_PITEM_HEAD ( PATH_PLAST_BUFFER ( search_path ) ,
- - PATH_LAST_POSITION ( search_path ) ) ;
2009-03-31 01:02:50 +07:00
blk_size = 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 & &
2009-03-31 01:02:50 +07:00
item_offset + op_bytes_number ( p_le_ih , blk_size ) > offset ) {
2009-03-31 01:02:49 +07:00
pos_in_item ( search_path ) = offset - item_offset ;
2005-07-13 10:21:28 +07:00
if ( is_indirect_le_ih ( p_le_ih ) ) {
2009-03-31 01:02:50 +07:00
pos_in_item ( search_path ) / = blk_size ;
2005-07-13 10:21:28 +07:00
}
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 ) )
2009-03-31 01:02:49 +07:00
pos_in_item ( search_path ) =
2005-07-13 10:21:28 +07:00
ih_item_len ( p_le_ih ) / UNFM_P_SIZE ;
else
2009-03-31 01:02:49 +07:00
pos_in_item ( search_path ) = ih_item_len ( p_le_ih ) ;
2005-07-13 10:21:28 +07:00
return POSITION_NOT_FOUND ;
}
2005-04-17 05:20:36 +07:00
/* Compare given item and item pointed to by the path. */
2009-03-31 01:02:49 +07:00
int comp_items ( const struct item_head * stored_ih , const struct treepath * path )
2005-04-17 05:20:36 +07:00
{
2009-03-31 01:02:49 +07:00
struct buffer_head * bh = PATH_PLAST_BUFFER ( path ) ;
2005-07-13 10:21:28 +07:00
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. */
2009-03-31 01:02:46 +07:00
if ( ! B_IS_IN_TREE ( bh ) )
2005-07-13 10:21:28 +07:00
return 1 ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
/* Last path position is invalid. */
2009-03-31 01:02:49 +07:00
if ( PATH_LAST_POSITION ( path ) > = B_NR_ITEMS ( bh ) )
2005-07-13 10:21:28 +07:00
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 */
2009-03-31 01:02:49 +07:00
ih = get_ih ( path ) ;
2005-07-13 10:21:28 +07:00
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
2006-12-08 17:36:32 +07:00
static inline int prepare_for_direct_item ( struct treepath * path ,
2005-07-13 10:21:28 +07:00
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 ) {
2009-03-31 01:02:44 +07:00
//
2005-07-13 10:21:28 +07:00
round_len = ROUND_UP ( new_file_length ) ;
2009-03-31 01:02:50 +07:00
/* this was new_file_length < le_ih ... */
2005-07-13 10:21:28 +07:00
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
}
2006-12-08 17:36:32 +07:00
static inline int prepare_for_direntry_item ( struct treepath * path ,
2005-07-13 10:21:28 +07:00
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
2006-03-25 18:06:57 +07:00
# define JOURNAL_FOR_FREE_BLOCK_AND_UPDATE_SD (2 * JOURNAL_PER_BALANCE_CNT + 1)
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 . */
2009-03-31 01:02:49 +07:00
static char prepare_for_delete_or_cut ( struct reiserfs_transaction_handle * th , struct inode * inode , struct treepath * path , const struct cpu_key * item_key , int * removed , /* Number of unformatted nodes which were removed
2005-07-13 10:21:28 +07:00
from end of the file . */
2009-03-31 01:02:50 +07:00
int * cut_size , unsigned long long new_file_length /* MAX_KEY_OFFSET in case of delete. */
2005-07-13 10:21:28 +07:00
)
{
2009-03-31 01:02:45 +07:00
struct super_block * sb = inode - > i_sb ;
2009-03-31 01:02:49 +07:00
struct item_head * p_le_ih = PATH_PITEM_HEAD ( path ) ;
struct buffer_head * bh = PATH_PLAST_BUFFER ( 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
2009-03-31 01:02:50 +07:00
RFALSE ( new_file_length ! = max_reiserfs_offset ( inode ) ,
2005-07-13 10:21:28 +07:00
" PAP-5210: mode must be M_DELETE " ) ;
2005-04-17 05:20:36 +07:00
2009-03-31 01:02:49 +07:00
* cut_size = - ( IH_SIZE + ih_item_len ( p_le_ih ) ) ;
2005-07-13 10:21:28 +07:00
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 ) )
2009-03-31 01:02:49 +07:00
return prepare_for_direntry_item ( path , p_le_ih , inode ,
2009-03-31 01:02:50 +07:00
new_file_length ,
2009-03-31 01:02:49 +07:00
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 ) )
2009-03-31 01:02:49 +07:00
return prepare_for_direct_item ( path , p_le_ih , inode ,
2009-03-31 01:02:50 +07:00
new_file_length , cut_size ) ;
2005-07-13 10:21:28 +07:00
/* Case of an indirect item. */
{
2009-03-31 01:02:45 +07:00
int blk_size = sb - > s_blocksize ;
2006-03-25 18:06:57 +07:00
struct item_head s_ih ;
int need_re_search ;
int delete = 0 ;
int result = M_CUT ;
int pos = 0 ;
2009-03-31 01:02:50 +07:00
if ( new_file_length = = max_reiserfs_offset ( inode ) ) {
2006-03-25 18:06:57 +07:00
/* prepare_for_delete_or_cut() is called by
* reiserfs_delete_item ( ) */
2009-03-31 01:02:50 +07:00
new_file_length = 0 ;
2006-03-25 18:06:57 +07:00
delete = 1 ;
}
do {
need_re_search = 0 ;
2009-03-31 01:02:49 +07:00
* cut_size = 0 ;
bh = PATH_PLAST_BUFFER ( path ) ;
copy_item_head ( & s_ih , PATH_PITEM_HEAD ( path ) ) ;
2006-03-25 18:06:57 +07:00
pos = I_UNFM_NUM ( & s_ih ) ;
2005-07-13 10:21:28 +07:00
2009-03-31 01:02:50 +07:00
while ( le_ih_k_offset ( & s_ih ) + ( pos - 1 ) * blk_size > new_file_length ) {
2007-07-26 23:47:03 +07:00
__le32 * unfm ;
__u32 block ;
2005-07-13 10:21:28 +07:00
2006-03-25 18:06:57 +07:00
/* Each unformatted block deletion may involve one additional
* bitmap block into the transaction , thereby the initial
* journal space reservation might not be enough . */
2009-03-31 01:02:49 +07:00
if ( ! delete & & ( * cut_size ) ! = 0 & &
reiserfs_transaction_free_space ( th ) < JOURNAL_FOR_FREE_BLOCK_AND_UPDATE_SD )
2006-03-25 18:06:57 +07:00
break ;
2005-07-13 10:21:28 +07:00
2009-03-31 01:02:46 +07:00
unfm = ( __le32 * ) B_I_PITEM ( bh , & s_ih ) + pos - 1 ;
2006-03-25 18:06:57 +07:00
block = get_block_num ( unfm , 0 ) ;
2005-07-13 10:21:28 +07:00
2006-03-25 18:06:57 +07:00
if ( block ! = 0 ) {
2009-03-31 01:02:46 +07:00
reiserfs_prepare_for_journal ( sb , bh , 1 ) ;
2006-03-25 18:06:57 +07:00
put_block_num ( unfm , 0 , 0 ) ;
2009-03-31 01:02:46 +07:00
journal_mark_dirty ( th , sb , bh ) ;
2006-03-25 18:06:57 +07:00
reiserfs_free_block ( th , inode , block , 1 ) ;
}
2005-07-13 10:21:28 +07:00
2009-05-01 04:36:33 +07:00
reiserfs_write_unlock ( sb ) ;
2006-03-25 18:06:57 +07:00
cond_resched ( ) ;
2009-05-01 04:36:33 +07:00
reiserfs_write_lock ( sb ) ;
2005-07-13 10:21:28 +07:00
2009-03-31 01:02:49 +07:00
if ( item_moved ( & s_ih , path ) ) {
2006-03-25 18:06:57 +07:00
need_re_search = 1 ;
break ;
}
pos - - ;
2009-03-31 01:02:49 +07:00
( * removed ) + + ;
( * cut_size ) - = UNFM_P_SIZE ;
2006-03-25 18:06:57 +07:00
if ( pos = = 0 ) {
2009-03-31 01:02:49 +07:00
( * cut_size ) - = IH_SIZE ;
2006-03-25 18:06:57 +07:00
result = M_DELETE ;
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 */
2009-03-31 01:02:46 +07:00
reiserfs_restore_prepared_buffer ( sb , bh ) ;
2006-03-25 18:06:57 +07:00
} while ( need_re_search & &
2009-03-31 01:02:49 +07:00
search_for_position_by_key ( sb , item_key , path ) = = POSITION_FOUND ) ;
pos_in_item ( path ) = pos * UNFM_P_SIZE ;
2006-03-25 18:06:57 +07:00
2009-03-31 01:02:49 +07:00
if ( * cut_size = = 0 ) {
2006-03-25 18:06:57 +07:00
/* Nothing were cut. maybe convert last unformatted node to the
* direct item ? */
result = M_CONVERT ;
}
return result ;
2005-07-13 10:21:28 +07:00
}
2005-04-17 05:20:36 +07:00
}
/* Calculate number of bytes which will be deleted or cut during balance */
2009-03-31 01:02:50 +07:00
static int calc_deleted_bytes_number ( struct tree_balance * tb , char mode )
2005-07-13 10:21:28 +07:00
{
2009-03-31 01:02:50 +07:00
int del_size ;
2009-03-31 01:02:48 +07:00
struct item_head * p_le_ih = PATH_PITEM_HEAD ( tb - > tb_path ) ;
2005-07-13 10:21:28 +07:00
if ( is_statdata_le_ih ( p_le_ih ) )
return 0 ;
2009-03-31 01:02:50 +07:00
del_size =
( mode = =
2009-03-31 01:02:48 +07:00
M_DELETE ) ? ih_item_len ( p_le_ih ) : - tb - > insert_size [ 0 ] ;
2005-07-13 10:21:28 +07:00
if ( is_direntry_le_ih ( p_le_ih ) ) {
2009-03-31 01:02:50 +07:00
/* 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 del_size ;
2005-07-13 10:21:28 +07:00
}
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
if ( is_indirect_le_ih ( p_le_ih ) )
2009-03-31 01:02:50 +07:00
del_size = ( del_size / UNFM_P_SIZE ) *
2009-03-31 01:02:48 +07:00
( PATH_PLAST_BUFFER ( tb - > tb_path ) - > b_size ) ;
2009-03-31 01:02:50 +07:00
return 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 ,
2009-03-31 01:02:48 +07:00
struct tree_balance * tb ,
2009-03-31 01:02:45 +07:00
struct super_block * sb ,
2009-03-31 01:02:50 +07:00
struct treepath * path , int size )
2005-07-13 10:21:28 +07:00
{
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
2009-03-31 01:02:48 +07:00
memset ( tb , ' \0 ' , sizeof ( struct tree_balance ) ) ;
tb - > transaction_handle = th ;
tb - > tb_sb = sb ;
2009-03-31 01:02:49 +07:00
tb - > tb_path = path ;
PATH_OFFSET_PBUFFER ( path , ILLEGAL_PATH_ELEMENT_OFFSET ) = NULL ;
PATH_OFFSET_POSITION ( path , ILLEGAL_PATH_ELEMENT_OFFSET ) = 0 ;
2009-03-31 01:02:50 +07:00
tb - > insert_size [ 0 ] = size ;
2005-07-13 10:21:28 +07:00
}
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
2009-03-31 01:02:49 +07:00
/* Delete object item.
* th - active transaction handle
* path - path to the deleted item
* item_key - key to search for the deleted item
* indode - used for updating i_blocks and quotas
* un_bh - NULL or unformatted node pointer
*/
int reiserfs_delete_item ( struct reiserfs_transaction_handle * th ,
struct treepath * path , const struct cpu_key * item_key ,
struct inode * inode , struct buffer_head * un_bh )
{
2009-03-31 01:02:47 +07:00
struct super_block * sb = inode - > i_sb ;
2005-07-13 10:21:28 +07:00
struct tree_balance s_del_balance ;
struct item_head s_ih ;
struct item_head * q_ih ;
int quota_cut_bytes ;
2009-03-31 01:02:50 +07:00
int ret_value , del_size , removed ;
2005-04-17 05:20:36 +07:00
# ifdef CONFIG_REISERFS_CHECK
2009-03-31 01:02:50 +07:00
char mode ;
int 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
2009-03-31 01:02:49 +07:00
init_tb_struct ( th , & s_del_balance , sb , path ,
2005-07-13 10:21:28 +07:00
0 /*size is unknown */ ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
while ( 1 ) {
2009-03-31 01:02:50 +07:00
removed = 0 ;
2005-04-17 05:20:36 +07:00
# ifdef CONFIG_REISERFS_CHECK
2009-03-31 01:02:50 +07:00
iter + + ;
mode =
2005-04-17 05:20:36 +07:00
# endif
2009-03-31 01:02:49 +07:00
prepare_for_delete_or_cut ( th , inode , path ,
2009-03-31 01:02:50 +07:00
item_key , & removed ,
& del_size ,
2009-03-31 01:02:47 +07:00
max_reiserfs_offset ( inode ) ) ;
2005-07-13 10:21:28 +07:00
2009-03-31 01:02:50 +07:00
RFALSE ( mode ! = M_DELETE , " PAP-5320: mode must be M_DELETE " ) ;
2005-07-13 10:21:28 +07:00
2009-03-31 01:02:49 +07:00
copy_item_head ( & s_ih , PATH_PITEM_HEAD ( path ) ) ;
2009-03-31 01:02:50 +07:00
s_del_balance . insert_size [ 0 ] = del_size ;
2005-07-13 10:21:28 +07:00
2009-03-31 01:02:50 +07:00
ret_value = fix_nodes ( M_DELETE , & s_del_balance , NULL , NULL ) ;
if ( ret_value ! = REPEAT_SEARCH )
2005-07-13 10:21:28 +07:00
break ;
2009-03-31 01:02:45 +07:00
PROC_INFO_INC ( sb , delete_item_restarted ) ;
2005-07-13 10:21:28 +07:00
// file system changed, repeat search
2009-03-31 01:02:50 +07:00
ret_value =
2009-03-31 01:02:49 +07:00
search_for_position_by_key ( sb , item_key , path ) ;
2009-03-31 01:02:50 +07:00
if ( ret_value = = IO_ERROR )
2005-07-13 10:21:28 +07:00
break ;
2009-03-31 01:02:50 +07:00
if ( ret_value = = FILE_NOT_FOUND ) {
2009-03-31 01:02:45 +07:00
reiserfs_warning ( sb , " vs-5340 " ,
2005-07-13 10:21:28 +07:00
" no items of the file %K found " ,
2009-03-31 01:02:49 +07:00
item_key ) ;
2005-07-13 10:21:28 +07:00
break ;
}
} /* while (1) */
2005-04-17 05:20:36 +07:00
2009-03-31 01:02:50 +07:00
if ( ret_value ! = CARRY_ON ) {
2005-07-13 10:21:28 +07:00
unfix_nodes ( & s_del_balance ) ;
return 0 ;
}
// reiserfs_delete_item returns item length when success
2009-03-31 01:02:50 +07:00
ret_value = calc_deleted_bytes_number ( & s_del_balance , M_DELETE ) ;
2009-03-31 01:02:49 +07:00
q_ih = get_ih ( path ) ;
2005-07-13 10:21:28 +07:00
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
*/
2009-03-31 01:02:47 +07:00
if ( ! S_ISLNK ( inode - > i_mode ) & & is_direct_le_ih ( q_ih ) ) {
2009-03-31 01:02:45 +07:00
if ( ( le_ih_k_offset ( q_ih ) & ( sb - > s_blocksize - 1 ) ) = = 1 ) {
quota_cut_bytes = sb - > s_blocksize + UNFM_P_SIZE ;
2005-07-13 10:21:28 +07:00
} else {
quota_cut_bytes = 0 ;
}
2005-04-17 05:20:36 +07:00
}
2009-03-31 01:02:49 +07:00
if ( un_bh ) {
2005-07-13 10:21:28 +07:00
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 .
* *
2009-03-31 01:02:49 +07:00
* * un_bh is from the page cache ( all unformatted nodes are
2005-07-13 10:21:28 +07:00
* * from the page cache ) and might be a highmem page . So , we
2009-03-31 01:02:49 +07:00
* * can ' t use un_bh - > b_data .
2005-07-13 10:21:28 +07:00
* * - clm
*/
2009-03-31 01:02:49 +07:00
data = kmap_atomic ( un_bh - > b_page , KM_USER0 ) ;
2005-07-13 10:21:28 +07:00
off = ( ( le_ih_k_offset ( & s_ih ) - 1 ) & ( PAGE_CACHE_SIZE - 1 ) ) ;
memcpy ( data + off ,
2009-03-31 01:02:49 +07:00
B_I_PITEM ( PATH_PLAST_BUFFER ( path ) , & s_ih ) ,
2009-03-31 01:02:50 +07:00
ret_value ) ;
2005-07-13 10:21:28 +07:00
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
2009-03-31 01:02:45 +07:00
reiserfs_debug ( sb , REISERFS_DEBUG_CODE ,
2005-07-13 10:21:28 +07:00
" reiserquota delete_item(): freeing %u, id=%u type=%c " ,
2009-03-31 01:02:47 +07:00
quota_cut_bytes , inode - > i_uid , head2type ( & s_ih ) ) ;
2005-04-17 05:20:36 +07:00
# endif
2009-03-31 02:29:21 +07:00
vfs_dq_free_space_nodirty ( inode , quota_cut_bytes ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
/* Return deleted body length */
2009-03-31 01:02:50 +07:00
return 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 ) {
2009-03-31 01:02:28 +07:00
reiserfs_error ( th - > t_super , " vs-5350 " ,
" i/o failure occurred trying "
" to delete %K " , & cpu_key ) ;
2005-07-13 10:21:28 +07:00
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 ) )
2009-03-31 01:02:21 +07:00
reiserfs_warning ( th - > t_super , " vs-5355 " ,
" %k not found " , key ) ;
2005-07-13 10:21:28 +07:00
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
2009-01-26 23:14:18 +07:00
vfs_dq_free_space_nodirty ( inode ,
2005-07-13 10:21:28 +07:00
quota_cut_bytes ) ;
}
break ;
}
// IO_ERROR, NO_DISK_SPACE, etc
2009-03-31 01:02:21 +07:00
reiserfs_warning ( th - > t_super , " vs-5360 " ,
2005-07-13 10:21:28 +07:00
" 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 ;
2008-04-28 16:16:20 +07:00
le32_add_cpu ( inode_generation , 1 ) ;
2005-07-13 10:21:28 +07:00
}
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 ) ;
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 ,
2009-03-31 01:02:47 +07:00
struct inode * inode ,
2005-07-13 10:21:28 +07:00
struct page * page ,
2009-03-31 01:02:49 +07:00
struct treepath * path ,
const struct cpu_key * item_key ,
2009-03-31 01:02:50 +07:00
loff_t new_file_size , char * mode )
2005-07-13 10:21:28 +07:00
{
2009-03-31 01:02:47 +07:00
struct super_block * sb = inode - > i_sb ;
2009-03-31 01:02:50 +07:00
int block_size = sb - > s_blocksize ;
2005-07-13 10:21:28 +07:00
int cut_bytes ;
BUG_ON ( ! th - > t_trans_id ) ;
2009-03-31 01:02:50 +07:00
BUG_ON ( new_file_size ! = inode - > i_size ) ;
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
*/
2009-03-31 01:02:47 +07:00
if ( atomic_read ( & inode - > i_count ) > 1 | |
! tail_has_to_be_packed ( inode ) | |
! page | | ( REISERFS_I ( inode ) - > i_flags & i_nopack_mask ) ) {
2009-03-31 01:02:44 +07:00
/* leave tail in an unformatted node */
2009-03-31 01:02:49 +07:00
* mode = M_SKIP_BALANCING ;
2005-07-13 10:21:28 +07:00
cut_bytes =
2009-03-31 01:02:50 +07:00
block_size - ( new_file_size & ( block_size - 1 ) ) ;
2009-03-31 01:02:49 +07:00
pathrelse ( path ) ;
2005-07-13 10:21:28 +07:00
return cut_bytes ;
}
2009-03-31 01:02:49 +07:00
/* Perform the conversion to a direct_item. */
/* return indirect_to_direct(inode, path, item_key,
2009-03-31 01:02:50 +07:00
new_file_size , mode ) ; */
2009-03-31 01:02:49 +07:00
return indirect2direct ( th , inode , page , path , item_key ,
2009-03-31 01:02:50 +07:00
new_file_size , mode ) ;
2005-07-13 10:21:28 +07:00
}
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 ,
2006-12-08 17:36:32 +07:00
struct inode * inode , struct treepath * 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 )
2009-03-31 01:02:25 +07:00
reiserfs_panic ( inode - > i_sb , " vs-5615 " ,
" found invalid item " ) ;
2005-07-13 10:21:28 +07:00
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 ) ;
}
2009-03-31 01:02:21 +07:00
reiserfs_warning ( inode - > i_sb , " reiserfs-5091 " , " indirect_to_direct "
" conversion has been rolled back due to "
" lack of disk space " ) ;
2005-07-13 10:21:28 +07:00
//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 ,
2009-03-31 01:02:49 +07:00
struct treepath * path ,
struct cpu_key * item_key ,
2009-03-31 01:02:47 +07:00
struct inode * inode ,
2009-03-31 01:02:50 +07:00
struct page * page , loff_t new_file_size )
2005-04-17 05:20:36 +07:00
{
2009-03-31 01:02:47 +07:00
struct super_block * sb = inode - > i_sb ;
2005-07-13 10:21:28 +07:00
/* 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 ;
2009-03-31 01:02:50 +07:00
int cut_size = 0 , /* Amount to be cut. */
ret_value = CARRY_ON , removed = 0 , /* Number of the removed unformatted nodes. */
is_inode_locked = 0 ;
char mode ; /* Mode of the balance. */
2005-07-13 10:21:28 +07:00
int retval2 = - 1 ;
int quota_cut_bytes ;
loff_t tail_pos = 0 ;
BUG_ON ( ! th - > t_trans_id ) ;
2009-03-31 01:02:49 +07:00
init_tb_struct ( th , & s_cut_balance , inode - > i_sb , path ,
2009-03-31 01:02:50 +07:00
cut_size ) ;
2005-07-13 10:21:28 +07:00
/* 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 . */
2009-03-31 01:02:50 +07:00
mode =
2009-03-31 01:02:49 +07:00
prepare_for_delete_or_cut ( th , inode , path ,
2009-03-31 01:02:50 +07:00
item_key , & removed ,
& cut_size , new_file_size ) ;
if ( mode = = M_CONVERT ) {
2005-07-13 10:21:28 +07:00
/* convert last unformatted node to direct item or leave
tail in the unformatted node */
2009-03-31 01:02:50 +07:00
RFALSE ( ret_value ! = CARRY_ON ,
2005-07-13 10:21:28 +07:00
" PAP-5570: can not convert twice " ) ;
2009-03-31 01:02:50 +07:00
ret_value =
2009-03-31 01:02:47 +07:00
maybe_indirect_to_direct ( th , inode , page ,
2009-03-31 01:02:49 +07:00
path , item_key ,
2009-03-31 01:02:50 +07:00
new_file_size , & mode ) ;
if ( mode = = M_SKIP_BALANCING )
2005-07-13 10:21:28 +07:00
/* tail has been left in the unformatted node */
2009-03-31 01:02:50 +07:00
return ret_value ;
2005-07-13 10:21:28 +07:00
2009-03-31 01:02:50 +07:00
is_inode_locked = 1 ;
2005-07-13 10:21:28 +07:00
/* removing of last unformatted node will change value we
have to return to truncate . Save it */
2009-03-31 01:02:50 +07:00
retval2 = ret_value ;
/*retval2 = sb->s_blocksize - (new_file_size & (sb->s_blocksize - 1)); */
2005-07-13 10:21:28 +07:00
/* 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 . */
2009-03-31 01:02:49 +07:00
set_cpu_key_k_type ( item_key , TYPE_INDIRECT ) ;
item_key - > key_length = 4 ;
2009-03-31 01:02:50 +07:00
new_file_size - =
( new_file_size & ( sb - > s_blocksize - 1 ) ) ;
tail_pos = new_file_size ;
set_cpu_key_k_offset ( item_key , new_file_size + 1 ) ;
2005-07-13 10:21:28 +07:00
if ( search_for_position_by_key
2009-03-31 01:02:49 +07:00
( sb , item_key ,
path ) = = POSITION_NOT_FOUND ) {
print_block ( PATH_PLAST_BUFFER ( path ) , 3 ,
PATH_LAST_POSITION ( path ) - 1 ,
PATH_LAST_POSITION ( path ) + 1 ) ;
2009-03-31 01:02:45 +07:00
reiserfs_panic ( sb , " PAP-5580 " , " item to "
2009-03-31 01:02:25 +07:00
" convert does not exist (%K) " ,
2009-03-31 01:02:49 +07:00
item_key ) ;
2005-07-13 10:21:28 +07:00
}
continue ;
}
2009-03-31 01:02:50 +07:00
if ( cut_size = = 0 ) {
2009-03-31 01:02:49 +07:00
pathrelse ( path ) ;
2005-07-13 10:21:28 +07:00
return 0 ;
}
2009-03-31 01:02:50 +07:00
s_cut_balance . insert_size [ 0 ] = cut_size ;
2005-07-13 10:21:28 +07:00
2009-03-31 01:02:50 +07:00
ret_value = fix_nodes ( mode , & s_cut_balance , NULL , NULL ) ;
if ( ret_value ! = REPEAT_SEARCH )
2005-07-13 10:21:28 +07:00
break ;
2009-03-31 01:02:45 +07:00
PROC_INFO_INC ( sb , cut_from_item_restarted ) ;
2005-07-13 10:21:28 +07:00
2009-03-31 01:02:50 +07:00
ret_value =
2009-03-31 01:02:49 +07:00
search_for_position_by_key ( sb , item_key , path ) ;
2009-03-31 01:02:50 +07:00
if ( ret_value = = POSITION_FOUND )
2005-07-13 10:21:28 +07:00
continue ;
2005-04-17 05:20:36 +07:00
2009-03-31 01:02:45 +07:00
reiserfs_warning ( sb , " PAP-5610 " , " item %K not found " ,
2009-03-31 01:02:49 +07:00
item_key ) ;
2005-07-13 10:21:28 +07:00
unfix_nodes ( & s_cut_balance ) ;
2009-03-31 01:02:50 +07:00
return ( ret_value = = IO_ERROR ) ? - EIO : - ENOENT ;
2005-07-13 10:21:28 +07:00
} /* while */
// check fix_nodes results (IO_ERROR or NO_DISK_SPACE)
2009-03-31 01:02:50 +07:00
if ( ret_value ! = CARRY_ON ) {
if ( is_inode_locked ) {
2005-07-13 10:21:28 +07:00
// FIXME: this seems to be not needed: we are always able
// to cut item
2009-03-31 01:02:49 +07:00
indirect_to_direct_roll_back ( th , inode , path ) ;
2005-07-13 10:21:28 +07:00
}
2009-03-31 01:02:50 +07:00
if ( ret_value = = NO_DISK_SPACE )
2009-03-31 01:02:45 +07:00
reiserfs_warning ( sb , " reiserfs-5092 " ,
2009-03-31 01:02:21 +07:00
" NO_DISK_SPACE " ) ;
2005-07-13 10:21:28 +07:00
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 */
2009-03-31 01:02:50 +07:00
RFALSE ( mode = = M_PASTE | | mode = = M_INSERT , " invalid mode " ) ;
2005-07-13 10:21:28 +07:00
/* Calculate number of bytes that need to be cut from the item. */
quota_cut_bytes =
2009-03-31 01:02:50 +07:00
( mode = =
2009-03-31 01:02:49 +07:00
M_DELETE ) ? ih_item_len ( get_ih ( path ) ) : - s_cut_balance .
2005-07-13 10:21:28 +07:00
insert_size [ 0 ] ;
if ( retval2 = = - 1 )
2009-03-31 01:02:50 +07:00
ret_value = calc_deleted_bytes_number ( & s_cut_balance , mode ) ;
2005-07-13 10:21:28 +07:00
else
2009-03-31 01:02:50 +07:00
ret_value = retval2 ;
2005-07-13 10:21:28 +07:00
/* For direct items, we only change the quota when deleting the last
* * item .
*/
p_le_ih = PATH_PITEM_HEAD ( s_cut_balance . tb_path ) ;
2009-03-31 01:02:47 +07:00
if ( ! S_ISLNK ( inode - > i_mode ) & & is_direct_le_ih ( p_le_ih ) ) {
2009-03-31 01:02:50 +07:00
if ( mode = = M_DELETE & &
2009-03-31 01:02:45 +07:00
( le_ih_k_offset ( p_le_ih ) & ( sb - > s_blocksize - 1 ) ) = =
2005-07-13 10:21:28 +07:00
1 ) {
// FIXME: this is to keep 3.5 happy
2009-03-31 01:02:47 +07:00
REISERFS_I ( inode ) - > i_first_direct_byte = U32_MAX ;
2009-03-31 01:02:45 +07:00
quota_cut_bytes = sb - > s_blocksize + UNFM_P_SIZE ;
2005-07-13 10:21:28 +07:00
} else {
quota_cut_bytes = 0 ;
}
2005-04-17 05:20:36 +07:00
}
# ifdef CONFIG_REISERFS_CHECK
2009-03-31 01:02:50 +07:00
if ( is_inode_locked ) {
2005-07-13 10:21:28 +07:00
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 ) )
2009-03-31 01:02:45 +07:00
reiserfs_panic ( sb , " vs-5652 " ,
2005-07-13 10:21:28 +07:00
" item must be indirect %h " , le_ih ) ;
2009-03-31 01:02:50 +07:00
if ( mode = = M_DELETE & & ih_item_len ( le_ih ) ! = UNFM_P_SIZE )
2009-03-31 01:02:45 +07:00
reiserfs_panic ( sb , " vs-5653 " , " completing "
2009-03-31 01:02:25 +07:00
" indirect2direct conversion indirect "
" item %h being deleted must be of "
" 4 byte long " , le_ih ) ;
2005-07-13 10:21:28 +07:00
2009-03-31 01:02:50 +07:00
if ( mode = = M_CUT
2005-07-13 10:21:28 +07:00
& & s_cut_balance . insert_size [ 0 ] ! = - UNFM_P_SIZE ) {
2009-03-31 01:02:45 +07:00
reiserfs_panic ( sb , " vs-5654 " , " can not complete "
2009-03-31 01:02:25 +07:00
" indirect2direct conversion of %h "
" (CUT, insert_size==%d) " ,
2005-07-13 10:21:28 +07:00
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
2009-03-31 01:02:50 +07:00
do_balance ( & s_cut_balance , NULL , NULL , mode ) ;
if ( is_inode_locked ) {
2005-07-13 10:21:28 +07:00
/* 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 ) ;
2009-03-31 01:02:47 +07:00
REISERFS_I ( inode ) - > i_flags & = ~ i_pack_on_close_mask ;
2005-07-13 10:21:28 +07:00
}
2005-04-17 05:20:36 +07:00
# ifdef REISERQUOTA_DEBUG
2009-03-31 01:02:47 +07:00
reiserfs_debug ( inode - > i_sb , REISERFS_DEBUG_CODE ,
2005-07-13 10:21:28 +07:00
" reiserquota cut_from_item(): freeing %u id=%u type=%c " ,
2009-03-31 01:02:47 +07:00
quota_cut_bytes , inode - > i_uid , ' ? ' ) ;
2005-04-17 05:20:36 +07:00
# endif
2009-03-31 02:29:21 +07:00
vfs_dq_free_space_nodirty ( inode , quota_cut_bytes ) ;
2009-03-31 01:02:50 +07:00
return 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 )
2009-03-31 01:02:28 +07:00
reiserfs_error ( inode - > i_sb , " vs-5655 " , " link count != 0 " ) ;
2005-07-13 10:21:28 +07:00
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 */
2009-03-31 01:02:47 +07:00
int reiserfs_do_truncate ( struct reiserfs_transaction_handle * th ,
struct inode * inode , /* ->i_size contains new size */
2005-07-13 10:21:28 +07:00
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. */
2009-03-31 01:02:50 +07:00
loff_t file_size , /* Old file size. */
new_file_size ; /* New file size. */
int deleted ; /* Number of deleted or truncated bytes. */
2005-07-13 10:21:28 +07:00
int retval ;
int err = 0 ;
BUG_ON ( ! th - > t_trans_id ) ;
if ( !
2009-03-31 01:02:47 +07:00
( S_ISREG ( inode - > i_mode ) | | S_ISDIR ( inode - > i_mode )
| | S_ISLNK ( inode - > i_mode ) ) )
2005-07-13 10:21:28 +07:00
return 0 ;
2009-03-31 01:02:47 +07:00
if ( S_ISDIR ( inode - > i_mode ) ) {
2005-07-13 10:21:28 +07:00
// deletion of directory - no need to update timestamps
2009-03-31 01:02:47 +07:00
truncate_directory ( th , inode ) ;
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
/* Get new file size. */
2009-03-31 01:02:50 +07:00
new_file_size = 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
2009-03-31 01:02:47 +07:00
make_cpu_key ( & s_item_key , inode , max_reiserfs_offset ( inode ) ,
2005-07-13 10:21:28 +07:00
TYPE_DIRECT , 3 ) ;
2005-04-17 05:20:36 +07:00
2005-07-13 10:21:28 +07:00
retval =
2009-03-31 01:02:47 +07:00
search_for_position_by_key ( inode - > i_sb , & s_item_key ,
2005-07-13 10:21:28 +07:00
& s_search_path ) ;
if ( retval = = IO_ERROR ) {
2009-03-31 01:02:47 +07:00
reiserfs_error ( inode - > i_sb , " vs-5657 " ,
2009-03-31 01:02:28 +07:00
" i/o failure occurred trying to truncate %K " ,
& s_item_key ) ;
2005-07-13 10:21:28 +07:00
err = - EIO ;
goto out ;
}
if ( retval = = POSITION_FOUND | | retval = = FILE_NOT_FOUND ) {
2009-03-31 01:02:47 +07:00
reiserfs_error ( inode - > i_sb , " PAP-5660 " ,
2009-03-31 01:02:28 +07:00
" wrong result %d of search for %K " , retval ,
& s_item_key ) ;
2005-07-13 10:21:28 +07:00
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 ) )
2009-03-31 01:02:50 +07:00
file_size = 0 ;
2005-07-13 10:21:28 +07:00
else {
loff_t offset = le_ih_k_offset ( p_le_ih ) ;
int bytes =
2009-03-31 01:02:47 +07:00
op_bytes_number ( p_le_ih , inode - > i_sb - > s_blocksize ) ;
2005-07-13 10:21:28 +07:00
/* 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 */
2009-03-31 01:02:50 +07:00
file_size = offset + bytes - 1 ;
2005-07-13 10:21:28 +07:00
}
/*
* are we doing a full truncate or delete , if so
* kick in the reada code
*/
2009-03-31 01:02:50 +07:00
if ( new_file_size = = 0 )
2005-07-13 10:21:28 +07:00
s_search_path . reada = PATH_READA | PATH_READA_BACK ;
2009-03-31 01:02:50 +07:00
if ( file_size = = 0 | | file_size < new_file_size ) {
2005-07-13 10:21:28 +07:00
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. */
2009-03-31 01:02:50 +07:00
set_cpu_key_k_offset ( & s_item_key , file_size ) ;
2005-07-13 10:21:28 +07:00
do {
/* Cut or delete file item. */
2009-03-31 01:02:50 +07:00
deleted =
2005-07-13 10:21:28 +07:00
reiserfs_cut_from_item ( th , & s_search_path , & s_item_key ,
2009-03-31 01:02:50 +07:00
inode , page , new_file_size ) ;
if ( deleted < 0 ) {
2009-03-31 01:02:47 +07:00
reiserfs_warning ( inode - > i_sb , " vs-5665 " ,
2009-03-31 01:02:21 +07:00
" reiserfs_cut_from_item failed " ) ;
2005-07-13 10:21:28 +07:00
reiserfs_check_path ( & s_search_path ) ;
return 0 ;
}
2005-04-17 05:20:36 +07:00
2009-03-31 01:02:50 +07:00
RFALSE ( deleted > file_size ,
2005-07-13 10:21:28 +07:00
" PAP-5670: reiserfs_cut_from_item: too many bytes deleted: deleted %d, file_size %lu, item_key %K " ,
2009-03-31 01:02:50 +07:00
deleted , 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. */
2009-03-31 01:02:50 +07:00
file_size - = deleted ;
2005-04-17 05:20:36 +07:00
2009-03-31 01:02:50 +07:00
set_cpu_key_k_offset ( & s_item_key , 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. */
/*
2009-03-31 01:02:44 +07:00
* * This loop could take a really long time , and could log
2005-07-13 10:21:28 +07:00
* * 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
*/
2006-03-25 18:06:57 +07:00
if ( journal_transaction_should_end ( th , 0 ) | |
reiserfs_transaction_free_space ( th ) < = JOURNAL_FOR_FREE_BLOCK_AND_UPDATE_SD ) {
2005-07-13 10:21:28 +07:00
int orig_len_alloc = th - > t_blocks_allocated ;
2009-03-31 01:02:43 +07:00
pathrelse ( & s_search_path ) ;
2005-07-13 10:21:28 +07:00
if ( update_timestamps ) {
2009-03-31 01:02:47 +07:00
inode - > i_mtime = CURRENT_TIME_SEC ;
inode - > i_ctime = CURRENT_TIME_SEC ;
2005-07-13 10:21:28 +07:00
}
2009-03-31 01:02:47 +07:00
reiserfs_update_sd ( th , inode ) ;
2005-07-13 10:21:28 +07:00
2009-03-31 01:02:47 +07:00
err = journal_end ( th , inode - > i_sb , orig_len_alloc ) ;
2005-07-13 10:21:28 +07:00
if ( err )
goto out ;
2009-03-31 01:02:47 +07:00
err = journal_begin ( th , inode - > i_sb ,
2006-03-25 18:06:57 +07:00
JOURNAL_FOR_FREE_BLOCK_AND_UPDATE_SD + JOURNAL_PER_BALANCE_CNT * 4 ) ;
2005-07-13 10:21:28 +07:00
if ( err )
goto out ;
2009-03-31 01:02:47 +07:00
reiserfs_update_inode_transaction ( inode ) ;
2005-07-13 10:21:28 +07:00
}
2009-03-31 01:02:50 +07:00
} while ( file_size > ROUND_UP ( new_file_size ) & &
2009-03-31 01:02:47 +07:00
search_for_position_by_key ( inode - > i_sb , & s_item_key ,
2005-07-13 10:21:28 +07:00
& s_search_path ) = = POSITION_FOUND ) ;
2009-03-31 01:02:50 +07:00
RFALSE ( file_size > ROUND_UP ( new_file_size ) ,
2005-07-13 10:21:28 +07:00
" PAP-5680: truncate did not finish: new_file_size %Ld, current %Ld, oid %d " ,
2009-03-31 01:02:50 +07:00
new_file_size , file_size , s_item_key . on_disk_key . k_objectid ) ;
2005-07-13 10:21:28 +07:00
update_and_out :
if ( update_timestamps ) {
// this is truncate, not file closing
2009-03-31 01:02:47 +07:00
inode - > i_mtime = CURRENT_TIME_SEC ;
inode - > i_ctime = CURRENT_TIME_SEC ;
2005-04-17 05:20:36 +07:00
}
2009-03-31 01:02:47 +07:00
reiserfs_update_sd ( th , 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
2006-12-08 17:36:32 +07:00
static void check_research_for_paste ( struct treepath * path ,
2009-03-31 01:02:49 +07:00
const struct cpu_key * 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 ) ! =
2009-03-31 01:02:49 +07:00
cpu_key_k_offset ( key )
2005-07-13 10:21:28 +07:00
| | op_bytes_number ( found_ih ,
get_last_bh ( path ) - > b_size ) ! =
pos_in_item ( path ) )
2009-03-31 01:02:25 +07:00
reiserfs_panic ( NULL , " PAP-5720 " , " found direct item "
" %h or position (%d) does not match "
" to key %K " , found_ih ,
2009-03-31 01:02:49 +07:00
pos_in_item ( path ) , key ) ;
2005-07-13 10:21:28 +07:00
}
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 ) ! =
2009-03-31 01:02:49 +07:00
cpu_key_k_offset ( key )
2005-07-13 10:21:28 +07:00
| | I_UNFM_NUM ( found_ih ) ! = pos_in_item ( path )
| | get_ih_free_space ( found_ih ) ! = 0 )
2009-03-31 01:02:25 +07:00
reiserfs_panic ( NULL , " PAP-5730 " , " found indirect "
" item (%h) or position (%d) does not "
" match to key (%K) " ,
2009-03-31 01:02:49 +07:00
found_ih , pos_in_item ( path ) , key ) ;
2005-07-13 10:21:28 +07:00
}
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. */
2009-03-31 01:02:49 +07:00
int reiserfs_paste_into_item ( struct reiserfs_transaction_handle * th , struct treepath * search_path , /* Path to the pasted item. */
const struct cpu_key * key , /* Key to search for the needed item. */
2005-07-13 10:21:28 +07:00
struct inode * inode , /* Inode item belongs to */
2009-03-31 01:02:49 +07:00
const char * body , /* Pointer to the bytes to paste. */
2009-03-31 01:02:50 +07:00
int pasted_size )
2005-07-13 10:21:28 +07:00
{ /* 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 " ,
2009-03-31 01:02:50 +07:00
pasted_size , inode - > i_uid ,
2009-03-31 01:02:49 +07:00
key2type ( & ( key - > on_disk_key ) ) ) ;
2005-04-17 05:20:36 +07:00
# endif
2009-03-31 02:29:21 +07:00
if ( vfs_dq_alloc_space_nodirty ( inode , pasted_size ) ) {
2009-03-31 01:02:49 +07:00
pathrelse ( search_path ) ;
2005-07-13 10:21:28 +07:00
return - EDQUOT ;
}
2009-03-31 01:02:49 +07:00
init_tb_struct ( th , & s_paste_balance , th - > t_super , search_path ,
2009-03-31 01:02:50 +07:00
pasted_size ) ;
2005-04-17 05:20:36 +07:00
# ifdef DISPLACE_NEW_PACKING_LOCALITIES
2009-03-31 01:02:49 +07:00
s_paste_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 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 ,
2009-03-31 01:02:49 +07:00
body ) ) = = REPEAT_SEARCH ) {
2005-07-13 10:21:28 +07:00
search_again :
/* file system changed while we were in the fix_nodes */
PROC_INFO_INC ( th - > t_super , paste_into_item_restarted ) ;
retval =
2009-03-31 01:02:49 +07:00
search_for_position_by_key ( th - > t_super , key ,
search_path ) ;
2005-07-13 10:21:28 +07:00
if ( retval = = IO_ERROR ) {
retval = - EIO ;
goto error_out ;
}
if ( retval = = POSITION_FOUND ) {
2009-03-31 01:02:21 +07:00
reiserfs_warning ( inode - > i_sb , " PAP-5710 " ,
" entry or pasted byte (%K) exists " ,
2009-03-31 01:02:49 +07:00
key ) ;
2005-07-13 10:21:28 +07:00
retval = - EEXIST ;
goto error_out ;
}
2005-04-17 05:20:36 +07:00
# ifdef CONFIG_REISERFS_CHECK
2009-03-31 01:02:49 +07:00
check_research_for_paste ( search_path , 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 ) {
2009-03-31 01:02:49 +07:00
do_balance ( & s_paste_balance , NULL /*ih */ , body , M_PASTE ) ;
2005-07-13 10:21:28 +07:00
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 " ,
2009-03-31 01:02:50 +07:00
pasted_size , inode - > i_uid ,
2009-03-31 01:02:49 +07:00
key2type ( & ( key - > on_disk_key ) ) ) ;
2005-04-17 05:20:36 +07:00
# endif
2009-03-31 02:29:21 +07:00
vfs_dq_free_space_nodirty ( inode , pasted_size ) ;
2005-07-13 10:21:28 +07:00
return retval ;
2005-04-17 05:20:36 +07:00
}
2009-03-31 01:02:49 +07:00
/* Insert new item into the buffer at the path.
* th - active transaction handle
* path - path to the inserted item
* ih - pointer to the item header to insert
* body - pointer to the bytes to insert
*/
int reiserfs_insert_item ( struct reiserfs_transaction_handle * th ,
struct treepath * path , const struct cpu_key * key ,
struct item_head * ih , struct inode * inode ,
const char * body )
{
2005-07-13 10:21:28 +07:00
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 ) ;
2009-03-31 01:02:49 +07:00
quota_bytes = ih_item_len ( ih ) ;
2005-07-13 10:21:28 +07:00
/* 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
*/
2009-03-31 01:02:49 +07:00
if ( ! S_ISLNK ( inode - > i_mode ) & & is_direct_le_ih ( ih ) )
2005-07-13 10:21:28 +07:00
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 " ,
2009-03-31 01:02:49 +07:00
quota_bytes , inode - > i_uid , head2type ( 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 . . . */
2009-01-26 23:14:18 +07:00
if ( vfs_dq_alloc_space_nodirty ( inode , quota_bytes ) ) {
2009-03-31 01:02:49 +07:00
pathrelse ( path ) ;
2005-07-13 10:21:28 +07:00
return - EDQUOT ;
}
2005-04-17 05:20:36 +07:00
}
2009-03-31 01:02:49 +07:00
init_tb_struct ( th , & s_ins_balance , th - > t_super , path ,
IH_SIZE + ih_item_len ( 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 =
2009-03-31 01:02:49 +07:00
fix_nodes ( M_INSERT , & s_ins_balance , ih ,
body ) ) = = REPEAT_SEARCH ) {
2005-07-13 10:21:28 +07:00
search_again :
/* file system changed while we were in the fix_nodes */
PROC_INFO_INC ( th - > t_super , insert_item_restarted ) ;
2009-03-31 01:02:49 +07:00
retval = search_item ( th - > t_super , key , path ) ;
2005-07-13 10:21:28 +07:00
if ( retval = = IO_ERROR ) {
retval = - EIO ;
goto error_out ;
}
if ( retval = = ITEM_FOUND ) {
2009-03-31 01:02:21 +07:00
reiserfs_warning ( th - > t_super , " PAP-5760 " ,
2005-07-13 10:21:28 +07:00
" 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 ) {
2009-03-31 01:02:49 +07:00
do_balance ( & s_ins_balance , ih , body , M_INSERT ) ;
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
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 " ,
2009-03-31 01:02:49 +07:00
quota_bytes , inode - > i_uid , head2type ( ih ) ) ;
2005-04-17 05:20:36 +07:00
# endif
2005-07-13 10:21:28 +07:00
if ( inode )
2009-01-26 23:14:18 +07:00
vfs_dq_free_space_nodirty ( inode , quota_bytes ) ;
2005-07-13 10:21:28 +07:00
return retval ;
2005-04-17 05:20:36 +07:00
}