VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / fs / reiserfs / stree.c
index 0d4f5f5..497b2f3 100644 (file)
@@ -60,6 +60,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,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; 
 }