vserver 1.9.5.x5
[linux-2.6.git] / fs / reiserfs / stree.c
index 0d4f5f5..73ec521 100644 (file)
  *  This file contains functions dealing with S+tree
  *
  * B_IS_IN_TREE
- * copy_short_key
  * copy_item_head
  * comp_short_keys
  * comp_keys
- * comp_cpu_keys
  * comp_short_le_keys
- * comp_short_cpu_keys
- * cpu_key2cpu_key
  * le_key2cpu_key
  * comp_le_keys
  * bin_search
@@ -60,6 +56,7 @@
 #include <linux/reiserfs_fs.h>
 #include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
+#include <linux/quotaops.h>
 
 /* Does the buffer contain a disk block which is in the tree. */
 inline int B_IS_IN_TREE (const struct buffer_head * p_s_bh)
@@ -71,14 +68,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);
-}
-
 //
 // to gets item head in le form
 //
@@ -95,7 +84,7 @@ inline void copy_item_head(struct item_head * p_v_to,
    Returns: -1 if key1 < key2 
    0 if key1 == key2
    1 if key1 > key2 */
-inline int  comp_short_keys (const struct key * le_key, 
+inline int  comp_short_keys (const struct reiserfs_key * le_key,
                             const struct cpu_key * cpu_key)
 {
   __u32 * p_s_le_u32, * p_s_cpu_u32;
@@ -119,7 +108,7 @@ inline int  comp_short_keys (const struct key * le_key,
    Compare keys using all 4 key fields.
    Returns: -1 if key1 < key2 0
    if key1 = key2 1 if key1 > key2 */
-inline int  comp_keys (const struct key * le_key, const struct cpu_key * cpu_key)
+static inline int  comp_keys (const struct reiserfs_key * le_key, const struct cpu_key * cpu_key)
 {
   int retval;
 
@@ -145,38 +134,7 @@ inline int  comp_keys (const struct key * le_key, const struct cpu_key * cpu_key
 }
 
 
-//
-// FIXME: not used yet
-//
-inline int comp_cpu_keys (const struct cpu_key * key1, 
-                         const struct cpu_key * key2)
-{
-    if (key1->on_disk_key.k_dir_id < key2->on_disk_key.k_dir_id)
-       return -1;
-    if (key1->on_disk_key.k_dir_id > key2->on_disk_key.k_dir_id)
-       return 1;
-
-    if (key1->on_disk_key.k_objectid < key2->on_disk_key.k_objectid)
-       return -1;
-    if (key1->on_disk_key.k_objectid > key2->on_disk_key.k_objectid)
-       return 1;
-
-    if (cpu_key_k_offset (key1) < cpu_key_k_offset (key2))
-       return -1;
-    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",
-                     key1, key2);
-
-    if (cpu_key_k_type (key1) < cpu_key_k_type (key2))
-       return -1;
-    if (cpu_key_k_type (key1) > cpu_key_k_type (key2))
-       return 1;
-    return 0;
-}
-
-inline int comp_short_le_keys (const struct key * key1, const struct key * key2)
+inline int comp_short_le_keys (const struct reiserfs_key * key1, const struct reiserfs_key * key2)
 {
   __u32 * p_s_1_u32, * p_s_2_u32;
   int n_key_length = REISERFS_SHORT_KEY_LEN;
@@ -192,33 +150,7 @@ inline int comp_short_le_keys (const struct key * key1, const struct key * key2)
   return 0;
 }
 
-inline int comp_short_cpu_keys (const struct cpu_key * key1, 
-                               const struct cpu_key * key2)
-{
-  __u32 * p_s_1_u32, * p_s_2_u32;
-  int n_key_length = REISERFS_SHORT_KEY_LEN;
-
-  p_s_1_u32 = (__u32 *)key1;
-  p_s_2_u32 = (__u32 *)key2;
-
-  for( ; n_key_length--; ++p_s_1_u32, ++p_s_2_u32 ) {
-    if ( *p_s_1_u32 < *p_s_2_u32 )
-      return -1;
-    if ( *p_s_1_u32 > *p_s_2_u32 )
-      return 1;
-  }
-  return 0;
-}
-
-
-
-inline void cpu_key2cpu_key (struct cpu_key * to, const struct cpu_key * from)
-{
-    memcpy (to, from, sizeof (struct cpu_key));
-}
-
-
-inline void le_key2cpu_key (struct cpu_key * to, const struct key * from)
+inline void le_key2cpu_key (struct cpu_key * to, const struct reiserfs_key * from)
 {
     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);
@@ -238,9 +170,9 @@ inline void le_key2cpu_key (struct cpu_key * to, const struct key * from)
 
 // this does not say which one is bigger, it only returns 1 if keys
 // are not equal, 0 otherwise
-inline int comp_le_keys (const struct key * k1, const struct key * k2)
+inline int comp_le_keys (const struct reiserfs_key * k1, const struct reiserfs_key * k2)
 {
-    return memcmp (k1, k2, sizeof (struct key));
+    return memcmp (k1, k2, sizeof (struct reiserfs_key));
 }
 
 /**************************************************************************
@@ -257,7 +189,7 @@ inline int comp_le_keys (const struct key * k1, const struct key * k2)
  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. */
-inline int bin_search (
+static inline  int bin_search (
               const void * p_v_key, /* Key to search for.                   */
              const void * p_v_base,/* First item in the array.             */
              int       p_n_num,    /* Number of items in the array.        */
@@ -274,7 +206,7 @@ inline      int bin_search (
     int   n_rbound, n_lbound, n_j;
 
    for ( n_j = ((n_rbound = p_n_num - 1) + (n_lbound = 0))/2; n_lbound <= n_rbound; n_j = (n_rbound + n_lbound)/2 )
-     switch( COMP_KEYS((struct key *)((char * )p_v_base + n_j * p_n_width), (struct cpu_key *)p_v_key) )  {
+     switch( comp_keys((struct reiserfs_key *)((char * )p_v_base + n_j * p_n_width), (struct cpu_key *)p_v_key) )  {
      case -1: n_lbound = n_j + 1; continue;
      case  1: n_rbound = n_j - 1; continue;
      case  0: *p_n_pos = n_j;     return ITEM_FOUND; /* Key found in the array.  */
@@ -293,17 +225,17 @@ extern struct tree_balance * cur_tb;
 
 
 /* Minimal possible key. It is never in the tree. */
-const struct key  MIN_KEY = {0, 0, {{0, 0},}};
+const struct reiserfs_key  MIN_KEY = {0, 0, {{0, 0},}};
 
 /* Maximal possible key. It is never in the tree. */
-const struct key  MAX_KEY = {0xffffffff, 0xffffffff, {{0xffffffff, 0xffffffff},}};
+const struct reiserfs_key  MAX_KEY = {0xffffffff, 0xffffffff, {{0xffffffff, 0xffffffff},}};
 
 
 /* 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. */
-inline const struct  key * get_lkey  (
+static inline  const struct  reiserfs_key * get_lkey  (
                        const struct path         * p_s_chk_path,
                         const struct super_block  * p_s_sb
                       ) {
@@ -342,7 +274,7 @@ inline      const struct  key * get_lkey  (
 
 
 /* Get delimiting key of the buffer at the path and its right neighbor. */
-inline const struct  key * get_rkey  (
+inline const struct  reiserfs_key * get_rkey  (
                        const struct path         * p_s_chk_path,
                         const struct super_block  * p_s_sb
                       ) {
@@ -398,11 +330,11 @@ static  inline  int key_in_buffer (
   RFALSE( !PATH_PLAST_BUFFER(p_s_chk_path)->b_bdev,
          "PAP-5060: device must not be NODEV");
 
-  if ( COMP_KEYS(get_lkey(p_s_chk_path, p_s_sb), p_s_key) == 1 )
+  if ( comp_keys(get_lkey(p_s_chk_path, p_s_sb), p_s_key) == 1 )
     /* left delimiting key is bigger, that the key we look for */
     return 0;
-  //  if ( COMP_KEYS(p_s_key, get_rkey(p_s_chk_path, p_s_sb)) != -1 )
-  if ( COMP_KEYS(get_rkey(p_s_chk_path, p_s_sb), p_s_key) != 1 )
+  //  if ( comp_keys(p_s_key, get_rkey(p_s_chk_path, p_s_sb)) != -1 )
+  if ( comp_keys(get_rkey(p_s_chk_path, p_s_sb), p_s_key) != 1 )
     /* p_s_key must be less than right delimitiing key */
     return 0;
   return 1;
@@ -499,21 +431,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 +457,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 +491,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 +518,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 +530,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;
-  
-    if (blocknr == 0)
-       return;
-
-    bh = sb_getblk (s, blocknr);
+    int i,j;
   
-    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 +594,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 +621,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 +631,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 --;
@@ -735,7 +679,7 @@ int search_by_key (struct super_block * p_s_sb,
         /* only check that the key is in the buffer if p_s_key is not
            equal to the MAX_KEY. Latter case is only possible in
            "finish_unfinished()" processing during mount. */
-        RFALSE( COMP_KEYS( &MAX_KEY, p_s_key ) && 
+        RFALSE( comp_keys( &MAX_KEY, p_s_key ) &&
                 ! key_in_buffer(p_s_search_path, p_s_key, p_s_sb),
                "PAP-5130: key is not in the buffer");
 #ifdef CONFIG_REISERFS_CHECK
@@ -748,8 +692,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 +730,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 reiserfs_key *le_key;
+
+           if (p_s_search_path->reada & PATH_READA_BACK)
+               limit = 0;
+           while(reada_count < SEARCH_BY_KEY_READA) {
+               if (pos == limit)
+                   break;
+               reada_blocks[reada_count++] = B_N_CHILD_NUM(p_s_bh, pos);
+               if (p_s_search_path->reada & PATH_READA_BACK)
+                   pos--;
+               else
+                   pos++;
+
+               /*
+                * check to make sure we're in the same object
+                */
+               le_key = B_N_PDELIM_KEY(p_s_bh, pos);
+               if (le32_to_cpu(le_key->k_objectid) !=
+                   p_s_key->on_disk_key.k_objectid)
+               {
+                   break;
+               }
+           }
+        }
     }
 }
 
@@ -1001,6 +970,8 @@ static char  prepare_for_delete_or_cut(
     struct item_head    * p_le_ih = PATH_PITEM_HEAD(p_s_path);
     struct buffer_head  * p_s_bh = PATH_PLAST_BUFFER(p_s_path);
 
+    BUG_ON (!th->t_trans_id);
+
     /* Stat_data item. */
     if ( is_statdata_le_ih (p_le_ih) ) {
 
@@ -1125,8 +1096,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,9 +1125,8 @@ static char  prepare_for_delete_or_cut(
     }
 }
 
-
-/* Calculate bytes number which will be deleted or cutted in the balance. */
-int calc_deleted_bytes_number(
+/* Calculate number of bytes which will be deleted or cut during balance */
+static int calc_deleted_bytes_number(
     struct  tree_balance  * p_s_tb,
     char                    c_mode
     ) {
@@ -1167,14 +1136,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)*
@@ -1189,6 +1158,9 @@ static void init_tb_struct(
     struct path         * p_s_path,
     int                   n_size
     ) {
+
+    BUG_ON (!th->t_trans_id);
+
     memset (p_s_tb,'\0',sizeof(struct tree_balance));
     p_s_tb->transaction_handle = th ;
     p_s_tb->tb_sb = p_s_sb;
@@ -1208,17 +1180,46 @@ void padd_item (char * item, int total_length, int length)
        item [--i] = 0;
 }
 
+#ifdef REISERQUOTA_DEBUG
+char key2type(struct reiserfs_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;
@@ -1228,6 +1229,8 @@ int reiserfs_delete_item (struct reiserfs_transaction_handle *th,
     int                        n_iter = 0;
 #endif
 
+    BUG_ON (!th->t_trans_id);
+
     init_tb_struct(th, &s_del_balance, p_s_sb, p_s_path, 0/*size is unknown*/);
 
     while ( 1 ) {
@@ -1244,7 +1247,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 +1258,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 +1271,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 +1318,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, REISERFS_DEBUG_CODE, "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 +1350,28 @@ 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 key * key)
+                                struct inode *inode,
+                                struct reiserfs_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;
+
+    BUG_ON (!th->t_trans_id);
     
     le_key2cpu_key (&cpu_key, key);
     
     while (1) {
        retval = search_item (th->t_super, &cpu_key, &path);
        if (retval == IO_ERROR) {
-           reiserfs_warning ("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 +1379,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 +1387,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, REISERFS_DEBUG_CODE, "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;
     }
@@ -1381,12 +1417,16 @@ void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th,
 }
 
 
-void reiserfs_delete_object (struct reiserfs_transaction_handle *th, struct inode * inode)
+int reiserfs_delete_object (struct reiserfs_transaction_handle *th, struct inode * inode)
 {
+    int err;
     inode->i_size = 0;
+    BUG_ON (!th->t_trans_id);
 
     /* for directory this deletes item containing "." and ".." */
-    reiserfs_do_truncate (th, inode, NULL, 0/*no timestamp updates*/);
+    err = reiserfs_do_truncate (th, inode, NULL, 0/*no timestamp updates*/);
+    if (err)
+        return err;
     
 #if defined( USE_INODE_GENERATION_COUNTER )
     if( !old_format_only ( th -> t_super ) )
@@ -1399,9 +1439,46 @@ 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));
+
+    return err;
 }
 
+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,
@@ -1414,6 +1491,7 @@ static int maybe_indirect_to_direct (struct reiserfs_transaction_handle *th,
     struct super_block * p_s_sb = p_s_inode->i_sb;
     int n_block_size = p_s_sb->s_blocksize;
     int cut_bytes;
+    BUG_ON (!th->t_trans_id);
 
     if (n_new_file_size != p_s_inode->i_size)
        BUG ();
@@ -1446,6 +1524,7 @@ static void indirect_to_direct_roll_back (struct reiserfs_transaction_handle *th
     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;
@@ -1459,14 +1538,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 +1565,17 @@ 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;
+
+    BUG_ON (!th->t_trans_id);
     
     init_tb_struct(th, &s_cut_balance, p_s_inode->i_sb, p_s_path, n_cut_size);
 
@@ -1532,6 +1615,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 +1630,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 +1640,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 +1653,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 +1663,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 +1713,30 @@ 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, REISERFS_DEBUG_CODE, "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)
 {
+    BUG_ON (!th->t_trans_id);
     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);    
 }
@@ -1652,7 +1746,7 @@ static void truncate_directory (struct reiserfs_transaction_handle *th, struct i
 
 /* Truncate file to the new size. Note, this must be called with a transaction
    already started */
-void reiserfs_do_truncate (struct reiserfs_transaction_handle *th, 
+int reiserfs_do_truncate (struct reiserfs_transaction_handle *th,
                           struct  inode * p_s_inode, /* ->i_size contains new
                                                          size */
                           struct page *page, /* up to date for last block */
@@ -1668,14 +1762,16 @@ void reiserfs_do_truncate (struct reiserfs_transaction_handle *th,
        n_new_file_size;/* New file size. */
     int                   n_deleted;      /* Number of deleted or truncated bytes. */
     int retval;
+    int err = 0;
 
+    BUG_ON (!th->t_trans_id);
     if ( ! (S_ISREG(p_s_inode->i_mode) || S_ISDIR(p_s_inode->i_mode) || S_ISLNK(p_s_inode->i_mode)) )
-       return;
+       return 0;
 
     if (S_ISDIR(p_s_inode->i_mode)) {
        // deletion of directory - no need to update timestamps
        truncate_directory (th, p_s_inode);
-       return;
+       return 0;
     }
 
     /* Get new file size. */
@@ -1686,15 +1782,17 @@ 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);
-       return;
+       reiserfs_warning (p_s_inode->i_sb, "vs-5657: reiserfs_do_truncate: "
+                         "i/o failure occurred trying to truncate %K", &s_item_key);
+        err = -EIO;
+        goto out;
     }
     if (retval == POSITION_FOUND || retval == FILE_NOT_FOUND) {
-       pathrelse (&s_search_path);
-       reiserfs_warning ("PAP-5660: reiserfs_do_truncate: "
-                         "wrong result %d of search for %K\n", retval, &s_item_key);
-       return;
+       reiserfs_warning (p_s_inode->i_sb, "PAP-5660: reiserfs_do_truncate: "
+                         "wrong result %d of search for %K", retval, &s_item_key);
+
+        err = -EIO;
+        goto out;
     }
 
     s_search_path.pos_in_item --;
@@ -1712,6 +1810,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,9 +1828,9 @@ 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;
+           return 0;
        }
 
        RFALSE( n_deleted > n_file_size,
@@ -1752,29 +1856,36 @@ void reiserfs_do_truncate (struct reiserfs_transaction_handle *th,
          decrement_counters_in_path(&s_search_path) ;
 
          if (update_timestamps) {
-             p_s_inode->i_mtime = p_s_inode->i_ctime = CURRENT_TIME;
+             p_s_inode->i_mtime = p_s_inode->i_ctime = CURRENT_TIME_SEC;
          } 
          reiserfs_update_sd(th, p_s_inode) ;
 
-         journal_end(th, p_s_inode->i_sb, orig_len_alloc) ;
-         journal_begin(th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 6) ;
+         err = journal_end(th, p_s_inode->i_sb, orig_len_alloc) ;
+         if (err)
+           goto out;
+         err = journal_begin (th, p_s_inode->i_sb,
+                               JOURNAL_PER_BALANCE_CNT * 6);
+         if (err)
+           goto out;
          reiserfs_update_inode_transaction(p_s_inode) ;
        }
     } while ( n_file_size > ROUND_UP (n_new_file_size) &&
              search_for_position_by_key(p_s_inode->i_sb, &s_item_key, &s_search_path) == POSITION_FOUND )  ;
 
     RFALSE( n_file_size > ROUND_UP (n_new_file_size),
-           "PAP-5680: truncate did not finish: new_file_size %Ld, current %Ld, oid %d\n",
+           "PAP-5680: truncate did not finish: new_file_size %Ld, current %Ld, oid %d",
            n_new_file_size, n_file_size, s_item_key.on_disk_key.k_objectid);
 
 update_and_out:
     if (update_timestamps) {
        // this is truncate, not file closing
-       p_s_inode->i_mtime = p_s_inode->i_ctime = CURRENT_TIME;
+           p_s_inode->i_mtime = p_s_inode->i_ctime = CURRENT_TIME_SEC;
     }
     reiserfs_update_sd (th, p_s_inode);
 
+out:
     pathrelse(&s_search_path) ;
+    return err;
 }
 
 
@@ -1789,7 +1900,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 +1908,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 +1920,39 @@ 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;
+
+    BUG_ON (!th->t_trans_id);
 
+    fs_gen = get_generation(inode->i_sb) ;
+
+#ifdef REISERQUOTA_DEBUG
+    reiserfs_debug (inode->i_sb, REISERFS_DEBUG_CODE, "reiserquota paste_into_item(): allocating %u id=%u type=%c", n_pasted_size, inode->i_uid, key2type(&(p_s_key->on_disk_key)));
+#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 +1961,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 +1981,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, REISERFS_DEBUG_CODE, "reiserquota paste_into_item(): freeing %u id=%u type=%c", n_pasted_size, inode->i_uid, key2type(&(p_s_key->on_disk_key)));
+#endif
+    DQUOT_FREE_SPACE_NODIRTY(inode, n_pasted_size);
     return retval ;
 }
 
@@ -1858,23 +1994,47 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th,
                         struct path         *  p_s_path,         /* Path to the inserteded item.         */
                         const struct cpu_key      * key,
                         struct item_head    *  p_s_ih,           /* Pointer to the item header to insert.*/
+                        struct inode        * inode,
                         const char          *  p_c_body)         /* Pointer to the bytes to insert.      */
 {
     struct tree_balance s_ins_balance;
     int                 retval;
+    int fs_gen = 0 ;
+    int quota_bytes = 0 ;
 
+    BUG_ON (!th->t_trans_id);
+
+    if (inode) {      /* Do we count quotas for item? */
+       fs_gen = get_generation(inode->i_sb);
+       quota_bytes = ih_item_len(p_s_ih);
+
+       /* hack so the quota code doesn't have to guess if the file has
+        ** a tail, links are always tails, so there's no guessing needed
+        */
+       if (!S_ISLNK (inode->i_mode) && is_direct_le_ih(p_s_ih)) {
+           quota_bytes = inode->i_sb->s_blocksize + UNFM_P_SIZE ;
+       }
+#ifdef REISERQUOTA_DEBUG
+       reiserfs_debug (inode->i_sb, REISERFS_DEBUG_CODE, "reiserquota insert_item(): allocating %u id=%u type=%c", quota_bytes, inode->i_uid, head2type(p_s_ih));
+#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 +2043,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 +2060,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, REISERFS_DEBUG_CODE, "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; 
 }