# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#                  ChangeSet    1.589   -> 1.590
#       fs/reiserfs/do_balan.c  1.10    -> 1.11
#        fs/reiserfs/inode.c    1.35    -> 1.36
#       fs/reiserfs/tail_conversion.c   1.13    -> 1.14
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/09/09      [email protected]       1.590
# Added support for unformatted pointers insertion. Implement hole-creation using this new mechanism which is much faster.
# --------------------------------------------
#
diff -Nru a/fs/reiserfs/do_balan.c b/fs/reiserfs/do_balan.c
--- a/fs/reiserfs/do_balan.c    Mon Sep  9 09:28:25 2002
+++ b/fs/reiserfs/do_balan.c    Mon Sep  9 09:28:25 2002
@@ -304,8 +304,6 @@
                   int new_item_len;
                   int version;

-                   RFALSE (!is_direct_le_ih (ih),
-                           "PAP-12075: only direct inserted item can be broken. %h", ih);
                   ret_val = leaf_shift_left (tb, tb->lnum[0]-1, -1);

                   /* Calculate item length to insert to S[0] */
@@ -328,7 +326,7 @@
                   version = ih_version (ih);

                   /* Calculate key component, item length and body to insert into S[0] */
-                    set_le_ih_k_offset( ih, le_ih_k_offset( ih ) + tb->lbytes );
+                    set_le_ih_k_offset( ih, le_ih_k_offset( ih ) + tb->lbytes * (is_indirect_le_ih(ih)?tb->tb_sb->s_blocksize/UNFM_P_SIZE:1) );

                   put_ih_item_len( ih, new_item_len );
                   if ( tb->lbytes >  zeros_num ) {
@@ -437,23 +435,28 @@
                               ih_item_len( B_N_PITEM_HEAD(tb->L[0],n+item_pos-ret_val)),
                               l_n,body, zeros_num > l_n ? l_n : zeros_num
                               );
-
-                           RFALSE( l_n &&
-                                   is_indirect_le_ih(B_N_PITEM_HEAD
-                                                     (tb->L[0],
-                                                      n + item_pos - ret_val)),
-                                   "PAP-12110: pasting more than 1 unformatted node pointer into indirect item");
-
                           /* 0-th item in S0 can be only of DIRECT type when l_n != 0*/
                           {
-                             int version;
-
-                             version = ih_version (B_N_PITEM_HEAD (tbS0, 0));
-                             set_le_key_k_offset (version, B_N_PKEY (tbS0, 0),
-                                                  le_key_k_offset (version, B_N_PKEY (tbS0, 0)) + l_n);
-                             version = ih_version (B_N_PITEM_HEAD(tb->CFL[0],tb->lkey[0]));
-                             set_le_key_k_offset (version, B_N_PDELIM_KEY(tb->CFL[0],tb->lkey[0]),
-                                                  le_key_k_offset (version, B_N_PDELIM_KEY(tb->CFL[0],tb->lkey[0])) + l_n);
+                               int version;
+                               int temp_l = l_n;
+
+                               RFALSE (ih_item_len (B_N_PITEM_HEAD (tbS0, 0)),
+                                       "PAP-12106: item length must be 0");
+                               RFALSE (comp_short_le_keys (B_N_PKEY (tbS0, 0),
+                                                           B_N_PKEY (tb->L[0],
+                                                                           n + item_pos - ret_val)),
+                                       "PAP-12107: items must be of the same file");
+                               if (is_indirect_le_ih(B_N_PITEM_HEAD (tb->L[0],
+                                                                     n + item_pos - ret_val))) {
+                                   temp_l = (l_n / UNFM_P_SIZE) * tb->tb_sb->s_blocksize;
+                               }
+                               /* update key of first item in S0 */
+                               version = ih_version (B_N_PITEM_HEAD (tbS0, 0));
+                               set_le_key_k_offset (version, B_N_PKEY (tbS0, 0),
+                                                    le_key_k_offset (version, B_N_PKEY (tbS0, 0)) + temp_l);
+                               /* update left delimiting key */
+                               set_le_key_k_offset (version, B_N_PDELIM_KEY(tb->CFL[0],tb->lkey[0]),
+                                                    le_key_k_offset (version, B_N_PDELIM_KEY(tb->CFL[0],tb->lkey[0])) + temp_l);
                           }

                           /* Calculate new body, position in item and insert_size[0] */
@@ -522,7 +525,7 @@
                           );
                   /* if appended item is indirect item, put unformatted node into un list */
                   if (is_indirect_le_ih (pasted))
