From: Chris Mason <mason@suse.com>

ReiserFS support for quotas.  Originally from Jan Kara


---

 25-akpm/fs/reiserfs/bitmap.c          |   70 ++++++++++---
 25-akpm/fs/reiserfs/do_balan.c        |    6 -
 25-akpm/fs/reiserfs/file.c            |   12 +-
 25-akpm/fs/reiserfs/fix_node.c        |    7 -
 25-akpm/fs/reiserfs/inode.c           |  152 ++++++++++++++++++++--------
 25-akpm/fs/reiserfs/namei.c           |   14 +-
 25-akpm/fs/reiserfs/stree.c           |  179 +++++++++++++++++++++++++++-------
 25-akpm/fs/reiserfs/super.c           |   11 +-
 25-akpm/fs/reiserfs/tail_conversion.c |   10 +
 25-akpm/include/linux/reiserfs_fs.h   |   24 +++-
 10 files changed, 364 insertions(+), 121 deletions(-)

diff -puN fs/reiserfs/bitmap.c~reiserfs-quota fs/reiserfs/bitmap.c
--- 25/fs/reiserfs/bitmap.c~reiserfs-quota	Fri Apr 23 14:36:54 2004
+++ 25-akpm/fs/reiserfs/bitmap.c	Fri Apr 23 14:36:54 2004
@@ -12,6 +12,7 @@
 #include <linux/pagemap.h>
 #include <linux/reiserfs_fs_sb.h>
 #include <linux/reiserfs_fs_i.h>
+#include <linux/quotaops.h>
 
 #define PREALLOCATION_SIZE 9
 
@@ -281,7 +282,8 @@ static int scan_bitmap (struct reiserfs_
 }
 
 static void _reiserfs_free_block (struct reiserfs_transaction_handle *th,
-				  b_blocknr_t block)
+				  struct inode *inode, b_blocknr_t block,
+				  int for_unformatted)
 {
     struct super_block * s = th->t_super;
     struct reiserfs_super_block * rs;
@@ -323,11 +325,13 @@ static void _reiserfs_free_block (struct
     set_sb_free_blocks( rs, sb_free_blocks(rs) + 1 );
 
     journal_mark_dirty (th, s, sbh);
-  s->s_dirt = 1;
+    if (for_unformatted)
+        DQUOT_FREE_BLOCK_NODIRTY(inode, 1);
 }
 
 void reiserfs_free_block (struct reiserfs_transaction_handle *th, 
-                          b_blocknr_t block)
+			  struct inode *inode, b_blocknr_t block,
+			  int for_unformatted)
 {
     struct super_block * s = th->t_super;
 
@@ -335,42 +339,46 @@ void reiserfs_free_block (struct reiserf
     RFALSE(is_reusable (s, block, 1) == 0, "vs-4071: can not free such block");
     /* mark it before we clear it, just in case */
     journal_mark_freed(th, s, block) ;
-    _reiserfs_free_block(th, block) ;
+    _reiserfs_free_block(th, inode, block, for_unformatted) ;
 }
 
 /* preallocated blocks don't need to be run through journal_mark_freed */
 void reiserfs_free_prealloc_block (struct reiserfs_transaction_handle *th, 
-                          b_blocknr_t block) {
+			  struct inode *inode, b_blocknr_t block) {
     RFALSE(!th->t_super, "vs-4060: trying to free block on nonexistent device");
     RFALSE(is_reusable (th->t_super, block, 1) == 0, "vs-4070: can not free such block");
-    _reiserfs_free_block(th, block) ;
+    _reiserfs_free_block(th, inode, block, 1) ;
 }
 
 static void __discard_prealloc (struct reiserfs_transaction_handle * th,
 				struct reiserfs_inode_info *ei)
 {
     unsigned long save = ei->i_prealloc_block ;
+    int dirty = 0;
+    struct inode *inode = &ei->vfs_inode;
 #ifdef CONFIG_REISERFS_CHECK
     if (ei->i_prealloc_count < 0)
 	reiserfs_warning("zam-4001:%s: inode has negative prealloc blocks count.\n", __FUNCTION__ );
 #endif
     while (ei->i_prealloc_count > 0) {
-	reiserfs_free_prealloc_block(th,ei->i_prealloc_block);
+	reiserfs_free_prealloc_block(th, inode, ei->i_prealloc_block);
 	ei->i_prealloc_block++;
 	ei->i_prealloc_count --;
+	dirty = 1;
     }
+    if (dirty)
+    	reiserfs_update_sd(th, inode);
     ei->i_prealloc_block = save;
     list_del_init(&(ei->i_prealloc_list));
 }
 
 /* FIXME: It should be inline function */
 void reiserfs_discard_prealloc (struct reiserfs_transaction_handle *th, 
-				struct inode * inode)
+				struct inode *inode)
 {
     struct reiserfs_inode_info *ei = REISERFS_I(inode);
-    if (ei->i_prealloc_count) {
+    if (ei->i_prealloc_count)
 	__discard_prealloc(th, ei);
-    }
 }
 
 void reiserfs_discard_all_prealloc (struct reiserfs_transaction_handle *th)
@@ -772,6 +780,24 @@ static inline int blocknrs_and_prealloc_
     int nr_allocated = 0;
 
     determine_prealloc_size(hint);
