- tmp = get_block_num(p_n_unfm_pointer,0);
- put_block_num(p_n_unfm_pointer, 0, 0);
- journal_mark_dirty (th, p_s_sb, p_s_bh);
- reiserfs_free_block(th, inode, tmp, 1);
- if ( item_moved (&s_ih, p_s_path) ) {
- need_research = 1;
- break ;
- }
- }
-
- /* a trick. If the buffer has been logged, this
- ** will do nothing. If we've broken the loop without
- ** logging it, it will restore the buffer
- **
- */
- reiserfs_restore_prepared_buffer(p_s_sb, p_s_bh);
-
- /* This loop can be optimized. */
- } while ( (*p_n_removed < n_unfm_number || need_research) &&
- search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path) == POSITION_FOUND );
-
- RFALSE( *p_n_removed < n_unfm_number,
- "PAP-5310: indirect item is not found");
- RFALSE( item_moved (&s_ih, p_s_path),
- "after while, comp failed, retry") ;
-
- if (c_mode == M_CUT)
- pos_in_item (p_s_path) *= UNFM_P_SIZE;
- return c_mode;
- }
+ /* Direct item. */
+ if (is_direct_le_ih(p_le_ih))
+ return prepare_for_direct_item(p_s_path, p_le_ih, inode,
+ n_new_file_length, p_n_cut_size);
+
+ /* Case of an indirect item. */
+ {
+ int n_unfm_number, /* Number of the item unformatted nodes. */
+ n_counter, n_blk_size;
+ __le32 *p_n_unfm_pointer; /* Pointer to the unformatted node number. */
+ __u32 tmp;
+ struct item_head s_ih; /* Item header. */
+ char c_mode; /* Returned mode of the balance. */
+ int need_research;
+
+ n_blk_size = p_s_sb->s_blocksize;
+
+ /* Search for the needed object indirect item until there are no unformatted nodes to be removed. */
+ do {
+ need_research = 0;
+ p_s_bh = PATH_PLAST_BUFFER(p_s_path);
+ /* Copy indirect item header to a temp variable. */
+ copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path));
+ /* Calculate number of unformatted nodes in this item. */
+ n_unfm_number = I_UNFM_NUM(&s_ih);
+
+ RFALSE(!is_indirect_le_ih(&s_ih) || !n_unfm_number ||
+ pos_in_item(p_s_path) + 1 != n_unfm_number,
+ "PAP-5240: invalid item %h "
+ "n_unfm_number = %d *p_n_pos_in_item = %d",
+ &s_ih, n_unfm_number, pos_in_item(p_s_path));
+
+ /* Calculate balance mode and position in the item to remove unformatted nodes. */
+ if (n_new_file_length == max_reiserfs_offset(inode)) { /* Case of delete. */
+ pos_in_item(p_s_path) = 0;
+ *p_n_cut_size = -(IH_SIZE + ih_item_len(&s_ih));
+ c_mode = M_DELETE;
+ } else { /* Case of truncate. */
+ if (n_new_file_length < le_ih_k_offset(&s_ih)) {
+ pos_in_item(p_s_path) = 0;
+ *p_n_cut_size =
+ -(IH_SIZE + ih_item_len(&s_ih));
+ c_mode = M_DELETE; /* Delete this item. */
+ } else {
+ /* indirect item must be truncated starting from *p_n_pos_in_item-th position */
+ pos_in_item(p_s_path) =
+ (n_new_file_length + n_blk_size -
+ le_ih_k_offset(&s_ih)) >> p_s_sb->
+ s_blocksize_bits;
+
+ RFALSE(pos_in_item(p_s_path) >
+ n_unfm_number,
+ "PAP-5250: invalid position in the item");
+
+ /* Either convert last unformatted node of indirect item to direct item or increase
+ its free space. */
+ if (pos_in_item(p_s_path) ==
+ n_unfm_number) {
+ *p_n_cut_size = 0; /* Nothing to cut. */
+ return M_CONVERT; /* Maybe convert last unformatted node to the direct item. */
+ }
+ /* Calculate size to cut. */
+ *p_n_cut_size =
+ -(ih_item_len(&s_ih) -
+ pos_in_item(p_s_path) *
+ UNFM_P_SIZE);
+
+ c_mode = M_CUT; /* Cut from this indirect item. */
+ }
+ }
+
+ RFALSE(n_unfm_number <= pos_in_item(p_s_path),
+ "PAP-5260: invalid position in the indirect item");
+
+ /* pointers to be cut */
+ n_unfm_number -= pos_in_item(p_s_path);
+ /* Set pointer to the last unformatted node pointer that is to be cut. */
+ p_n_unfm_pointer =
+ (__le32 *) B_I_PITEM(p_s_bh,
+ &s_ih) + I_UNFM_NUM(&s_ih) -
+ 1 - *p_n_removed;
+
+ /* We go through the unformatted nodes pointers of the indirect
+ item and look for the unformatted nodes in the cache. If we
+ found some of them we free it, zero corresponding indirect item
+ entry and log buffer containing that indirect item. For this we
+ need to prepare last path element for logging. If some
+ unformatted node has b_count > 1 we must not free this
+ unformatted node since it is in use. */
+ reiserfs_prepare_for_journal(p_s_sb, p_s_bh, 1);
+ // note: path could be changed, first line in for loop takes care
+ // of it
+
+ for (n_counter = *p_n_removed;
+ n_counter < n_unfm_number;
+ n_counter++, p_n_unfm_pointer--) {
+
+ cond_resched();
+ if (item_moved(&s_ih, p_s_path)) {
+ need_research = 1;
+ break;
+ }
+ RFALSE(p_n_unfm_pointer <
+ (__le32 *) B_I_PITEM(p_s_bh, &s_ih)
+ || p_n_unfm_pointer >
+ (__le32 *) B_I_PITEM(p_s_bh,
+ &s_ih) +
+ I_UNFM_NUM(&s_ih) - 1,
+ "vs-5265: pointer out of range");
+
+ /* Hole, nothing to remove. */
+ if (!get_block_num(p_n_unfm_pointer, 0)) {
+ (*p_n_removed)++;
+ continue;
+ }
+
+ (*p_n_removed)++;
+
+ tmp = get_block_num(p_n_unfm_pointer, 0);
+ put_block_num(p_n_unfm_pointer, 0, 0);
+ journal_mark_dirty(th, p_s_sb, p_s_bh);
+ reiserfs_free_block(th, inode, tmp, 1);
+ if (item_moved(&s_ih, p_s_path)) {
+ need_research = 1;
+ break;
+ }
+ }
+
+ /* a trick. If the buffer has been logged, this
+ ** will do nothing. If we've broken the loop without
+ ** logging it, it will restore the buffer
+ **
+ */
+ reiserfs_restore_prepared_buffer(p_s_sb, p_s_bh);
+
+ /* This loop can be optimized. */
+ } while ((*p_n_removed < n_unfm_number || need_research) &&
+ search_for_position_by_key(p_s_sb, p_s_item_key,
+ p_s_path) ==
+ POSITION_FOUND);
+
+ RFALSE(*p_n_removed < n_unfm_number,
+ "PAP-5310: indirect item is not found");
+ RFALSE(item_moved(&s_ih, p_s_path),
+ "after while, comp failed, retry");
+
+ if (c_mode == M_CUT)
+ pos_in_item(p_s_path) *= UNFM_P_SIZE;
+ return c_mode;
+ }