-                       set_ih_free_space (pasted, ((struct unfm_nodeinfo*)body)->unfm_freespace);
+                       set_ih_free_space (pasted, 0);
                   tb->insert_size[0] = 0;
                   zeros_num = 0;
               }
@@ -550,15 +553,11 @@
           { /* new item or its part falls to R[0] */
               if ( item_pos == n - tb->rnum[0] + 1 && tb->rbytes != -1 )
               { /* part of new item falls into R[0] */
-                   int old_key_comp, old_len, r_zeros_number;
+                   loff_t old_key_comp, old_len, r_zeros_number;
                   const char * r_body;
                   int version;
                   loff_t offset;

-                   RFALSE( !is_direct_le_ih (ih),
-                           "PAP-12135: only direct item can be split. (%h)",
-                           ih);
-
                   leaf_shift_right(tb,tb->rnum[0]-1,-1);

                   version = ih_version(ih);
@@ -567,7 +566,7 @@
                   old_len = ih_item_len(ih);

                   /* Calculate key component and item length to insert into R[0] */
-                    offset = le_ih_k_offset( ih ) + (old_len - tb->rbytes );
+                    offset = le_ih_k_offset( ih ) + (old_len - tb->rbytes )*(is_indirect_le_ih(ih)?tb->tb_sb->s_blocksize/UNFM_P_SIZE:1);
                    set_le_ih_k_offset( ih, offset );
                   put_ih_item_len( ih, tb->rbytes);
                   /* Insert part of the item into R[0] */
@@ -575,13 +574,13 @@
                   bi.bi_bh = tb->R[0];
                   bi.bi_parent = tb->FR[0];
                   bi.bi_position = get_right_neighbor_position (tb, 0);
-                   if ( offset - old_key_comp > zeros_num ) {
+                   if ( (old_len - tb->rbytes) > zeros_num ) {
                       r_zeros_number = 0;
-                       r_body = body + offset - old_key_comp - zeros_num;
+                       r_body = body + (old_len - tb->rbytes) - zeros_num;
                   }
                   else {
                       r_body = body;
-                       r_zeros_number = zeros_num - (offset - old_key_comp);
+                       r_zeros_number = zeros_num - (old_len - tb->rbytes);
                       zeros_num -= r_zeros_number;
                   }

@@ -692,12 +691,17 @@

                       {
                         int version;
+                         unsigned long temp_rem = n_rem;

                         version = ih_version (B_N_PITEM_HEAD (tb->R[0],0));
+                         if (is_indirect_le_key(version,B_N_PKEY(tb->R[0],0))){
+                             temp_rem = (n_rem / UNFM_P_SIZE) *
+                                        tb->tb_sb->s_blocksize;
+                         }
                         set_le_key_k_offset (version, B_N_PKEY(tb->R[0],0),
-                                              le_key_k_offset (version, B_N_PKEY(tb->R[0],0)) + n_rem);
+                                              le_key_k_offset (version, B_N_PKEY(tb->R[0],0)) + temp_rem);
                         set_le_key_k_offset (version, B_N_PDELIM_KEY(tb->CFR[0],tb->rkey[0]),
-                                              le_key_k_offset (version, B_N_PDELIM_KEY(tb->CFR[0],tb->rkey[0])) + n_rem);
+                                              le_key_k_offset (version, B_N_PDELIM_KEY(tb->CFR[0],tb->rkey[0])) + temp_rem);
                       }
/*               k_offset (B_N_PKEY(tb->R[0],0)) += n_rem;
                 k_offset (B_N_PDELIM_KEY(tb->CFR[0],tb->rkey[0])) += n_rem;*/
@@ -721,13 +725,12 @@
                       leaf_paste_in_buffer(&bi, 0, n_shift, tb->insert_size[0] - n_rem, r_body, r_zeros_number);

                       if (is_indirect_le_ih (B_N_PITEM_HEAD(tb->R[0],0))) {
-
+#if 0
                           RFALSE( n_rem,
                                   "PAP-12160: paste more than one unformatted node pointer");
-
-                           set_ih_free_space (B_N_PITEM_HEAD(tb->R[0],0), ((struct unfm_nodeinfo*)body)->unfm_freespace);
+#endif
+                           set_ih_free_space (B_N_PITEM_HEAD(tb->R[0],0), 0);
                       }
-
                       tb->insert_size[0] = n_rem;
                       if ( ! n_rem )
                           pos_in_item ++;
@@ -766,7 +769,7 @@
                   }

                   if (is_indirect_le_ih (pasted))