+    if (!hint->formatted_node) {
+        int quota_ret;
+#ifdef REISERQUOTA_DEBUG
+	printk(KERN_DEBUG "reiserquota: allocating %d blocks id=%u\n", amount_needed, hint->inode->i_uid);
+#endif
+	quota_ret = DQUOT_ALLOC_BLOCK_NODIRTY(hint->inode, amount_needed);
+	if (quota_ret)    /* Quota exceeded? */
+	    return QUOTA_EXCEEDED;
+	if (hint->preallocate && hint->prealloc_size ) {
+#ifdef REISERQUOTA_DEBUG
+	    printk(KERN_DEBUG "reiserquota: allocating (prealloc) %d blocks id=%u\n", hint->prealloc_size, hint->inode->i_uid);
+#endif
+	    quota_ret = DQUOT_PREALLOC_BLOCK_NODIRTY(hint->inode, hint->prealloc_size);
+	    if (quota_ret)
+		hint->preallocate=hint->prealloc_size=0;
+	}
+    }
+
     while((nr_allocated
 	  += allocate_without_wrapping_disk(hint, new_blocknrs + nr_allocated, start, finish,
 					  amount_needed - nr_allocated, hint->prealloc_size))
@@ -779,8 +805,14 @@ static inline int blocknrs_and_prealloc_
 
 	/* not all blocks were successfully allocated yet*/
 	if (second_pass) {	/* it was a second pass; we must free all blocks */
+	    if (!hint->formatted_node) {
+#ifdef REISERQUOTA_DEBUG
+		printk(KERN_DEBUG "reiserquota: freeing (nospace) %d blocks id=%u\n", amount_needed + hint->prealloc_size - nr_allocated, hint->inode->i_uid);
+#endif
+		DQUOT_FREE_BLOCK_NODIRTY(hint->inode, amount_needed + hint->prealloc_size - nr_allocated);     /* Free not allocated blocks */
+	    }
 	    while (nr_allocated --)
-		reiserfs_free_block(hint->th, new_blocknrs[nr_allocated]);
+		reiserfs_free_block(hint->th, hint->inode, new_blocknrs[nr_allocated], !hint->formatted_node);
 
 	    return NO_DISK_SPACE;
 	} else {		/* refine search parameters for next pass */
@@ -789,7 +821,19 @@ static inline int blocknrs_and_prealloc_
 	    start = 0;
 	    continue;
 	}
-      }
+    }
+    if ( !hint->formatted_node &&
+         amount_needed + hint->prealloc_size >
+	 nr_allocated + REISERFS_I(hint->inode)->i_prealloc_count) {
+    /* Some of preallocation blocks were not allocated */
+#ifdef REISERQUOTA_DEBUG
+	printk(KERN_DEBUG "reiserquota: freeing (failed prealloc) %d blocks id=%u\n", amount_needed + hint->prealloc_size - nr_allocated - INODE_INFO(hint->inode)->i_prealloc_count, hint->inode->i_uid);
+#endif
+	DQUOT_FREE_BLOCK_NODIRTY(hint->inode, amount_needed +
+	                         hint->prealloc_size - nr_allocated -
+				 REISERFS_I(hint->inode)->i_prealloc_count);
+    }
+
     return CARRY_ON;
 }
 
@@ -858,7 +902,7 @@ int reiserfs_allocate_blocknrs(reiserfs_
 
     if (ret != CARRY_ON) {
 	while (amount_needed ++ < initial_amount_needed) {
-	    reiserfs_free_block(hint->th, *(--new_blocknrs));
+	    reiserfs_free_block(hint->th, hint->inode, *(--new_blocknrs), 1);
 	}
     }
     return ret;
diff -puN fs/reiserfs/do_balan.c~reiserfs-quota fs/reiserfs/do_balan.c
--- 25/fs/reiserfs/do_balan.c~reiserfs-quota	Fri Apr 23 14:36:54 2004
+++ 25-akpm/fs/reiserfs/do_balan.c	Fri Apr 23 14:36:54 2004
@@ -1234,7 +1234,7 @@ static void free_thrown(struct tree_bala
 	    if (buffer_dirty (tb->thrown[i]))
 	      printk ("free_thrown deals with dirty buffer %d\n", blocknr);
 	    brelse(tb->thrown[i]) ; /* incremented in store_thrown */
-	    reiserfs_free_block (tb->transaction_handle, blocknr);
+	    reiserfs_free_block (tb->transaction_handle, NULL, blocknr, 0);
 	}
     }
 }
@@ -1247,10 +1247,6 @@ void reiserfs_invalidate_buffer (struct 
     set_blkh_nr_item( blkh, 0 );
     
     clear_buffer_dirty(bh);
-    /* reiserfs_free_block is no longer schedule safe 
-    reiserfs_free_block (tb->transaction_handle, tb->tb_sb, bh->b_blocknr);
-    */
-
     store_thrown (tb, bh);
 }
 
diff -puN fs/reiserfs/file.c~reiserfs-quota fs/reiserfs/file.c
--- 25/fs/reiserfs/file.c~reiserfs-quota	Fri Apr 23 14:36:54 2004
+++ 25-akpm/fs/reiserfs/file.c	Fri Apr 23 14:36:54 2004
@@ -13,6 +13,7 @@
 #include <linux/writeback.h>
 #include <linux/blkdev.h>
 #include <linux/buffer_head.h>
+#include <linux/quotaops.h>
 
 /*
 ** We pack the tails of files on file close, not at the time they are written.
@@ -274,7 +275,7 @@ int reiserfs_allocate_blocks_for_region(
 		    /* Ok, there is existing indirect item already. Need to append it */
 		    /* Calculate position past inserted item */
 		    make_cpu_key( &key, inode, le_key_k_offset( get_inode_item_key_version(inode), &(ih->ih_key)) + op_bytes_number(ih, inode->i_sb->s_blocksize), TYPE_INDIRECT, 3);
-		    res = reiserfs_paste_into_item( th, &path, &key, (char *)zeros, UNFM_P_SIZE*to_paste);
+		    res = reiserfs_paste_into_item( th, &path, &key, inode, (char *)zeros, UNFM_P_SIZE*to_paste);
 		    if ( res ) {
 			kfree(zeros);
 			goto error_exit_free_blocks;
@@ -304,7 +305,7 @@ int reiserfs_allocate_blocks_for_region(
 		        kfree(zeros);
 			goto error_exit_free_blocks;
 		    }
-		    res = reiserfs_insert_item( th, &path, &key, &ins_ih, (char *)zeros);
+		    res = reiserfs_insert_item( th, &path, &key, &ins_ih, inode, (char *)zeros);
 		} else {
 		    reiserfs_panic(inode->i_sb, "green-9011: Unexpected key type %K\n", &key);
 		}
@@ -421,7 +422,7 @@ retry:
 	    // position. We do not need to recalculate path as it should
 	    // already point to correct place.
 	    make_cpu_key( &key, inode, le_key_k_offset( get_inode_item_key_version(inode), &(ih->ih_key)) + op_bytes_number(ih, inode->i_sb->s_blocksize), TYPE_INDIRECT, 3);
-	    res = reiserfs_paste_into_item( th, &path, &key, (char *)(allocated_blocks+curr_block), UNFM_P_SIZE*(blocks_to_allocate-curr_block));
+	    res = reiserfs_paste_into_item( th, &path, &key, inode, (char *)(allocated_blocks+curr_block), UNFM_P_SIZE*(blocks_to_allocate-curr_block));
 	    if ( res ) {
 		goto error_exit_free_blocks;
 	    }
@@ -452,7 +453,7 @@ retry:
 		goto error_exit_free_blocks;
 	    }
 	    /* Insert item into the tree with the data as its body */
