X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Freiserfs%2Fstree.c;h=497b2f371b0d7231c0d8b5eb5c5164defbb62163;hb=9bf4aaab3e101692164d49b7ca357651eb691cb6;hp=0d4f5f5c1a8a3b486bedbc3a0ea12520d0cc9cd9;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c index 0d4f5f5c1..497b2f371 100644 --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c @@ -60,6 +60,7 @@ #include #include #include +#include /* Does the buffer contain a disk block which is in the tree. */ inline int B_IS_IN_TREE (const struct buffer_head * p_s_bh) @@ -71,9 +72,6 @@ inline int B_IS_IN_TREE (const struct buffer_head * p_s_bh) return ( B_LEVEL (p_s_bh) != FREE_LEVEL ); } - - - inline void copy_short_key (void * to, const void * from) { memcpy (to, from, SHORT_KEY_SIZE); @@ -166,7 +164,7 @@ inline int comp_cpu_keys (const struct cpu_key * key1, if (cpu_key_k_offset (key1) > cpu_key_k_offset (key2)) return 1; - reiserfs_warning ("comp_cpu_keys: type are compared for %K and %K\n", + reiserfs_warning (NULL, "comp_cpu_keys: type are compared for %K and %K", key1, key2); if (cpu_key_k_type (key1) < cpu_key_k_type (key2)) @@ -499,21 +497,21 @@ static int is_leaf (char * buf, int blocksize, struct buffer_head * bh) blkh = (struct block_head *)buf; if ( blkh_level(blkh) != DISK_LEAF_NODE_LEVEL) { - printk ("is_leaf: this should be caught earlier\n"); + reiserfs_warning (NULL, "is_leaf: this should be caught earlier"); return 0; } nr = blkh_nr_item(blkh); if (nr < 1 || nr > ((blocksize - BLKH_SIZE) / (IH_SIZE + MIN_ITEM_LEN))) { /* item number is too big or too small */ - reiserfs_warning ("is_leaf: nr_item seems wrong: %z\n", bh); + reiserfs_warning (NULL, "is_leaf: nr_item seems wrong: %z", bh); return 0; } ih = (struct item_head *)(buf + BLKH_SIZE) + nr - 1; used_space = BLKH_SIZE + IH_SIZE * nr + (blocksize - ih_location (ih)); if (used_space != blocksize - blkh_free_space(blkh)) { /* free space does not match to calculated amount of use space */ - reiserfs_warning ("is_leaf: free space seems wrong: %z\n", bh); + reiserfs_warning (NULL, "is_leaf: free space seems wrong: %z", bh); return 0; } @@ -525,19 +523,19 @@ static int is_leaf (char * buf, int blocksize, struct buffer_head * bh) prev_location = blocksize; for (i = 0; i < nr; i ++, ih ++) { if ( le_ih_k_type(ih) == TYPE_ANY) { - reiserfs_warning ("is_leaf: wrong item type for item %h\n",ih); + reiserfs_warning (NULL, "is_leaf: wrong item type for item %h",ih); return 0; } if (ih_location (ih) >= blocksize || ih_location (ih) < IH_SIZE * nr) { - reiserfs_warning ("is_leaf: item location seems wrong: %h\n", ih); + reiserfs_warning (NULL, "is_leaf: item location seems wrong: %h", ih); return 0; } if (ih_item_len (ih) < 1 || ih_item_len (ih) > MAX_ITEM_LEN (blocksize)) { - reiserfs_warning ("is_leaf: item length seems wrong: %h\n", ih); + reiserfs_warning (NULL, "is_leaf: item length seems wrong: %h", ih); return 0; } if (prev_location - ih_location (ih) != ih_item_len (ih)) { - reiserfs_warning ("is_leaf: item location seems wrong (second one): %h\n", ih); + reiserfs_warning (NULL, "is_leaf: item location seems wrong (second one): %h", ih); return 0; } prev_location = ih_location (ih); @@ -559,20 +557,20 @@ static int is_internal (char * buf, int blocksize, struct buffer_head * bh) nr = blkh_level(blkh); if (nr <= DISK_LEAF_NODE_LEVEL || nr > MAX_HEIGHT) { /* this level is not possible for internal nodes */ - printk ("is_internal: this should be caught earlier\n"); + reiserfs_warning (NULL, "is_internal: this should be caught earlier"); return 0; } nr = blkh_nr_item(blkh); if (nr > (blocksize - BLKH_SIZE - DC_SIZE) / (KEY_SIZE + DC_SIZE)) { /* for internal which is not root we might check min number of keys */ - reiserfs_warning ("is_internal: number of key seems wrong: %z\n", bh); + reiserfs_warning (NULL, "is_internal: number of key seems wrong: %z", bh); return 0; } used_space = BLKH_SIZE + KEY_SIZE * nr + DC_SIZE * (nr + 1); if (used_space != blocksize - blkh_free_space(blkh)) { - reiserfs_warning ("is_internal: free space seems wrong: %z\n", bh); + reiserfs_warning (NULL, "is_internal: free space seems wrong: %z", bh); return 0; } @@ -586,7 +584,7 @@ static int is_internal (char * buf, int blocksize, struct buffer_head * bh) static int is_tree_node (struct buffer_head * bh, int level) { if (B_LEVEL (bh) != level) { - printk ("is_tree_node: node level %d does not match to the expected one %d\n", + reiserfs_warning (NULL, "is_tree_node: node level %d does not match to the expected one %d", B_LEVEL (bh), level); return 0; } @@ -598,26 +596,29 @@ static int is_tree_node (struct buffer_head * bh, int level) -#ifdef SEARCH_BY_KEY_READA +#define SEARCH_BY_KEY_READA 16 /* The function is NOT SCHEDULE-SAFE! */ -static void search_by_key_reada (struct super_block * s, int blocknr) +static void search_by_key_reada (struct super_block * s, + struct buffer_head **bh, + unsigned long *b, int num) { - struct buffer_head * bh; + int i,j; - if (blocknr == 0) - return; - - bh = sb_getblk (s, blocknr); - - if (!buffer_uptodate (bh)) { - ll_rw_block (READA, 1, &bh); + for (i = 0 ; i < num ; i++) { + bh[i] = sb_getblk (s, b[i]); + } + for (j = 0 ; j < i ; j++) { + /* + * note, this needs attention if we are getting rid of the BKL + * you have to make sure the prepared bit isn't set on this buffer + */ + if (!buffer_uptodate(bh[j])) + ll_rw_block(READA, 1, bh + j); + brelse(bh[j]); } - bh->b_count --; } -#endif - /************************************************************************** * Algorithm SearchByKey * * look for item in the Disk S+Tree by its key * @@ -659,6 +660,9 @@ int search_by_key (struct super_block * p_s_sb, int n_node_level, n_retval; int right_neighbor_of_leaf_node; int fs_gen; + struct buffer_head *reada_bh[SEARCH_BY_KEY_READA]; + unsigned long reada_blocks[SEARCH_BY_KEY_READA]; + int reada_count = 0; #ifdef CONFIG_REISERFS_CHECK int n_repeat_counter = 0; @@ -683,9 +687,9 @@ int search_by_key (struct super_block * p_s_sb, #ifdef CONFIG_REISERFS_CHECK if ( !(++n_repeat_counter % 50000) ) - reiserfs_warning ("PAP-5100: search_by_key: %s:" + reiserfs_warning (p_s_sb, "PAP-5100: search_by_key: %s:" "there were %d iterations of while loop " - "looking for key %K\n", + "looking for key %K", current->comm, n_repeat_counter, p_s_key); #endif @@ -693,19 +697,25 @@ int search_by_key (struct super_block * p_s_sb, p_s_last_element = PATH_OFFSET_PELEMENT(p_s_search_path, ++p_s_search_path->path_length); fs_gen = get_generation (p_s_sb); -#ifdef SEARCH_BY_KEY_READA - /* schedule read of right neighbor */ - search_by_key_reada (p_s_sb, right_neighbor_of_leaf_node); -#endif - /* Read the next tree node, and set the last element in the path to have a pointer to it. */ - if ( ! (p_s_bh = p_s_last_element->pe_buffer = - sb_bread(p_s_sb, n_block_number)) ) { + if ((p_s_bh = p_s_last_element->pe_buffer = + sb_getblk(p_s_sb, n_block_number)) ) { + if (!buffer_uptodate(p_s_bh) && reada_count > 1) { + search_by_key_reada (p_s_sb, reada_bh, + reada_blocks, reada_count); + } + ll_rw_block(READ, 1, &p_s_bh); + wait_on_buffer(p_s_bh); + if (!buffer_uptodate(p_s_bh)) + goto io_error; + } else { +io_error: p_s_search_path->path_length --; pathrelse(p_s_search_path); return IO_ERROR; } + reada_count = 0; if (expected_level == -1) expected_level = SB_TREE_HEIGHT (p_s_sb); expected_level --; @@ -748,8 +758,8 @@ int search_by_key (struct super_block * p_s_sb, // make sure, that the node contents look like a node of // certain level if (!is_tree_node (p_s_bh, expected_level)) { - reiserfs_warning ("vs-5150: search_by_key: " - "invalid format found in block %ld. Fsck?\n", + reiserfs_warning (p_s_sb, "vs-5150: search_by_key: " + "invalid format found in block %ld. Fsck?", p_s_bh->b_blocknr); pathrelse (p_s_search_path); return IO_ERROR; @@ -786,11 +796,36 @@ int search_by_key (struct super_block * p_s_sb, position in the node. */ n_block_number = B_N_CHILD_NUM(p_s_bh, p_s_last_element->pe_position); -#ifdef SEARCH_BY_KEY_READA - /* if we are going to read leaf node, then calculate its right neighbor if possible */ - if (n_node_level == DISK_LEAF_NODE_LEVEL + 1 && p_s_last_element->pe_position < B_NR_ITEMS (p_s_bh)) - right_neighbor_of_leaf_node = B_N_CHILD_NUM(p_s_bh, p_s_last_element->pe_position + 1); -#endif + /* if we are going to read leaf nodes, try for read ahead as well */ + if ((p_s_search_path->reada & PATH_READA) && + n_node_level == DISK_LEAF_NODE_LEVEL + 1) + { + int pos = p_s_last_element->pe_position; + int limit = B_NR_ITEMS(p_s_bh); + struct key *le_key; + + if (p_s_search_path->reada & PATH_READA_BACK) + limit = 0; + while(reada_count < SEARCH_BY_KEY_READA) { + if (pos == limit) + break; + reada_blocks[reada_count++] = B_N_CHILD_NUM(p_s_bh, pos); + if (p_s_search_path->reada & PATH_READA_BACK) + pos--; + else + pos++; + + /* + * check to make sure we're in the same object + */ + le_key = B_N_PDELIM_KEY(p_s_bh, pos); + if (le32_to_cpu(le_key->k_objectid) != + p_s_key->on_disk_key.k_objectid) + { + break; + } + } + } } } @@ -1125,8 +1160,7 @@ static char prepare_for_delete_or_cut( tmp = get_block_num(p_n_unfm_pointer,0); put_block_num(p_n_unfm_pointer, 0, 0); journal_mark_dirty (th, p_s_sb, p_s_bh); - inode->i_blocks -= p_s_sb->s_blocksize / 512; - reiserfs_free_block(th, tmp); + reiserfs_free_block(th, inode, tmp, 1); if ( item_moved (&s_ih, p_s_path) ) { need_research = 1; break ; @@ -1155,8 +1189,7 @@ static char prepare_for_delete_or_cut( } } - -/* Calculate bytes number which will be deleted or cutted in the balance. */ +/* Calculate number of bytes which will be deleted or cut during balance */ int calc_deleted_bytes_number( struct tree_balance * p_s_tb, char c_mode @@ -1167,14 +1200,14 @@ int calc_deleted_bytes_number( if ( is_statdata_le_ih (p_le_ih) ) return 0; + n_del_size = ( c_mode == M_DELETE ) ? ih_item_len(p_le_ih) : -p_s_tb->insert_size[0]; if ( is_direntry_le_ih (p_le_ih) ) { // return EMPTY_DIR_SIZE; /* We delete emty directoris only. */ // we can't use EMPTY_DIR_SIZE, as old format dirs have a different // empty size. ick. FIXME, is this right? // - return ih_item_len(p_le_ih); + return n_del_size ; } - n_del_size = ( c_mode == M_DELETE ) ? ih_item_len(p_le_ih) : -p_s_tb->insert_size[0]; if ( is_indirect_le_ih (p_le_ih) ) n_del_size = (n_del_size/UNFM_P_SIZE)* @@ -1208,17 +1241,46 @@ void padd_item (char * item, int total_length, int length) item [--i] = 0; } +#ifdef REISERQUOTA_DEBUG +char key2type(struct key *ih) +{ + 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'; +} + +char head2type(struct item_head *ih) +{ + 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'; +} +#endif /* Delete object item. */ int reiserfs_delete_item (struct reiserfs_transaction_handle *th, struct path * p_s_path, /* Path to the deleted item. */ const struct cpu_key * p_s_item_key, /* Key to search for the deleted item. */ - struct inode * p_s_inode,/* inode is here just to update i_blocks */ + struct inode * p_s_inode,/* inode is here just to update i_blocks and quotas */ struct buffer_head * p_s_un_bh) /* NULL or unformatted node pointer. */ { struct super_block * p_s_sb = p_s_inode->i_sb; struct tree_balance s_del_balance; struct item_head s_ih; + struct item_head *q_ih; + int quota_cut_bytes; int n_ret_value, n_del_size, n_removed; @@ -1244,7 +1306,7 @@ int reiserfs_delete_item (struct reiserfs_transaction_handle *th, copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path)); s_del_balance.insert_size[0] = n_del_size; - n_ret_value = fix_nodes(M_DELETE, &s_del_balance, NULL, 0); + n_ret_value = fix_nodes(M_DELETE, &s_del_balance, NULL, NULL); if ( n_ret_value != REPEAT_SEARCH ) break; @@ -1255,8 +1317,8 @@ int reiserfs_delete_item (struct reiserfs_transaction_handle *th, if (n_ret_value == IO_ERROR) break; if (n_ret_value == FILE_NOT_FOUND) { - reiserfs_warning ("vs-5340: reiserfs_delete_item: " - "no items of the file %K found\n", p_s_item_key); + reiserfs_warning (p_s_sb, "vs-5340: reiserfs_delete_item: " + "no items of the file %K found", p_s_item_key); break; } } /* while (1) */ @@ -1268,6 +1330,22 @@ int reiserfs_delete_item (struct reiserfs_transaction_handle *th, // reiserfs_delete_item returns item length when success n_ret_value = calc_deleted_bytes_number(&s_del_balance, M_DELETE); + q_ih = get_ih(p_s_path) ; + quota_cut_bytes = ih_item_len(q_ih) ; + + /* hack so the quota code doesn't have to guess if the file + ** has a tail. On tail insert, we allocate quota for 1 unformatted node. + ** We test the offset because the tail might have been + ** split into multiple items, and we only want to decrement for + ** the unfm node once + */ + if (!S_ISLNK (p_s_inode->i_mode) && is_direct_le_ih(q_ih)) { + if ((le_ih_k_offset(q_ih) & (p_s_sb->s_blocksize - 1)) == 1) { + quota_cut_bytes = p_s_sb->s_blocksize + UNFM_P_SIZE; + } else { + quota_cut_bytes = 0 ; + } + } if ( p_s_un_bh ) { int off; @@ -1299,10 +1377,14 @@ int reiserfs_delete_item (struct reiserfs_transaction_handle *th, B_I_PITEM(PATH_PLAST_BUFFER(p_s_path), &s_ih), n_ret_value); kunmap_atomic(data, KM_USER0); } - /* Perform balancing after all resources have been collected at once. */ do_balance(&s_del_balance, NULL, NULL, M_DELETE); +#ifdef REISERQUOTA_DEBUG + reiserfs_debug (p_s_sb, "reiserquota delete_item(): freeing %u, id=%u type=%c", quota_cut_bytes, p_s_inode->i_uid, head2type(&s_ih)); +#endif + DQUOT_FREE_SPACE_NODIRTY(p_s_inode, quota_cut_bytes); + /* Return deleted body length */ return n_ret_value; } @@ -1327,22 +1409,26 @@ int reiserfs_delete_item (struct reiserfs_transaction_handle *th, /* this deletes item which never gets split */ void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th, + struct inode *inode, struct key * key) { struct tree_balance tb; INITIALIZE_PATH (path); - int item_len; + int item_len = 0; int tb_init = 0 ; struct cpu_key cpu_key; int retval; + int quota_cut_bytes = 0; le_key2cpu_key (&cpu_key, key); while (1) { retval = search_item (th->t_super, &cpu_key, &path); if (retval == IO_ERROR) { - reiserfs_warning ("vs-5350: reiserfs_delete_solid_item: " - "i/o failure occurred trying to delete %K\n", &cpu_key); + reiserfs_warning (th->t_super, + "vs-5350: reiserfs_delete_solid_item: " + "i/o failure occurred trying to delete %K", + &cpu_key); break; } if (retval != ITEM_FOUND) { @@ -1350,7 +1436,7 @@ void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th, // No need for a warning, if there is just no free space to insert '..' item into the newly-created subdir if ( !( (unsigned long long) GET_HASH_VALUE (le_key_k_offset (le_key_version (key), key)) == 0 && \ (unsigned long long) GET_GENERATION_NUMBER (le_key_k_offset (le_key_version (key), key)) == 1 ) ) - reiserfs_warning ("vs-5355: reiserfs_delete_solid_item: %k not found", key); + reiserfs_warning (th->t_super, "vs-5355: reiserfs_delete_solid_item: %k not found", key); break; } if (!tb_init) { @@ -1358,21 +1444,28 @@ void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th, 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)) ; - retval = fix_nodes (M_DELETE, &tb, NULL, 0); + retval = fix_nodes (M_DELETE, &tb, NULL, NULL); if (retval == REPEAT_SEARCH) { PROC_INFO_INC( th -> t_super, delete_solid_item_restarted ); continue; } if (retval == CARRY_ON) { - do_balance (&tb, 0, 0, M_DELETE); + do_balance (&tb, NULL, NULL, M_DELETE); + if (inode) { /* Should we count quota for item? (we don't count quotas for save-links) */ +#ifdef REISERQUOTA_DEBUG + reiserfs_debug (th->t_super, "reiserquota delete_solid_item(): freeing %u id=%u type=%c", quota_cut_bytes, inode->i_uid, key2type(key)); +#endif + DQUOT_FREE_SPACE_NODIRTY(inode, quota_cut_bytes); + } break; } // IO_ERROR, NO_DISK_SPACE, etc - reiserfs_warning ("vs-5360: reiserfs_delete_solid_item: " - "could not delete %K due to fix_nodes failure\n", &cpu_key); + reiserfs_warning (th->t_super, "vs-5360: reiserfs_delete_solid_item: " + "could not delete %K due to fix_nodes failure", &cpu_key); unfix_nodes (&tb); break; } @@ -1399,9 +1492,44 @@ void reiserfs_delete_object (struct reiserfs_transaction_handle *th, struct inod } /* USE_INODE_GENERATION_COUNTER */ #endif - reiserfs_delete_solid_item (th, INODE_PKEY (inode)); + reiserfs_delete_solid_item (th, inode, INODE_PKEY (inode)); } +static void +unmap_buffers(struct page *page, loff_t pos) { + struct buffer_head *bh ; + struct buffer_head *head ; + struct buffer_head *next ; + unsigned long tail_index ; + unsigned long cur_index ; + + if (page) { + if (page_has_buffers(page)) { + tail_index = pos & (PAGE_CACHE_SIZE - 1) ; + cur_index = 0 ; + head = page_buffers(page) ; + bh = head ; + do { + next = bh->b_this_page ; + + /* we want to unmap the buffers that contain the tail, and + ** all the buffers after it (since the tail must be at the + ** end of the file). We don't want to unmap file data + ** before the tail, since it might be dirty and waiting to + ** reach disk + */ + cur_index += bh->b_size ; + if (cur_index > tail_index) { + reiserfs_unmap_buffer(bh) ; + } + bh = next ; + } while (bh != head) ; + if ( PAGE_SIZE == bh->b_size ) { + clear_page_dirty(page); + } + } + } +} static int maybe_indirect_to_direct (struct reiserfs_transaction_handle *th, struct inode * p_s_inode, @@ -1459,14 +1587,14 @@ static void indirect_to_direct_roll_back (struct reiserfs_transaction_handle *th "vs-5616: appended bytes found"); PATH_LAST_POSITION (path) --; - removed = reiserfs_delete_item (th, path, &tail_key, inode, 0/*unbh not needed*/); + 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); } - printk ("indirect_to_direct_roll_back: indirect_to_direct conversion has been rolled back due to lack of disk space\n"); + reiserfs_warning (inode->i_sb, "indirect_to_direct_roll_back: indirect_to_direct conversion has been rolled back due to lack of disk space"); //mark_file_without_tail (inode); mark_inode_dirty (inode); } @@ -1486,13 +1614,15 @@ int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th, structure by using the init_tb_struct and fix_nodes functions. After that we can make tree balancing. */ struct tree_balance s_cut_balance; + struct item_head *p_le_ih; int n_cut_size = 0, /* Amount to be cut. */ n_ret_value = CARRY_ON, n_removed = 0, /* Number of the removed unformatted nodes. */ n_is_inode_locked = 0; char c_mode; /* Mode of the balance. */ int retval2 = -1; - + int quota_cut_bytes; + loff_t tail_pos = 0; init_tb_struct(th, &s_cut_balance, p_s_inode->i_sb, p_s_path, n_cut_size); @@ -1532,6 +1662,7 @@ int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th, set_cpu_key_k_type (p_s_item_key, TYPE_INDIRECT); p_s_item_key->key_length = 4; n_new_file_size -= (n_new_file_size & (p_s_sb->s_blocksize - 1)); + tail_pos = n_new_file_size; set_cpu_key_k_offset (p_s_item_key, n_new_file_size + 1); if ( search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path) == POSITION_NOT_FOUND ){ print_block (PATH_PLAST_BUFFER (p_s_path), 3, PATH_LAST_POSITION (p_s_path) - 1, PATH_LAST_POSITION (p_s_path) + 1); @@ -1546,7 +1677,7 @@ int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th, s_cut_balance.insert_size[0] = n_cut_size; - n_ret_value = fix_nodes(c_mode, &s_cut_balance, NULL, 0); + n_ret_value = fix_nodes(c_mode, &s_cut_balance, NULL, NULL); if ( n_ret_value != REPEAT_SEARCH ) break; @@ -1556,7 +1687,7 @@ int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th, if (n_ret_value == POSITION_FOUND) continue; - reiserfs_warning ("PAP-5610: reiserfs_cut_from_item: item %K not found\n", p_s_item_key); + reiserfs_warning (p_s_sb, "PAP-5610: reiserfs_cut_from_item: item %K not found", p_s_item_key); unfix_nodes (&s_cut_balance); return (n_ret_value == IO_ERROR) ? -EIO : -ENOENT; } /* while */ @@ -1569,7 +1700,7 @@ int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th, indirect_to_direct_roll_back (th, p_s_inode, p_s_path); } if (n_ret_value == NO_DISK_SPACE) - reiserfs_warning ("NO_DISK_SPACE"); + reiserfs_warning (p_s_sb, "NO_DISK_SPACE"); unfix_nodes (&s_cut_balance); return -EIO; } @@ -1579,23 +1710,27 @@ int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th, RFALSE( c_mode == M_PASTE || c_mode == M_INSERT, "invalid mode"); /* Calculate number of bytes that need to be cut from the item. */ + quota_cut_bytes = ( c_mode == M_DELETE ) ? ih_item_len(get_ih(p_s_path)) : -s_cut_balance.insert_size[0]; if (retval2 == -1) n_ret_value = calc_deleted_bytes_number(&s_cut_balance, c_mode); else n_ret_value = retval2; - - if ( c_mode == M_DELETE ) { - struct item_head * p_le_ih = PATH_PITEM_HEAD (s_cut_balance.tb_path); - - if ( is_direct_le_ih (p_le_ih) && (le_ih_k_offset (p_le_ih) & (p_s_sb->s_blocksize - 1)) == 1 ) { - /* we delete first part of tail which was stored in direct - item(s) */ + + + /* For direct items, we only change the quota when deleting the last + ** item. + */ + p_le_ih = PATH_PITEM_HEAD (s_cut_balance.tb_path); + if (!S_ISLNK (p_s_inode->i_mode) && is_direct_le_ih(p_le_ih)) { + if (c_mode == M_DELETE && + (le_ih_k_offset (p_le_ih) & (p_s_sb->s_blocksize - 1)) == 1 ) { // FIXME: this is to keep 3.5 happy REISERFS_I(p_s_inode)->i_first_direct_byte = U32_MAX; - p_s_inode->i_blocks -= p_s_sb->s_blocksize / 512; + quota_cut_bytes = p_s_sb->s_blocksize + UNFM_P_SIZE ; + } else { + quota_cut_bytes = 0 ; } } - #ifdef CONFIG_REISERFS_CHECK if (n_is_inode_locked) { struct item_head * le_ih = PATH_PITEM_HEAD (s_cut_balance.tb_path); @@ -1625,24 +1760,29 @@ int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th, if ( n_is_inode_locked ) { /* we've done an indirect->direct conversion. when the data block ** was freed, it was removed from the list of blocks that must - ** be flushed before the transaction commits, so we don't need to - ** deal with it here. + ** be flushed before the transaction commits, make sure to + ** unmap and invalidate it */ + unmap_buffers(page, tail_pos); REISERFS_I(p_s_inode)->i_flags &= ~i_pack_on_close_mask ; } +#ifdef REISERQUOTA_DEBUG + reiserfs_debug (p_s_inode->i_sb, "reiserquota cut_from_item(): freeing %u id=%u type=%c", quota_cut_bytes, p_s_inode->i_uid, '?'); +#endif + DQUOT_FREE_SPACE_NODIRTY(p_s_inode, quota_cut_bytes); return n_ret_value; } - static void truncate_directory (struct reiserfs_transaction_handle *th, struct inode * inode) { if (inode->i_nlink) - reiserfs_warning ("vs-5655: truncate_directory: link count != 0\n"); + reiserfs_warning (inode->i_sb, + "vs-5655: truncate_directory: link count != 0"); set_le_key_k_offset (KEY_FORMAT_3_5, INODE_PKEY (inode), DOT_OFFSET); set_le_key_k_type (KEY_FORMAT_3_5, INODE_PKEY (inode), TYPE_DIRENTRY); - reiserfs_delete_solid_item (th, INODE_PKEY (inode)); - + 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); } @@ -1686,14 +1826,14 @@ void reiserfs_do_truncate (struct reiserfs_transaction_handle *th, retval = search_for_position_by_key(p_s_inode->i_sb, &s_item_key, &s_search_path); if (retval == IO_ERROR) { - reiserfs_warning ("vs-5657: reiserfs_do_truncate: " - "i/o failure occurred trying to truncate %K\n", &s_item_key); + reiserfs_warning (p_s_inode->i_sb, "vs-5657: reiserfs_do_truncate: " + "i/o failure occurred trying to truncate %K", &s_item_key); return; } if (retval == POSITION_FOUND || retval == FILE_NOT_FOUND) { pathrelse (&s_search_path); - reiserfs_warning ("PAP-5660: reiserfs_do_truncate: " - "wrong result %d of search for %K\n", retval, &s_item_key); + reiserfs_warning (p_s_inode->i_sb, "PAP-5660: reiserfs_do_truncate: " + "wrong result %d of search for %K", retval, &s_item_key); return; } @@ -1712,6 +1852,12 @@ void reiserfs_do_truncate (struct reiserfs_transaction_handle *th, space, this file would have this file size */ n_file_size = offset + bytes - 1; } + /* + * are we doing a full truncate or delete, if so + * kick in the reada code + */ + if (n_new_file_size == 0) + s_search_path.reada = PATH_READA | PATH_READA_BACK; if ( n_file_size == 0 || n_file_size < n_new_file_size ) { goto update_and_out ; @@ -1724,7 +1870,7 @@ void reiserfs_do_truncate (struct reiserfs_transaction_handle *th, /* Cut or delete file item. */ n_deleted = reiserfs_cut_from_item(th, &s_search_path, &s_item_key, p_s_inode, page, n_new_file_size); if (n_deleted < 0) { - reiserfs_warning ("vs-5665: reiserfs_do_truncate: reiserfs_cut_from_item failed"); + reiserfs_warning (p_s_inode->i_sb, "vs-5665: reiserfs_do_truncate: reiserfs_cut_from_item failed"); reiserfs_check_path(&s_search_path) ; return; } @@ -1764,7 +1910,7 @@ void reiserfs_do_truncate (struct reiserfs_transaction_handle *th, search_for_position_by_key(p_s_inode->i_sb, &s_item_key, &s_search_path) == POSITION_FOUND ) ; RFALSE( n_file_size > ROUND_UP (n_new_file_size), - "PAP-5680: truncate did not finish: new_file_size %Ld, current %Ld, oid %d\n", + "PAP-5680: truncate did not finish: new_file_size %Ld, current %Ld, oid %d", n_new_file_size, n_file_size, s_item_key.on_disk_key.k_objectid); update_and_out: @@ -1789,7 +1935,7 @@ static void check_research_for_paste (struct path * path, if (le_ih_k_offset (found_ih) + op_bytes_number (found_ih, get_last_bh (path)->b_size) != cpu_key_k_offset (p_s_key) || op_bytes_number (found_ih, get_last_bh (path)->b_size) != pos_in_item (path)) - reiserfs_panic (0, "PAP-5720: check_research_for_paste: " + reiserfs_panic (NULL, "PAP-5720: check_research_for_paste: " "found direct item %h or position (%d) does not match to key %K", found_ih, pos_in_item (path), p_s_key); } @@ -1797,7 +1943,7 @@ static void check_research_for_paste (struct path * path, if (le_ih_k_offset (found_ih) + op_bytes_number (found_ih, get_last_bh (path)->b_size) != cpu_key_k_offset (p_s_key) || I_UNFM_NUM (found_ih) != pos_in_item (path) || get_ih_free_space (found_ih) != 0) - reiserfs_panic (0, "PAP-5730: check_research_for_paste: " + reiserfs_panic (NULL, "PAP-5730: check_research_for_paste: " "found indirect item (%h) or position (%d) does not match to key (%K)", found_ih, pos_in_item (path), p_s_key); } @@ -1809,18 +1955,37 @@ static void check_research_for_paste (struct path * path, int reiserfs_paste_into_item (struct reiserfs_transaction_handle *th, struct path * p_s_search_path, /* Path to the pasted item. */ const struct cpu_key * p_s_key, /* Key to search for the needed item.*/ + struct inode * inode, /* Inode item belongs to */ const char * p_c_body, /* Pointer to the bytes to paste. */ int n_pasted_size) /* Size of pasted bytes. */ { struct tree_balance s_paste_balance; int retval; + int fs_gen; + + fs_gen = get_generation(inode->i_sb) ; +#ifdef REISERQUOTA_DEBUG + reiserfs_debug (inode->i_sb, "reiserquota paste_into_item(): allocating %u id=%u type=%c", n_pasted_size, inode->i_uid, key2type(&(p_s_key->on_disk_key))); +#endif + + if (DQUOT_ALLOC_SPACE_NODIRTY(inode, n_pasted_size)) { + pathrelse(p_s_search_path); + return -EDQUOT; + } init_tb_struct(th, &s_paste_balance, th->t_super, p_s_search_path, n_pasted_size); #ifdef DISPLACE_NEW_PACKING_LOCALITIES s_paste_balance.key = p_s_key->on_disk_key; #endif - - while ( (retval = fix_nodes(M_PASTE, &s_paste_balance, NULL, p_c_body)) == REPEAT_SEARCH ) { + + /* DQUOT_* can schedule, must check before the fix_nodes */ + if (fs_changed(fs_gen, inode->i_sb)) { + goto search_again; + } + + while ((retval = fix_nodes(M_PASTE, &s_paste_balance, NULL, p_c_body)) == +REPEAT_SEARCH ) { +search_again: /* file system changed while we were in the fix_nodes */ PROC_INFO_INC( th -> t_super, paste_into_item_restarted ); retval = search_for_position_by_key (th->t_super, p_s_key, p_s_search_path); @@ -1829,7 +1994,7 @@ int reiserfs_paste_into_item (struct reiserfs_transaction_handle *th, goto error_out ; } if (retval == POSITION_FOUND) { - reiserfs_warning ("PAP-5710: reiserfs_paste_into_item: entry or pasted byte (%K) exists\n", p_s_key); + reiserfs_warning (inode->i_sb, "PAP-5710: reiserfs_paste_into_item: entry or pasted byte (%K) exists", p_s_key); retval = -EEXIST ; goto error_out ; } @@ -1849,6 +2014,10 @@ int reiserfs_paste_into_item (struct reiserfs_transaction_handle *th, error_out: /* this also releases the path */ unfix_nodes(&s_paste_balance); +#ifdef REISERQUOTA_DEBUG + reiserfs_debug (inode->i_sb, "reiserquota paste_into_item(): freeing %u id=%u type=%c", n_pasted_size, inode->i_uid, key2type(&(p_s_key->on_disk_key))); +#endif + DQUOT_FREE_SPACE_NODIRTY(inode, n_pasted_size); return retval ; } @@ -1858,23 +2027,45 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th, struct path * p_s_path, /* Path to the inserteded item. */ const struct cpu_key * key, struct item_head * p_s_ih, /* Pointer to the item header to insert.*/ + struct inode * inode, const char * p_c_body) /* Pointer to the bytes to insert. */ { struct tree_balance s_ins_balance; int retval; - + int fs_gen = 0 ; + int quota_bytes = 0 ; + + if (inode) { /* Do we count quotas for item? */ + fs_gen = get_generation(inode->i_sb); + quota_bytes = ih_item_len(p_s_ih); + + /* hack so the quota code doesn't have to guess if the file has + ** a tail, links are always tails, so there's no guessing needed + */ + if (!S_ISLNK (inode->i_mode) && is_direct_le_ih(p_s_ih)) { + quota_bytes = inode->i_sb->s_blocksize + UNFM_P_SIZE ; + } +#ifdef REISERQUOTA_DEBUG + reiserfs_debug (inode->i_sb, "reiserquota insert_item(): allocating %u id=%u type=%c", quota_bytes, inode->i_uid, head2type(p_s_ih)); +#endif + /* We can't dirty inode here. It would be immediately written but + * appropriate stat item isn't inserted yet... */ + if (DQUOT_ALLOC_SPACE_NODIRTY(inode, quota_bytes)) { + pathrelse(p_s_path); + return -EDQUOT; + } + } init_tb_struct(th, &s_ins_balance, th->t_super, p_s_path, IH_SIZE + ih_item_len(p_s_ih)); #ifdef DISPLACE_NEW_PACKING_LOCALITIES s_ins_balance.key = key->on_disk_key; #endif - - /* - if (p_c_body == 0) - n_zeros_num = ih_item_len(p_s_ih); - */ - // le_key2cpu_key (&key, &(p_s_ih->ih_key)); + /* 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; + } while ( (retval = fix_nodes(M_INSERT, &s_ins_balance, p_s_ih, p_c_body)) == REPEAT_SEARCH) { +search_again: /* file system changed while we were in the fix_nodes */ PROC_INFO_INC( th -> t_super, insert_item_restarted ); retval = search_item (th->t_super, key, p_s_path); @@ -1883,8 +2074,8 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th, goto error_out ; } if (retval == ITEM_FOUND) { - reiserfs_warning ("PAP-5760: reiserfs_insert_item: " - "key %K already exists in the tree\n", key); + reiserfs_warning (th->t_super, "PAP-5760: reiserfs_insert_item: " + "key %K already exists in the tree", key); retval = -EEXIST ; goto error_out; } @@ -1900,6 +2091,11 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th, error_out: /* also releases the path */ unfix_nodes(&s_ins_balance); +#ifdef REISERQUOTA_DEBUG + reiserfs_debug (th->t_super, "reiserquota insert_item(): freeing %u id=%u type=%c", quota_bytes, inode->i_uid, head2type(p_s_ih)); +#endif + if (inode) + DQUOT_FREE_SPACE_NODIRTY(inode, quota_bytes) ; return retval; }