-                       set_ih_free_space (pasted, ((struct unfm_nodeinfo*)body)->unfm_freespace);
+                       set_ih_free_space (pasted, 0);
                   zeros_num = tb->insert_size[0] = 0;
               }
           }
@@ -843,12 +846,6 @@
                   const char * r_body;
                   int version;

-                   RFALSE( !is_direct_le_ih(ih),
-                       /* The items which can be inserted are:
-                          Stat_data item, direct item, indirect item and directory item which consist of only two entries "." and "..".
-                          These items must not be broken except for a direct one. */
-                           "PAP-12205: non-direct item can not be broken when inserting");
-
                   /* Move snum[i]-1 items from S[0] to S_new[i] */
                   leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i] - 1, -1, S_new[i]);
                   /* Remember key component and item length */
@@ -858,7 +855,7 @@

                   /* Calculate key component and item length to insert into S_new[i] */
                    set_le_ih_k_offset( ih,
-                                le_ih_k_offset(ih) + (old_len - sbytes[i] ) );
+                                le_ih_k_offset(ih) + (old_len - sbytes[i] )*(is_indirect_le_ih(ih)?tb->tb_sb->s_blocksize/UNFM_P_SIZE:1) );

                   put_ih_item_len( ih, sbytes[i] );

@@ -868,13 +865,13 @@
                   bi.bi_parent = 0;
                   bi.bi_position = 0;

-                   if ( le_ih_k_offset (ih) - old_key_comp > zeros_num ) {
+                   if ( (old_len - sbytes[i]) > zeros_num ) {
                       r_zeros_number = 0;
-                       r_body = body + (le_ih_k_offset(ih) - old_key_comp) - zeros_num;
+                       r_body = body + (old_len - sbytes[i]) - zeros_num;
                   }
                   else {
                       r_body = body;
-                       r_zeros_number = zeros_num - (le_ih_k_offset (ih) - old_key_comp);
+                       r_zeros_number = zeros_num - (old_len - sbytes[i]);
                       zeros_num -= r_zeros_number;
                   }

@@ -995,11 +992,14 @@

                           tmp = B_N_PITEM_HEAD(S_new[i],0);
                           if (is_indirect_le_ih (tmp)) {
-                               if (n_rem)
-                                   reiserfs_panic (tb->tb_sb, "PAP-12230: balance_leaf: invalid action with indirect item");
-                               set_ih_free_space (tmp, ((struct unfm_nodeinfo*)body)->unfm_freespace);
+                               set_ih_free_space (tmp, 0);
+                               set_le_ih_k_offset( tmp, le_ih_k_offset(tmp) +
+                                                   (n_rem / UNFM_P_SIZE) *
+                                                   tb->tb_sb->s_blocksize);
+                           } else {
+                               set_le_ih_k_offset( tmp, le_ih_k_offset(tmp) +
+                                                   n_rem );
                           }
-                            set_le_ih_k_offset( tmp, le_ih_k_offset(tmp) + n_rem );
                       }

                       tb->insert_size[0] = n_rem;
@@ -1045,7 +1045,7 @@

                   /* if we paste to indirect item update ih_free_space */
                   if (is_indirect_le_ih (pasted))
-                       set_ih_free_space (pasted, ((struct unfm_nodeinfo*)body)->unfm_freespace);
+                       set_ih_free_space (pasted, 0);
                   zeros_num = tb->insert_size[0] = 0;
               }
           }
@@ -1141,11 +1141,12 @@
                   leaf_paste_in_buffer (&bi, item_pos, pos_in_item, tb->insert_size[0], body, zeros_num);

                   if (is_indirect_le_ih (pasted)) {
-
+#if 0
                       RFALSE( tb->insert_size[0] != UNFM_P_SIZE,
                               "PAP-12280: insert_size for indirect item must be %d, not %d",
                               UNFM_P_SIZE, tb->insert_size[0]);
-                       set_ih_free_space (pasted, ((struct unfm_nodeinfo*)body)->unfm_freespace);
+#endif
+                       set_ih_free_space (pasted, 0);
                   }
                   tb->insert_size[0] = 0;
               }
diff -Nru a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
--- a/fs/reiserfs/inode.c       Mon Sep  9 09:28:25 2002
+++ b/fs/reiserfs/inode.c       Mon Sep  9 09:28:25 2002
@@ -774,36 +774,69 @@
              pointer to 'block'-th block use block, which is already
              allocated */
           struct cpu_key tmp_key;