-	    res = reiserfs_insert_item( th, &path, &key, &ins_ih, (char *)(allocated_blocks+curr_block));
+	    res = reiserfs_insert_item( th, &path, &key, &ins_ih, inode, (char *)(allocated_blocks+curr_block));
 	} else {
 	    reiserfs_panic(inode->i_sb, "green-9010: unexpected item type for key %K\n",&key);
 	}
@@ -462,7 +463,6 @@ retry:
     // unless we return an error, they are also responsible for logging
     // the inode.
     //
-    inode->i_blocks += blocks_to_allocate << (inode->i_blkbits - 9);
     pathrelse(&path);
     reiserfs_write_unlock(inode->i_sb);
 
@@ -508,7 +508,7 @@ error_exit_free_blocks:
     pathrelse(&path);
     // free blocks
     for( i = 0; i < blocks_to_allocate; i++ )
-	reiserfs_free_block(th, le32_to_cpu(allocated_blocks[i]));
+	reiserfs_free_block(th, inode, le32_to_cpu(allocated_blocks[i]), 1);
 
 error_exit:
     reiserfs_update_sd(th, inode); // update any changes we made to blk count
diff -puN fs/reiserfs/fix_node.c~reiserfs-quota fs/reiserfs/fix_node.c
--- 25/fs/reiserfs/fix_node.c~reiserfs-quota	Fri Apr 23 14:36:54 2004
+++ 25-akpm/fs/reiserfs/fix_node.c	Fri Apr 23 14:36:54 2004
@@ -795,8 +795,9 @@ static int  get_empty_nodes(
   else /* If we have enough already then there is nothing to do. */
     return CARRY_ON;
 
-  if ( reiserfs_new_form_blocknrs (p_s_tb, a_n_blocknrs,
-                                   n_amount_needed) == NO_DISK_SPACE )
+  /* No need to check quota - is not allocated for blocks used for formatted nodes */
+  if (reiserfs_new_form_blocknrs (p_s_tb, a_n_blocknrs,
+                                   n_amount_needed) == NO_DISK_SPACE)
     return NO_DISK_SPACE;
 
   /* for each blocknumber we just got, get a buffer and stick it on FEB */
@@ -2492,7 +2493,7 @@ void unfix_nodes (struct tree_balance * 
 	    /* de-allocated block which was not used by balancing and
                bforget about buffer for it */
 	    brelse (tb->FEB[i]);
-	    reiserfs_free_block (tb->transaction_handle, blocknr);
+	    reiserfs_free_block (tb->transaction_handle, NULL, blocknr, 0);
 	}
 	if (tb->used[i]) {
 	    /* release used as new nodes including a new root */
diff -puN fs/reiserfs/inode.c~reiserfs-quota fs/reiserfs/inode.c
--- 25/fs/reiserfs/inode.c~reiserfs-quota	Fri Apr 23 14:36:54 2004
+++ 25-akpm/fs/reiserfs/inode.c	Fri Apr 23 14:36:54 2004
@@ -4,6 +4,7 @@
 
 #include <linux/config.h>
 #include <linux/time.h>
+#include <linux/fs.h>
 #include <linux/reiserfs_fs.h>
 #include <linux/reiserfs_acl.h>
 #include <linux/reiserfs_xattr.h>
@@ -39,6 +40,7 @@ void reiserfs_delete_inode (struct inode
   
     reiserfs_write_lock(inode->i_sb);
 
+    DQUOT_FREE_INODE(inode);
     /* The = 0 happens when we abort creating a new inode for some reason like lack of space.. */
     if (!(inode->i_state & I_NEW) && INODE_PKEY(inode)->k_objectid != 0) { /* also handles bad_inode case */
 	down (&inode->i_sem); 
@@ -647,7 +649,7 @@ start_trans:
 
 	repeat = _allocate_block(th, block, inode, &allocated_block_nr, &path, create);
 
-	if (repeat == NO_DISK_SPACE) {
+	if (repeat == NO_DISK_SPACE || repeat == QUOTA_EXCEEDED) {
 	    /* restart the transaction to give the journal a chance to free
 	    ** some blocks.  releases the path, so we have to go back to
 	    ** research if we succeed on the second try
@@ -656,10 +658,13 @@ start_trans:
 	    restart_transaction(th, inode, &path) ;
 	    repeat = _allocate_block(th, block, inode, &allocated_block_nr, NULL, create);
 
-	    if (repeat != NO_DISK_SPACE) {
+	    if (repeat != NO_DISK_SPACE && repeat != QUOTA_EXCEEDED) {
 		goto research ;
 	    }
-	    retval = -ENOSPC;
+	    if (repeat == QUOTA_EXCEEDED)
+		retval = -EDQUOT;
+	    else
+		retval = -ENOSPC;
 	    goto failure;
 	}
 
@@ -687,7 +692,6 @@ start_trans:
 	    put_block_num(item, pos_in_item, allocated_block_nr) ;
             unfm_ptr = allocated_block_nr;
 	    journal_mark_dirty (th, inode->i_sb, bh);
-	    inode->i_blocks += (inode->i_sb->s_blocksize / 512) ;
 	    reiserfs_update_sd(th, inode) ;
 	}
 	set_block_dev_mapped(bh_result, unfm_ptr, inode);
@@ -734,13 +738,11 @@ start_trans:
 	    set_cpu_key_k_offset (&tmp_key, 1);
 	    PATH_LAST_POSITION(&path) ++;
 
-	    retval = reiserfs_insert_item (th, &path, &tmp_key, &tmp_ih, (char *)&unp);
+	    retval = reiserfs_insert_item (th, &path, &tmp_key, &tmp_ih, inode, (char *)&unp);
 	    if (retval) {
-		reiserfs_free_block (th, allocated_block_nr);
-		goto failure; // retval == -ENOSPC or -EIO or -EEXIST
+		reiserfs_free_block (th, inode, allocated_block_nr, 1);
+		goto failure; // retval == -ENOSPC, -EDQUOT or -EIO or -EEXIST
 	    }
-	    if (unp)
-		inode->i_blocks += inode->i_sb->s_blocksize / 512;
 	    //mark_tail_converted (inode);
 	} else if (is_direct_le_ih (ih)) {
 	    /* direct item has to be converted */
@@ -778,7 +780,7 @@ start_trans:
 			if (!th)
 			    th = reiserfs_persistent_transaction(inode->i_sb,3);
 			if (th)
-			    reiserfs_free_block (th, allocated_block_nr);
+			    reiserfs_free_block (th,inode,allocated_block_nr,1);
 		    }
 		    goto failure ;
 		}
@@ -787,7 +789,7 @@ start_trans:
 	    retval = direct2indirect (th, inode, &path, unbh, tail_offset);
 	    if (retval) {
 		reiserfs_unmap_buffer(unbh);
-		reiserfs_free_block (th, allocated_block_nr);
+		reiserfs_free_block (th, inode, allocated_block_nr, 1);
 		goto failure;
 	    }
 	    /* it is important the set_buffer_uptodate is done after
@@ -820,9 +822,6 @@ start_trans:
 		 */
 		mark_buffer_dirty(unbh) ;
 	    }
-
-	    //inode->i_blocks += inode->i_sb->s_blocksize / 512;
-	    //mark_tail_converted (inode);
 	} else {
 	    /* append indirect item with holes if needed, when appending
 	       pointer to 'block'-th block use block, which is already
@@ -870,24 +869,21 @@ start_trans:
 		   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 * blocks_needed);
+	    retval = reiserfs_paste_into_item (th, &path, &tmp_key, inode, (char *)un, UNFM_P_SIZE * blocks_needed);
 
 	    if (blocks_needed != 1)
 		kfree(un);
 
 	    if (retval) {
-		reiserfs_free_block (th, allocated_block_nr);
+		reiserfs_free_block (th, inode, allocated_block_nr, 1);
 		goto failure;
 	    }
-	    if (done) {
-		inode->i_blocks += inode->i_sb->s_blocksize / 512;
-	    } else {
+	    if (!done) {
 		/* 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)
@@ -919,7 +915,7 @@ start_trans:
 			      "%K should not be found\n", &key);
 	    retval = -EEXIST;
 	    if (allocated_block_nr)
-	        reiserfs_free_block (th, allocated_block_nr);
+	        reiserfs_free_block (th, inode, allocated_block_nr, 1);
 	    pathrelse(&path) ;
 	    goto failure;
 	}
@@ -949,6 +945,58 @@ reiserfs_readpages(struct file *file, st
     return mpage_readpages(mapping, pages, nr_pages, reiserfs_get_block);
 }
 
+/* Compute real number of used bytes by file
+ * Following three functions can go away when we'll have enough space in stat item
+ */
+static int real_space_diff(struct inode *inode, int sd_size)
+{
+    int bytes;
+    loff_t blocksize = inode->i_sb->s_blocksize ;
+
+    if (S_ISLNK(inode->i_mode) || S_ISDIR(inode->i_mode))
+        return sd_size ;
+
+    /* End of file is also in full block with indirect reference, so round
+    ** up to the next block.
+    **
+    ** there is just no way to know if the tail is actually packed
+    ** on the file, so we have to assume it isn't.  When we pack the
+    ** tail, we add 4 bytes to pretend there really is an unformatted
+    ** node pointer
+    */
+    bytes = ((inode->i_size + (blocksize-1)) >> inode->i_sb->s_blocksize_bits) * UNFM_P_SIZE + sd_size;
+    return bytes ;
+}
+
+static inline loff_t to_real_used_space(struct inode *inode, ulong blocks,
+                                        int sd_size)
+{
+    if (S_ISLNK(inode->i_mode) || S_ISDIR(inode->i_mode)) {
+        return inode->i_size + (loff_t)(real_space_diff(inode, sd_size)) ;
+    }
+    return ((loff_t)real_space_diff(inode, sd_size)) + (((loff_t)blocks) << 9);
+}
+
+/* Compute number of blocks used by file in ReiserFS counting */
+static inline ulong to_fake_used_blocks(struct inode *inode, int sd_size)
+{
+    loff_t bytes = inode_get_bytes(inode) ;
+    loff_t real_space = real_space_diff(inode, sd_size) ;
+
+    /* keeps fsck and non-quota versions of reiserfs happy */
+    if (S_ISLNK(inode->i_mode) || S_ISDIR(inode->i_mode)) {
+        bytes += (loff_t)511 ;
+    }
+
+    /* files from before the quota patch might i_blocks such that
+    ** bytes < real_space.  Deal with that here to prevent it from
+    ** going negative.
+    */
+    if (bytes < real_space)
+        return 0 ;
+    return (bytes - real_space) >> 9;
+}
+
 //
 // BAD: new directories have stat data of new type and all other items
 // of old type. Version stored in the inode says about body items, so
@@ -1014,6 +1062,14 @@ static void init_inode (struct inode * i
 
         rdev = sd_v1_rdev(sd);
 	REISERFS_I(inode)->i_first_direct_byte = sd_v1_first_direct_byte(sd);
+	/* an early bug in the quota code can give us an odd number for the
+	** block count.  This is incorrect, fix it here.
+	*/
+	if (inode->i_blocks & 1) {
+	    inode->i_blocks++ ;
+	}
+	inode_set_bytes(inode, to_real_used_space(inode, inode->i_blocks,
+	                                          SD_V1_SIZE));
 	/* nopack is initially zero for v1 objects. For v2 objects,
 	   nopack is initialised from sd_attrs */
 	REISERFS_I(inode)->i_flags &= ~i_nopack_mask;
@@ -1046,6 +1102,8 @@ static void init_inode (struct inode * i
 	    set_inode_item_key_version (inode, KEY_FORMAT_3_6);
 	REISERFS_I(inode)->i_first_direct_byte = 0;
 	set_inode_sd_version (inode, STAT_DATA_V2);
+	inode_set_bytes(inode, to_real_used_space(inode, inode->i_blocks,
+	                                          SD_V2_SIZE));
 	/* read persistent inode attributes from sd and initalise
 	   generic inode flags from them */
 	REISERFS_I(inode)->i_attrs = sd_v2_attrs( sd );
@@ -1072,7 +1130,7 @@ static void init_inode (struct inode * i
 
 
 // update new stat data with inode fields
-static void inode2sd (void * sd, struct inode * inode)
+static void inode2sd (void * sd, struct inode * inode, loff_t size)
 {
     struct stat_data * sd_v2 = (struct stat_data *)sd;
     __u16 flags;
@@ -1080,12 +1138,12 @@ static void inode2sd (void * sd, struct 
     set_sd_v2_mode(sd_v2, inode->i_mode );
     set_sd_v2_nlink(sd_v2, inode->i_nlink );
     set_sd_v2_uid(sd_v2, inode->i_uid );
-    set_sd_v2_size(sd_v2, inode->i_size );
+    set_sd_v2_size(sd_v2, size );
     set_sd_v2_gid(sd_v2, inode->i_gid );
     set_sd_v2_mtime(sd_v2, inode->i_mtime.tv_sec );
     set_sd_v2_atime(sd_v2, inode->i_atime.tv_sec );
     set_sd_v2_ctime(sd_v2, inode->i_ctime.tv_sec );
-    set_sd_v2_blocks(sd_v2, inode->i_blocks );
+    set_sd_v2_blocks(sd_v2, to_fake_used_blocks(inode, SD_V2_SIZE));
     if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
 	set_sd_v2_rdev(sd_v2, new_encode_dev(inode->i_rdev));
     else
@@ -1097,7 +1155,7 @@ static void inode2sd (void * sd, struct 
 
 
 // used to copy inode's fields to old stat data
-static void inode2sd_v1 (void * sd, struct inode * inode)
+static void inode2sd_v1 (void * sd, struct inode * inode, loff_t size)
 {
     struct stat_data_v1 * sd_v1 = (struct stat_data_v1 *)sd;
 
@@ -1105,7 +1163,7 @@ static void inode2sd_v1 (void * sd, stru
     set_sd_v1_uid(sd_v1, inode->i_uid );
     set_sd_v1_gid(sd_v1, inode->i_gid );
     set_sd_v1_nlink(sd_v1, inode->i_nlink );
-    set_sd_v1_size(sd_v1, inode->i_size );
+    set_sd_v1_size(sd_v1, size );
     set_sd_v1_atime(sd_v1, inode->i_atime.tv_sec );
     set_sd_v1_ctime(sd_v1, inode->i_ctime.tv_sec );
     set_sd_v1_mtime(sd_v1, inode->i_mtime.tv_sec );
@@ -1113,7 +1171,7 @@ static void inode2sd_v1 (void * sd, stru
     if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
         set_sd_v1_rdev(sd_v1, new_encode_dev(inode->i_rdev));
     else
-        set_sd_v1_blocks(sd_v1, inode->i_blocks );
+        set_sd_v1_blocks(sd_v1, to_fake_used_blocks(inode, SD_V1_SIZE));
 
     // Sigh. i_first_direct_byte is back
     set_sd_v1_first_direct_byte(sd_v1, REISERFS_I(inode)->i_first_direct_byte);
@@ -1123,7 +1181,8 @@ static void inode2sd_v1 (void * sd, stru
 /* NOTE, you must prepare the buffer head before sending it here,
 ** and then log it after the call
 */
-static void update_stat_data (struct path * path, struct inode * inode)
+static void update_stat_data (struct path * path, struct inode * inode,
+                              loff_t size)
 {
     struct buffer_head * bh;
     struct item_head * ih;
@@ -1137,17 +1196,17 @@ static void update_stat_data (struct pat
   
     if (stat_data_v1 (ih)) {
 	// path points to old stat data
-	inode2sd_v1 (B_I_PITEM (bh, ih), inode);
+	inode2sd_v1 (B_I_PITEM (bh, ih), inode, size);
     } else {
-	inode2sd (B_I_PITEM (bh, ih), inode);
+	inode2sd (B_I_PITEM (bh, ih), inode, size);
     }
 
     return;
 }
 
 
-void reiserfs_update_sd (struct reiserfs_transaction_handle *th, 
-			 struct inode * inode)
+void reiserfs_update_sd_size (struct reiserfs_transaction_handle *th,
+			      struct inode * inode, loff_t size)
 {
     struct cpu_key key;
     INITIALIZE_PATH(path);
@@ -1197,7 +1256,7 @@ void reiserfs_update_sd (struct reiserfs
 	}
 	break;
     }
-    update_stat_data (&path, inode);
+    update_stat_data (&path, inode, size);
     journal_mark_dirty(th, th->t_super, bh) ; 
     pathrelse (&path);
     return;
@@ -1480,6 +1539,7 @@ int reiserfs_sync_inode (struct reiserfs
 /* stat data of new object is inserted already, this inserts the item
    containing "." and ".." entries */
 static int reiserfs_new_directory (struct reiserfs_transaction_handle *th, 
+				   struct inode *inode,
 				   struct item_head * ih, struct path * path,
 				   struct inode * dir)
 {
@@ -1524,13 +1584,14 @@ static int reiserfs_new_directory (struc
     }
 
     /* insert item, that is empty directory item */
-    return reiserfs_insert_item (th, path, &key, ih, body);
+    return reiserfs_insert_item (th, path, &key, ih, inode, body);
 }
 
 
 /* stat data of object has been inserted, this inserts the item
    containing the body of symlink */
 static int reiserfs_new_symlink (struct reiserfs_transaction_handle *th, 
+				 struct inode *inode,	/* Inode of symlink */
 				 struct item_head * ih,
 				 struct path * path, const char * symname, int item_len)
 {
@@ -1560,7 +1621,7 @@ static int reiserfs_new_symlink (struct 
     }
 
     /* insert item, that is body of symlink */
-    return reiserfs_insert_item (th, path, &key, ih, symname);
+    return reiserfs_insert_item (th, path, &key, ih, inode, symname);
 }
 
 
@@ -1628,7 +1689,8 @@ int reiserfs_new_inode (struct reiserfs_
 
     inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
     inode->i_size = i_size;
-    inode->i_blocks = (inode->i_size + 511) >> 9;
+    inode->i_blocks = 0;
+    inode->i_bytes = 0;
     REISERFS_I(inode)->i_first_direct_byte = S_ISLNK(mode) ? 1 : 
       U32_MAX/*NO_BYTES_IN_DIRECT_ITEM*/;
 
@@ -1673,9 +1735,9 @@ int reiserfs_new_inode (struct reiserfs_
 	    err = -EINVAL;
 	    goto out_bad_inode;
 	}
-	inode2sd_v1 (&sd, inode);
+	inode2sd_v1 (&sd, inode, inode->i_size);
     } else {
-	inode2sd (&sd, inode);
+	inode2sd (&sd, inode, inode->i_size);
     }
     // these do not go to on-disk stat data
     inode->i_ino = le32_to_cpu (ih.ih_key.k_objectid);
@@ -1699,7 +1761,7 @@ int reiserfs_new_inode (struct reiserfs_
     if (REISERFS_I(dir)->new_packing_locality)
 	th->displace_new_blocks = 1;
 #endif
-    retval = reiserfs_insert_item (th, &path_to_key, &key, &ih, (char *)(&sd));
+    retval = reiserfs_insert_item (th, &path_to_key, &key, &ih, inode, (char *)(&sd));
     if (retval) {
 	err = retval;
 	reiserfs_check_path(&path_to_key) ;
@@ -1712,14 +1774,14 @@ int reiserfs_new_inode (struct reiserfs_
 #endif
     if (S_ISDIR(mode)) {
 	/* insert item with "." and ".." */
-	retval = reiserfs_new_directory (th, &ih, &path_to_key, dir);
+	retval = reiserfs_new_directory (th, inode, &ih, &path_to_key, dir);
     }
 
     if (S_ISLNK(mode)) {
 	/* insert body of symlink */
 	if (!old_format_only (sb))
 	    i_size = ROUND_UP(i_size);
-	retval = reiserfs_new_symlink (th, &ih, &path_to_key, symname, i_size);
+	retval = reiserfs_new_symlink (th, inode, &ih, &path_to_key, symname, i_size);
     }
     if (retval) {
 	err = retval;
@@ -1757,6 +1819,9 @@ out_bad_inode:
 
     /* dquot_drop must be done outside a transaction */
     journal_end(th, th->t_super, th->t_blocks_allocated) ;
+    DQUOT_FREE_INODE(inode);
+    DQUOT_DROP(inode);
+    inode->i_flags |= S_NOQUOTA;
     make_bad_inode(inode);
 
 out_inserted_sd:
@@ -2294,6 +2359,7 @@ static int reiserfs_commit_write(struct 
     struct inode *inode = page->mapping->host ;
     loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
     int ret = 0;
+    int update_sd = 0;
     struct reiserfs_transaction_handle *th = NULL;
     
     reiserfs_wait_on_write_block(inode->i_sb) ;
@@ -2320,11 +2386,14 @@ static int reiserfs_commit_write(struct 
 	reiserfs_update_inode_transaction(inode) ;
 	inode->i_size = pos ;
 	reiserfs_update_sd(&myth, inode) ;
+	update_sd = 1;
 	journal_end(&myth, inode->i_sb, 1) ;
 	reiserfs_write_unlock(inode->i_sb);
     }
     if (th) {
 	reiserfs_write_lock(inode->i_sb);
+	if (!update_sd)
+	    reiserfs_update_sd(th, inode) ;
         reiserfs_end_persistent_transaction(th);
 	reiserfs_write_unlock(inode->i_sb);
     }
@@ -2533,7 +2602,6 @@ static ssize_t reiserfs_direct_IO(int rw
 			offset, nr_segs, reiserfs_get_blocks_direct_io, NULL);
 }
 
-
 int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) {
     struct inode *inode = dentry->d_inode ;
     int error ;
diff -puN fs/reiserfs/namei.c~reiserfs-quota fs/reiserfs/namei.c
--- 25/fs/reiserfs/namei.c~reiserfs-quota	Fri Apr 23 14:36:54 2004
+++ 25-akpm/fs/reiserfs/namei.c	Fri Apr 23 14:36:54 2004
@@ -18,6 +18,7 @@
 #include <linux/reiserfs_acl.h>
 #include <linux/reiserfs_xattr.h>
 #include <linux/smp_lock.h>
+#include <linux/quotaops.h>
 
 #define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { i->i_nlink++; if (i->i_nlink >= REISERFS_LINK_MAX) i->i_nlink=1; }
 #define DEC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) i->i_nlink--;
@@ -519,7 +520,7 @@ static int reiserfs_add_entry (struct re
     }
   
     /* perform the insertion of the entry that we have prepared */
-    retval = reiserfs_paste_into_item (th, &path, &entry_key, buffer, paste_size);
+    retval = reiserfs_paste_into_item (th, &path, &entry_key, dir, buffer, paste_size);
     if (buffer != small_buf)
 	reiserfs_kfree (buffer, buflen, dir->i_sb);
     if (retval) {
@@ -528,7 +529,6 @@ static int reiserfs_add_entry (struct re
     }
 
     dir->i_size += paste_size;
-    dir->i_blocks = ((dir->i_size + 511) >> 9);
     dir->i_mtime = dir->i_ctime = CURRENT_TIME;
     if (!S_ISDIR (inode->i_mode) && visible)
 	// reiserfs_mkdir or reiserfs_rename will do that by itself
@@ -544,7 +544,9 @@ static int reiserfs_add_entry (struct re
 ** inserted into the tree yet.
 */
 static int drop_new_inode(struct inode *inode) {
+    DQUOT_DROP(inode);
     make_bad_inode(inode) ;
+    inode->i_flags |= S_NOQUOTA;
     iput(inode) ;
     return 0 ;
 }
@@ -570,6 +572,11 @@ static int new_inode_init(struct inode *
     } else {
         inode->i_gid = current->fsgid;
     }
+    DQUOT_INIT(inode);
+    if (DQUOT_ALLOC_INODE(inode)) {
+        drop_new_inode(inode);
+	return -EDQUOT;
+    }
     return 0 ;
 }
 
@@ -836,7 +843,6 @@ static int reiserfs_rmdir (struct inode 
 
     DEC_DIR_INODE_NLINK(dir)
     dir->i_size -= (DEH_SIZE + de.de_entrylen);
-    dir->i_blocks = ((dir->i_size + 511) >> 9);
     reiserfs_update_sd (&th, dir);
 
     /* prevent empty directory from getting lost */
@@ -919,7 +925,6 @@ static int reiserfs_unlink (struct inode
     reiserfs_update_sd (&th, inode);
 
     dir->i_size -= (de.de_entrylen + DEH_SIZE);
-    dir->i_blocks = ((dir->i_size + 511) >> 9);
     dir->i_ctime = dir->i_mtime = CURRENT_TIME;
     reiserfs_update_sd (&th, dir);
 
@@ -1335,7 +1340,6 @@ static int reiserfs_rename (struct inode
 	reiserfs_warning ("vs-7060: reiserfs_rename: couldn't not cut old name. Fsck later?\n");
 
     old_dir->i_size -= DEH_SIZE + old_de.de_entrylen;
-    old_dir->i_blocks = ((old_dir->i_size + 511) >> 9);
 
     reiserfs_update_sd (&th, old_dir);
     reiserfs_update_sd (&th, new_dir);
diff -puN fs/reiserfs/stree.c~reiserfs-quota fs/reiserfs/stree.c
--- 25/fs/reiserfs/stree.c~reiserfs-quota	Fri Apr 23 14:36:54 2004
+++ 25-akpm/fs/reiserfs/stree.c	Fri Apr 23 14:36:54 2004
@@ -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 bu
   return ( B_LEVEL (p_s_bh) != FREE_LEVEL );
 }
 
-
-
-
 inline void copy_short_key (void * to, const void * from)
 {
     memcpy (to, from, SHORT_KEY_SIZE);
@@ -1125,8 +1123,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 +1152,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 +1163,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 +1204,46 @@ void padd_item (char * item, int total_l
 	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;
@@ -1268,6 +1293,22 @@ int reiserfs_delete_item (struct reiserf
 
     // 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 +1340,14 @@ int reiserfs_delete_item (struct reiserf
 	       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
+    printk(KERN_DEBUG "reiserquota delete_item(): freeing %u, id=%u type=%c\n", 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,14 +1372,16 @@ int reiserfs_delete_item (struct reiserf
 
 /* 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);
     
@@ -1358,6 +1405,7 @@ void reiserfs_delete_solid_item (struct 
 	    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);
 	if (retval == REPEAT_SEARCH) {
@@ -1367,6 +1415,12 @@ void reiserfs_delete_solid_item (struct 
 
 	if (retval == CARRY_ON) {
 	    do_balance (&tb, 0, 0, M_DELETE);
+	    if (inode) {	/* Should we count quota for item? (we don't count quotas for save-links) */
+#ifdef REISERQUOTA_DEBUG
+		printk(KERN_DEBUG "reiserquota delete_solid_item(): freeing %u id=%u type=%c\n", quota_cut_bytes, inode->i_uid, key2type(key));
+#endif
+		DQUOT_FREE_SPACE_NODIRTY(inode, quota_cut_bytes);
+	    }
 	    break;
 	}
 
@@ -1399,7 +1453,7 @@ void reiserfs_delete_object (struct reis
       }
 /* USE_INODE_GENERATION_COUNTER */
 #endif
-    reiserfs_delete_solid_item (th, INODE_PKEY (inode));
+    reiserfs_delete_solid_item (th, inode, INODE_PKEY (inode));
 }
 
 
@@ -1486,12 +1540,14 @@ int reiserfs_cut_from_item (struct reise
        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;
     
     
     init_tb_struct(th, &s_cut_balance, p_s_inode->i_sb, p_s_path, n_cut_size);
@@ -1579,23 +1635,27 @@ int reiserfs_cut_from_item (struct reise
     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);
@@ -1630,10 +1690,13 @@ int reiserfs_cut_from_item (struct reise
 	*/
 	REISERFS_I(p_s_inode)->i_flags &= ~i_pack_on_close_mask ;
     }
+#ifdef REISERQUOTA_DEBUG
+    printk(KERN_DEBUG "reiserquota cut_from_item(): freeing %u id=%u type=%c\n", 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)
@@ -1641,8 +1704,8 @@ static void truncate_directory (struct r
 
     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);    
 }
@@ -1809,18 +1872,37 @@ static void check_research_for_paste (st
 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
+    printk(KERN_DEBUG "reiserquota paste_into_item(): allocating %u id=%u type=%c\n", 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);
@@ -1849,6 +1931,10 @@ int reiserfs_paste_into_item (struct rei
 error_out:
     /* this also releases the path */
     unfix_nodes(&s_paste_balance);
+#ifdef REISERQUOTA_DEBUG
+    printk(KERN_DEBUG "reiserquota paste_into_item(): freeing %u id=%u type=%c\n", 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 +1944,45 @@ int reiserfs_insert_item(struct reiserfs
 			 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
+	printk(KERN_DEBUG "reiserquota insert_item(): allocating %u id=%u type=%c\n", 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);
@@ -1900,6 +2008,11 @@ int reiserfs_insert_item(struct reiserfs
 error_out:
     /* also releases the path */
     unfix_nodes(&s_ins_balance);
+#ifdef REISERQUOTA_DEBUG
+    printk(KERN_DEBUG "reiserquota insert_item(): freeing %u id=%u type=%c\n", quota_bytes, inode->i_uid, head2type(p_s_ih));
+#endif
+    if (inode)
+	DQUOT_FREE_SPACE_NODIRTY(inode, quota_bytes) ;
     return retval; 
 }
 
diff -puN fs/reiserfs/super.c~reiserfs-quota fs/reiserfs/super.c
--- 25/fs/reiserfs/super.c~reiserfs-quota	Fri Apr 23 14:36:54 2004
+++ 25-akpm/fs/reiserfs/super.c	Fri Apr 23 14:36:54 2004
@@ -115,7 +115,7 @@ static void remove_save_link_only (struc
      /* we are going to do one balancing */
      journal_begin (&th, s, JOURNAL_PER_BALANCE_CNT);
  
-     reiserfs_delete_solid_item (&th, key);
+     reiserfs_delete_solid_item (&th, NULL, key);
      if (oid_free)
         /* removals are protected by direct items */
         reiserfs_release_objectid (&th, le32_to_cpu (key->k_objectid));
@@ -301,8 +301,8 @@ void add_save_link (struct reiserfs_tran
     /* body of "save" link */
     link = INODE_PKEY (inode)->k_dir_id;
 
-    /* put "save" link inot tree */
-    retval = reiserfs_insert_item (th, &path, &key, &ih, (char *)&link);
+    /* put "save" link inot tree, don't charge quota to anyone */
+    retval = reiserfs_insert_item (th, &path, &key, &ih, NULL, (char *)&link);
     if (retval) {
 	if (retval != -ENOSPC)
 	    reiserfs_warning ("vs-2120: add_save_link: insert_item returned %d\n",
@@ -344,7 +344,8 @@ void remove_save_link (struct inode * in
           ( REISERFS_I(inode) -> i_flags & i_link_saved_truncate_mask ) ) ||
         ( !truncate && 
           ( REISERFS_I(inode) -> i_flags & i_link_saved_unlink_mask ) ) )
-	reiserfs_delete_solid_item (&th, &key);
+	/* don't take quota bytes from anywhere */
+	reiserfs_delete_solid_item (&th, NULL, &key);
     if (!truncate) {
 	reiserfs_release_objectid (&th, inode->i_ino);
 	REISERFS_I(inode) -> i_flags &= ~i_link_saved_unlink_mask;
@@ -714,6 +715,8 @@ static int reiserfs_parse_options (struc
 	{"jdev", 'j', 0, 0, 0},
 	{"nolargeio", 'w', 0, 0, 0},
 	{"commit", 'c', 0, 0, 0},
+	{"usrquota", 0, 0, 0, 0},
+	{"grpquota", 0, 0, 0, 0},
 	{NULL, 0, 0, 0, 0}
     };
 	
diff -puN fs/reiserfs/tail_conversion.c~reiserfs-quota fs/reiserfs/tail_conversion.c
--- 25/fs/reiserfs/tail_conversion.c~reiserfs-quota	Fri Apr 23 14:36:54 2004
+++ 25-akpm/fs/reiserfs/tail_conversion.c	Fri Apr 23 14:36:54 2004
@@ -66,11 +66,11 @@ int direct2indirect (struct reiserfs_tra
 	set_ih_free_space (&ind_ih, 0); /* delete at nearest future */
         put_ih_item_len( &ind_ih, UNFM_P_SIZE );
 	PATH_LAST_POSITION (path)++;
-	n_retval = reiserfs_insert_item (th, path, &end_key, &ind_ih, 
+	n_retval = reiserfs_insert_item (th, path, &end_key, &ind_ih, inode,
 					 (char *)&unfm_ptr);
     } else {
 	/* Paste into last indirect item of an object. */
-	n_retval = reiserfs_paste_into_item(th, path, &end_key,
+	n_retval = reiserfs_paste_into_item(th, path, &end_key, inode,
 					    (char *)&unfm_ptr, UNFM_P_SIZE);
     }
     if ( n_retval ) {
@@ -274,7 +274,7 @@ int indirect2direct (struct reiserfs_tra
     set_cpu_key_k_type (&key, TYPE_DIRECT);
     key.key_length = 4;
     /* Insert tail as new direct item in the tree */
-    if ( reiserfs_insert_item(th, p_s_path, &key, &s_ih,
+    if ( reiserfs_insert_item(th, p_s_path, &key, &s_ih, p_s_inode,
 			      tail ? tail : NULL) < 0 ) {
 	/* No disk memory. So we can not convert last unformatted node
 	   to the direct item.  In this case we used to adjust
@@ -292,13 +292,15 @@ int indirect2direct (struct reiserfs_tra
     */
     unmap_buffers(page, pos1) ;
 
+    /* make sure to get the i_blocks changes from reiserfs_insert_item */
+    reiserfs_update_sd(th, p_s_inode);
+
     // note: we have now the same as in above direct2indirect
     // conversion: there are two keys which have matching first three
     // key components. They only differ by the fouhth one.
 
     /* We have inserted new direct item and must remove last
        unformatted node. */
-    p_s_inode->i_blocks += (p_s_sb->s_blocksize / 512);
     *p_c_mode = M_CUT;
 
     /* we store position of first direct item in the in-core inode */
diff -puN include/linux/reiserfs_fs.h~reiserfs-quota include/linux/reiserfs_fs.h
--- 25/include/linux/reiserfs_fs.h~reiserfs-quota	Fri Apr 23 14:36:54 2004
+++ 25-akpm/include/linux/reiserfs_fs.h	Fri Apr 23 14:36:54 2004
@@ -268,6 +268,7 @@ int is_reiserfs_jr (struct reiserfs_supe
 #define NO_DISK_SPACE -3
 #define NO_BALANCING_NEEDED  (-4)
 #define NO_MORE_UNUSED_CONTIGUOUS_BLOCKS (-5)
+#define QUOTA_EXCEEDED -6
 
 typedef __u32 b_blocknr_t;
 typedef __u32 unp_t;
@@ -1238,7 +1239,6 @@ excessive effort to avoid disturbing the
 gods only know how we are going to SMP the code that uses them.
 znodes are the way! */
 
-
 struct  path {
   int                   path_length;                      	/* Length of the array above.   */
   struct  path_element  path_elements[EXTENDED_MAX_HEIGHT];	/* Array of the path elements.  */
@@ -1889,11 +1889,13 @@ void pathrelse_and_restore (struct super
 int reiserfs_insert_item (struct reiserfs_transaction_handle *th, 
 			  struct path * path, 
 			  const struct cpu_key * key,
-			  struct item_head * ih, const char * body);
+			  struct item_head * ih,
+			  struct inode *inode, const char * body);
 
 int reiserfs_paste_into_item (struct reiserfs_transaction_handle *th,
 			      struct path * path,
 			      const struct cpu_key * key,
+			      struct inode *inode,
 			      const char * body, int paste_size);
 
 int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th,
@@ -1910,7 +1912,7 @@ int reiserfs_delete_item (struct reiserf
 			  struct buffer_head  * p_s_un_bh);
 
 void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th,
-                                                                struct key * key);
+				 struct inode *inode, struct key * key);
 void reiserfs_delete_object (struct reiserfs_transaction_handle *th, struct inode * p_s_inode);
 void reiserfs_do_truncate (struct reiserfs_transaction_handle *th, 
 			   struct  inode * p_s_inode, struct page *, 
@@ -1955,8 +1957,18 @@ int reiserfs_new_inode (struct reiserfs_
 				   struct inode * dir, int mode, 
 				   const char * symname, loff_t i_size,
 				   struct dentry *dentry, struct inode *inode);
-int reiserfs_sync_inode (struct reiserfs_transaction_handle *th, struct inode * inode);
-void reiserfs_update_sd (struct reiserfs_transaction_handle *th, struct inode * inode);
+
+int reiserfs_sync_inode (struct reiserfs_transaction_handle *th,
+                         struct inode * inode);
+
+void reiserfs_update_sd_size (struct reiserfs_transaction_handle *th,
+                              struct inode * inode, loff_t size);
+
+static inline void reiserfs_update_sd(struct reiserfs_transaction_handle *th,
+                                      struct inode *inode)
+{
+    reiserfs_update_sd_size(th, inode, inode->i_size) ;
+}
 
 void sd_attrs_to_i_attrs( __u16 sd_attrs, struct inode *inode );
 void i_attrs_to_sd_attrs( struct inode *inode, __u16 *sd_attrs );
@@ -2139,7 +2151,7 @@ typedef struct __reiserfs_blocknr_hint r
 
 int reiserfs_parse_alloc_options (struct super_block *, char *);
 int is_reusable (struct super_block * s, b_blocknr_t block, int bit_value);
-void reiserfs_free_block (struct reiserfs_transaction_handle *th, b_blocknr_t);
+void reiserfs_free_block (struct reiserfs_transaction_handle *th, struct inode *, b_blocknr_t, int for_unformatted);
 int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *, b_blocknr_t * , int, int);
 extern inline int reiserfs_new_form_blocknrs (struct tree_balance * tb,
 					      b_blocknr_t *new_blocknrs, int amount_needed)

_