-           struct unfm_nodeinfo un = {0, 0};
+           unp_t unf_single=0; // We use this in case we need to allocate only
+                               // one block which is a fastpath
+           unp_t *un;
+           __u64 max_to_insert=MAX_ITEM_LEN(inode->i_sb->s_blocksize)/UNFM_P_SIZE;
+           __u64 blocks_needed;

           RFALSE( pos_in_item != ih_item_len(ih) / UNFM_P_SIZE,
                   "vs-804: invalid position for append");
+
           /* indirect item has to be appended, set up key of that position */
           make_cpu_key (&tmp_key, inode,
                         le_key_k_offset (version, &(ih->ih_key)) + op_bytes_number (ih, inode->i_sb->s_blocksize),
                         //pos_in_item * inode->i_sb->s_blocksize,
                         TYPE_INDIRECT, 3);// key type is unimportant
-
-           if (cpu_key_k_offset (&tmp_key) == cpu_key_k_offset (&key)) {
+
+           blocks_needed = 1 + ((cpu_key_k_offset (&key) - cpu_key_k_offset (&tmp_key)) >> inode->i_sb->s_blocksize_bits);
+           RFALSE( blocks_needed < 0, "green-805: invalid offset");
+
+           if ( blocks_needed == 1 ) {
+               un = &unf_single;
+           } else {
+               un=kmalloc( min(blocks_needed,max_to_insert)*UNFM_P_SIZE,
+                           GFP_ATOMIC); // We need to avoid scheduling.
+               if ( !un) {
+                   un = &unf_single;
+                   blocks_needed = 1;
+                   max_to_insert = 0;
+               } else
+                   memset(un, 0, UNFM_P_SIZE * min(blocks_needed,max_to_insert));
+           }
+           if ( blocks_needed <= max_to_insert) {
               /* we are going to add target block to the file. Use allocated
                  block for that */
-               un.unfm_nodenum = cpu_to_le32 (allocated_block_nr);
+               un[blocks_needed-1] = cpu_to_le32 (allocated_block_nr);
               set_block_dev_mapped (bh_result, allocated_block_nr, inode);
               bh_result->b_state |= (1UL << BH_New);
               done = 1;
           } else {
               /* paste hole to the indirect item */
+               // If kmalloc failed, max_to_insert becomes zero and it means we
+               // only have space for one block
+               blocks_needed=max_to_insert?max_to_insert:1;
           }
-           retval = reiserfs_paste_into_item (&th, &path, &tmp_key, (char *)&un, UNFM_P_SIZE);
+           retval = reiserfs_paste_into_item (&th, &path, &tmp_key, (char *)un, UNFM_P_SIZE * blocks_needed);
+
+           if (blocks_needed != 1)
+               kfree(un);
+
           if (retval) {
               reiserfs_free_block (&th, allocated_block_nr);
               goto failure;
           }
-           if (un.unfm_nodenum)
+           if (done) {
               inode->i_blocks += inode->i_sb->s_blocksize / 512;
+           } else {
+               // We need to mark new file size in case this function will be
+               // interrupted/aborted later on. And we may do this only for
+               // holes.
+               inode->i_size += inode->i_sb->s_blocksize * blocks_needed;
+           }
           //mark_tail_converted (inode);
       }
-
+
       if (done == 1)
           break;

diff -Nru a/fs/reiserfs/tail_conversion.c b/fs/reiserfs/tail_conversion.c
--- a/fs/reiserfs/tail_conversion.c     Mon Sep  9 09:28:25 2002
+++ b/fs/reiserfs/tail_conversion.c     Mon Sep  9 09:28:25 2002
@@ -30,7 +30,7 @@
                                key of unfm pointer to be pasted */
    int        n_blk_size,
      n_retval;          /* returned value for reiserfs_insert_item and clones */
-    struct unfm_nodeinfo unfm_ptr;  /* Handle on an unformatted node
+    unp_t unfm_ptr;  /* Handle on an unformatted node
                                      that will be inserted in the
                                      tree. */

@@ -59,8 +59,7 @@

    p_le_ih = PATH_PITEM_HEAD (path);

-    unfm_ptr.unfm_nodenum = cpu_to_le32 (unbh->b_blocknr);
-    unfm_ptr.unfm_freespace = 0; // ???
+    unfm_ptr = cpu_to_le32 (unbh->b_blocknr);

    if ( is_statdata_le_ih (p_le_ih) )  {
       /* Insert new indirect item. */