--- fs/reiserfs/bitmap.c	Tue Aug 29 01:58:06 2000
+++ fs/reiserfs/bitmap.c	Tue Aug 29 10:59:41 2000
@@ -12,6 +12,7 @@
 #include <linux/reiserfs_fs.h>
 #include <linux/locks.h>
 #include <asm/bitops.h>
+#include <linux/quotaops.h>
 
 #else
 
@@ -110,7 +111,7 @@
 
 /* There would be a modest performance benefit if we write a version
    to free a list of blocks at once. -Hans */
-void reiserfs_free_block (struct reiserfs_transaction_handle *th, unsigned long block)
+void reiserfs_free_block (struct reiserfs_transaction_handle *th, struct inode *inode, unsigned long block, int for_unformatted)
 {
     struct super_block * s = th->t_super;
     struct reiserfs_super_block * rs;
@@ -151,6 +152,13 @@
 
   journal_mark_dirty (th, s, sbh);
   s->s_dirt = 1;
+  if (for_unformatted) {
+    inode_sub_bytes(inode, s->s_blocksize);
+#ifdef REISERQUOTA_DEBUG
+    printk(KERN_DEBUG "reiserquota: freeing block id=%u\n", inode->i_uid);
+#endif
+    DQUOT_FREE_BLOCK(inode->i_sb, inode, 1);
+  }
 }
 
 
@@ -288,6 +296,7 @@
 
    return CARRY_ON if everything is ok
    return NO_DISK_SPACE if out of disk space
+   return QUOTA_EXCEEDED if disk quota is exceeded (can only happen for unformatted nodes)
    return NO_MORE_UNUSED_CONTIGUOUS_BLOCKS if the block we found is not contiguous to the last one
    
    return block numbers found, in the array free_blocknrs.  assumes
@@ -307,6 +316,7 @@
 /* This function is NOT SCHEDULE-SAFE! */
 
 static int do_reiserfs_new_blocknrs (struct reiserfs_transaction_handle *th,
+                                     struct inode *inode,
                                      unsigned long * free_blocknrs, 
 				     unsigned long search_start, 
 				     int amount_needed, int priority, 
@@ -315,6 +325,7 @@
 {
   struct super_block * s = th->t_super;
   int i, j;
+  int quota_ret = 0;
   unsigned long * block_list_start = free_blocknrs;
   int init_amount_needed = amount_needed;
   unsigned long new_block = 0 ; 
@@ -365,9 +376,11 @@
 				   -Hans */
 free_and_return:
 	for ( ; block_list_start != free_blocknrs; block_list_start++) {
-	  reiserfs_free_block (th, *block_list_start);
+	  reiserfs_free_block (th, inode, *block_list_start, for_unformatted);
 	  *block_list_start = 0;
 	}
+	if (quota_ret)
+            return QUOTA_EXCEEDED;
 	if (for_prealloc) 
 	    return NO_MORE_UNUSED_CONTIGUOUS_BLOCKS;
 	else
@@ -417,7 +430,18 @@
 	amount_needed++ ;
 	continue ;
     }
-       
+    if (for_unformatted) {	/* We directly account quotas only for unformatted nodes */
+#ifdef REISERQUOTA_DEBUG
+	printk(KERN_DEBUG "reiserquota: allocating block id=%u\n", inode->i_uid);
+#endif
+	if (for_prealloc)
+	    quota_ret = DQUOT_PREALLOC_BLOCK(inode->i_sb, inode, 1);
+	else
+	    quota_ret = DQUOT_ALLOC_BLOCK(inode->i_sb, inode, 1);
+	if (quota_ret)	/* Quota exceeded? */
+	    goto free_and_return;
+	inode_add_bytes(inode, s->s_blocksize);
+    }
 
     reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[i], 1) ;
 
@@ -432,6 +456,13 @@
     if (reiserfs_test_and_set_le_bit (j, SB_AP_BITMAP (s)[i]->b_data)) {
 	reiserfs_warning("vs-4150: reiserfs_new_blocknrs, block not free");
 	reiserfs_restore_prepared_buffer(s, SB_AP_BITMAP(s)[i]) ;
+	if (for_unformatted) {
+#ifdef REISERQUOTA_DEBUG
+	    printk(KERN_DEBUG "reiserquota: freeing block id=%u\n", inode->i_uid);
+#endif
+	    DQUOT_FREE_BLOCK(inode->i_sb, inode, 1);
+	    inode_sub_bytes(inode, s->s_blocksize);
+	}
 	amount_needed++ ;
 	continue ;
     }    
@@ -452,12 +483,12 @@
 // this is called only by get_empty_nodes with for_preserve_list==0
 int reiserfs_new_blocknrs (struct reiserfs_transaction_handle *th, unsigned long * free_blocknrs,
 			    unsigned long search_start, int amount_needed) {
-  return do_reiserfs_new_blocknrs(th, free_blocknrs, search_start, amount_needed, 0/*for_preserve_list-priority*/, 0/*for_formatted*/, 0/*for_prealloc */) ;
+  return do_reiserfs_new_blocknrs(th, NULL, free_blocknrs, search_start, amount_needed, 0/*for_preserve_list-priority*/, 0/*for_formatted*/, 0/*for_prealloc */) ;
 }
 
 
 // called by get_new_buffer and by reiserfs_get_block with amount_needed == 1 and for_preserve_list == 0
-int reiserfs_new_unf_blocknrs(struct reiserfs_transaction_handle *th, unsigned long * free_blocknrs,
+int reiserfs_new_unf_blocknrs(struct reiserfs_transaction_handle *th, struct inode *inode, unsigned long * free_blocknrs,
 			      unsigned long search_start) {
 #if 0
 #ifdef REISERFS_PREALLOCATE
@@ -466,7 +497,7 @@
 #endif
 #endif
 
-  return do_reiserfs_new_blocknrs(th, free_blocknrs, search_start, 
+  return do_reiserfs_new_blocknrs(th, inode, free_blocknrs, search_start, 
                                   1/*amount_needed*/,
 				  0/*for_preserve_list-priority*/, 
 				  1/*for formatted*/,
@@ -526,7 +557,7 @@
     {
       if ( search_start < border ) search_start=border;
   
-      ret = do_reiserfs_new_blocknrs(th, free_blocknrs, search_start, 
+      ret = do_reiserfs_new_blocknrs(th, p_s_inode, free_blocknrs, search_start, 
 				     1/*amount_needed*/, 
 				/* someone please remove the preserve list detritus. -Hans */
 				     0/*for_preserve_list-priority*/, 
@@ -560,7 +591,7 @@
   n = 8;
   blks = n-1;
   for (i=0; i<n; i++) {
-    ret = do_reiserfs_new_blocknrs(th, free_blocknrs, search_start, 
+    ret = do_reiserfs_new_blocknrs(th, p_s_inode, free_blocknrs, search_start, 
 				   1/*amount_needed*/, 
 				   0/*for_preserve_list-priority*/, 
 				   1/*for_formatted*/,
@@ -577,7 +608,7 @@
       /* this should be caught by new_blocknrs now, checking code */
       /* use your email name of yura, not yr, and I don't believe you have written 4050 error messages.... -Hans */
       reiserfs_warning("yura-4160, reiserfs_new_unf_blocknrs2: pre-allocated not contiguous set of blocks!\n") ;
-      reiserfs_free_block(th, allocated[i]);
+      reiserfs_free_block(th, p_s_inode, allocated[i], 1);
       blks = i-1; 
       break;
     }
@@ -620,7 +651,7 @@
 {
     if (inode->u.reiserfs_i.i_prealloc_count > 0) {
       while (inode->u.reiserfs_i.i_prealloc_count--) {
-	reiserfs_free_block(th,inode->u.reiserfs_i.i_prealloc_block);
+	reiserfs_free_block(th,inode,inode->u.reiserfs_i.i_prealloc_block,1);
 	inode->u.reiserfs_i.i_prealloc_block++;
       }
     }
--- fs/reiserfs/buffer2.c	Tue Aug 29 01:58:06 2000
+++ fs/reiserfs/buffer2.c	Fri Jul 21 15:14:06 2000
@@ -398,6 +398,7 @@
 /* The function is NOT SCHEDULE-SAFE! */
 int get_new_buffer(
 		   struct reiserfs_transaction_handle *th, 
+		   struct inode *inode,
 		   struct buffer_head *  p_s_bh,
 		   struct buffer_head ** pp_s_new_bh,
 		   struct path	       * p_s_path
@@ -406,8 +407,10 @@
   int		n_repeat;
   struct super_block *	 p_s_sb = th->t_super;
 
-  if ( (n_repeat = reiserfs_new_unf_blocknrs (th, &n_new_blocknumber, p_s_bh->b_blocknr)) == NO_DISK_SPACE )
+  if ( (n_repeat = reiserfs_new_unf_blocknrs (th, inode, &n_new_blocknumber, p_s_bh->b_blocknr)) == NO_DISK_SPACE )
     return NO_DISK_SPACE;
+  if (n_repeat == QUOTA_EXCEEDED)
+    return QUOTA_EXCEEDED;
   
   *pp_s_new_bh = reiserfs_getblk(p_s_sb->s_dev, n_new_blocknumber, p_s_sb->s_blocksize);
   if (atomic_read (&(*pp_s_new_bh)->b_count) > 1) {
--- fs/reiserfs/do_balan.c	Tue Aug 29 01:58:06 2000
+++ fs/reiserfs/do_balan.c	Fri Jul 21 14:10:54 2000
@@ -1640,7 +1640,7 @@
 	    if (buffer_dirty (tb->thrown[i]))
 	      printk ("free_thrown deals with dirty buffer %ld\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);
 	}
     }
 }
--- fs/reiserfs/fix_node.c	Tue Aug 29 01:58:06 2000
+++ fs/reiserfs/fix_node.c	Tue Aug 29 03:12:24 2000
@@ -2741,7 +2741,7 @@
 	    /* 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 */
--- fs/reiserfs/inode.c	Tue Aug 29 01:58:06 2000
+++ fs/reiserfs/inode.c	Tue Aug 29 03:14:04 2000
@@ -7,6 +7,7 @@
 #include <linux/reiserfs_fs.h>
 #include <linux/locks.h>
 #include <linux/smp_lock.h>
+#include <linux/quotaops.h>
 #include <asm/uaccess.h>
 
 #else
@@ -29,6 +30,10 @@
   
     lock_kernel() ; 
 
+    /* Quota might not be initialized when we get some just partly created inode and in that
+       case this inode also wasn't counted to quota. */
+    if (IS_QUOTAINIT(inode))
+	DQUOT_FREE_INODE(inode->i_sb, inode);
     /* The = 0 happens when we abort creating a new inode for some reason like lack of space.. */
     if (INODE_PKEY(inode)->k_objectid != 0) { /* also handles bad_inode case */
 	down (&inode->i_sem); 
@@ -449,7 +454,7 @@
 #ifdef REISERFS_PREALLOCATE
 	repeat = reiserfs_new_unf_blocknrs2 (&th, inode, &allocated_block_nr, tag);
 #else
-	repeat = reiserfs_new_unf_blocknrs (&th, &allocated_block_nr, tag);
+	repeat = reiserfs_new_unf_blocknrs (&th, inode, &allocated_block_nr, tag);
 #endif
 
 	if (repeat == NO_DISK_SPACE) {
@@ -461,14 +466,21 @@
 #ifdef REISERFS_PREALLOCATE
 	    repeat = reiserfs_new_unf_blocknrs2 (&th, inode, &allocated_block_nr, tag);
 #else
-	    repeat = reiserfs_new_unf_blocknrs (&th, &allocated_block_nr, tag);
+	    repeat = reiserfs_new_unf_blocknrs (&th, inode, &allocated_block_nr, tag);
 #endif
 
-	    if (repeat != NO_DISK_SPACE) {
+	    if (repeat != NO_DISK_SPACE && repeat != QUOTA_EXCEEDED) {
 		allocated_block_nr = 0 ; /* just in case it got changed somehow */
 		goto research ;
 	    }
-	    retval = -ENOSPC;
+	    if (repeat == QUOTA_EXCEEDED)
+ 		retval = -EDQUOT;
+	    else
+		retval = -ENOSPC;
+	    goto failure;
+	}
+	if (repeat == QUOTA_EXCEEDED) {
+	    retval = -EDQUOT;
 	    goto failure;
 	}
 
@@ -532,17 +544,15 @@
 	    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);
+		reiserfs_free_block (&th, inode, allocated_block_nr, 1);
 
 #ifdef REISERFS_PREALLOCATE
 		reiserfs_discard_prealloc (&th, inode); 
 #endif
 		goto failure; // retval == -ENOSPC 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 */
@@ -565,15 +575,15 @@
 			 
 		    fs_gen = get_generation (inode->i_sb);
 
-		    get_new_buffer (&th, bh, &unbh, &path);
+		    get_new_buffer (&th, inode, bh, &unbh, &path);
 		    if (!unbh) {
 			/* restart_transaction calls pathrelse for us */
 			restart_transaction(&th, inode, &path) ;
-			get_new_buffer (&th, bh, &unbh, &path);
+			get_new_buffer (&th, inode, bh, &unbh, &path);
 			if (unbh) {
 			    goto search_again ;
 			}
-			reiserfs_free_block (&th, allocated_block_nr);
+			reiserfs_free_block (&th, inode, allocated_block_nr, 1);
 
 #ifdef REISERFS_PREALLOCATE
 			reiserfs_discard_prealloc (&th, inode); 
@@ -596,13 +606,13 @@
 		    unsigned long tmp = unbh->b_blocknr;
 
 		    bforget (unbh);
-		    reiserfs_free_block (&th, tmp);
+		    reiserfs_free_block (&th, inode, tmp, 1);
 #ifdef REISERFS_PREALLOCATE
 		    reiserfs_discard_prealloc (&th, inode); 
 #endif
 
 		}
-		reiserfs_free_block (&th, allocated_block_nr);
+		reiserfs_free_block (&th, inode, allocated_block_nr, 1);
 
 #ifdef REISERFS_PREALLOCATE
 		reiserfs_discard_prealloc (&th, inode); 
@@ -626,7 +636,6 @@
 		allow_flush_page_lock(inode->i_sb, unbh->b_page, inode) ;
 		brelse (unbh);
 	    }
-	    //inode->i_blocks += inode->i_sb->s_blocksize / 512;
 	    //mark_tail_converted (inode);
 	} else {
 	    /* append indirect item with holes if needed, when appending
@@ -656,17 +665,15 @@
 	    } else {
 		/* paste hole to the indirect item */
 	    }
-	    retval = reiserfs_paste_into_item (&th, &path, &tmp_key, (char *)&un, UNFM_P_SIZE);
+	    retval = reiserfs_paste_into_item (&th, &path, &tmp_key, inode, (char *)&un, UNFM_P_SIZE);
 	    if (retval) {
-		reiserfs_free_block (&th, allocated_block_nr);
+		reiserfs_free_block (&th, inode, allocated_block_nr, 1);
 
 #ifdef REISERFS_PREALLOCATE
 		reiserfs_discard_prealloc (&th, inode); 
 #endif
 		goto failure;
 	    }
-	    if (un.unfm_nodenum)
-		inode->i_blocks += inode->i_sb->s_blocksize / 512;
 	    //mark_tail_converted (inode);
 	}
 		
@@ -1064,7 +1071,7 @@
 
 /* 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, 
+static int reiserfs_new_directory (struct reiserfs_transaction_handle *th, struct inode *inode,
 				   struct item_head * ih, struct path * path, const struct inode * dir)
 {
     struct super_block * sb = th->t_super;
@@ -1108,13 +1115,14 @@
     }
 
     /* 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)
 {
@@ -1144,7 +1152,7 @@
     }
 
     /* 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);
 }
 
 
@@ -1221,7 +1229,6 @@
 
     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->u.reiserfs_i.i_first_direct_byte = S_ISLNK(mode) ? 1 : 
       U32_MAX/*NO_BYTES_IN_DIRECT_ITEM*/;
 
@@ -1235,6 +1242,16 @@
     inode->i_blksize = PAGE_SIZE;
     inode->i_dev = sb->s_dev;
   
+     // initialize quotas in inode
+     DQUOT_INIT(inode);
+     if (DQUOT_ALLOC_INODE(inode->i_sb, inode)) {
+	DQUOT_DROP(inode);	/* Drop quotas for inode so that on delete no quota will be decremented */
+	inode->i_nlink = 0;
+	iput(inode);
+	*err = -EDQUOT;
+	reiserfs_check_path(&path_to_key);
+	return NULL;
+     }
     // store in in-core inode the key of stat data and version all
     // object items will have (directory items will have old offset
     // format, other new objects will consist of new items)
@@ -1245,7 +1262,7 @@
 	inode_items_version (inode) = ITEM_VERSION_2;
 
     /* insert the stat data into the tree */
-    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) {
 	iput (inode);
 	*err = retval;
@@ -1255,14 +1272,14 @@
 
     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) {
       inode->i_nlink = 0;
--- fs/reiserfs/stree.c	Tue Aug 29 01:58:06 2000
+++ fs/reiserfs/stree.c	Tue Aug 29 11:14:49 2000
@@ -60,6 +60,7 @@
 #include <linux/pagemap.h>
 #include <linux/reiserfs_fs.h>
 #include <linux/smp_lock.h>
+#include <linux/quotaops.h>
 
 #else
 
@@ -1237,8 +1238,7 @@
 		*p_n_unfm_pointer = 0;
 		journal_mark_dirty (th, p_s_sb, p_s_bh);
 		bforget (p_s_un_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 ;
@@ -1373,12 +1373,39 @@
 	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. */
 			  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 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;
@@ -1458,6 +1485,11 @@
 	       B_I_PITEM(PATH_PLAST_BUFFER(p_s_path), &s_ih), n_ret_value);
 
     }
+    inode_sub_bytes(p_s_inode, s_ih.ih_item_len);
+#ifdef REISERQUOTA_DEBUG
+    printk(KERN_DEBUG "reiserquota delete_item(): freeing %u, id=%u type=%c\n", s_ih.ih_item_len, p_s_inode->i_uid, head2type(&s_ih));
+#endif
+    DQUOT_FREE_SPACE(p_s_inode->i_sb, p_s_inode, s_ih.ih_item_len);
 
     /* Perform balancing after all resources have been collected at once. */ 
     do_balance(&s_del_balance, NULL, NULL, M_DELETE);
@@ -1503,11 +1535,12 @@
 
 /* this deletes item which never gets split */
 static 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;	/* Just to prevent bad gcc warning */
     int tb_init = 0 ;
     struct cpu_key cpu_key;
     int retval;
@@ -1538,6 +1571,11 @@
 	    continue;
 
 	if (retval == CARRY_ON) {
+#ifdef REISERQUOTA_DEBUG
+	    printk(KERN_DEBUG "reiserquota delete_solid_item(): freeing %u id=%u type=%c\n", item_len, inode->i_uid, key2type(key));
+#endif
+	    inode_sub_bytes(inode, item_len);
+	    DQUOT_FREE_SPACE(inode->i_sb, inode, item_len);
 	    do_balance (&tb, 0, 0, M_DELETE);
 	    break;
 	}
@@ -1569,7 +1607,7 @@
         reiserfs_warning("clm-4001: deleting inode with link count==%d\n", inode->i_nlink) ;
     }
 #endif
-    reiserfs_delete_solid_item (th, INODE_PKEY (inode));
+    reiserfs_delete_solid_item (th, inode, INODE_PKEY (inode));
 }
 
 
@@ -1758,6 +1796,15 @@
 	n_ret_value = calc_deleted_bytes_number(&s_cut_balance, c_mode);
     else
 	n_ret_value = retval2;
+
+    {	/* Update quotas and used space */
+	struct item_head *ih = PATH_PITEM_HEAD(s_cut_balance.tb_path);
+	inode_sub_bytes(p_s_inode, c_mode == M_DELETE ? ih->ih_item_len : -s_cut_balance.insert_size[0]);
+#ifdef REISERQUOTA_DEBUG
+	printk(KERN_DEBUG "reiserquota cut_from_item(): freeing %u id=%u type=%c\n", c_mode == M_DELETE ? ih->ih_item_len : -s_cut_balance.insert_size[0], p_s_inode->i_uid, head2type(ih));
+#endif
+	DQUOT_FREE_SPACE(p_s_inode->i_sb, p_s_inode, c_mode == M_DELETE ? ih->ih_item_len : -s_cut_balance.insert_size[0]);
+    }
     
     if ( c_mode == M_DELETE ) {
 	struct item_head * p_le_ih = PATH_PITEM_HEAD (s_cut_balance.tb_path);
@@ -1767,10 +1814,8 @@
                item(s) */
 	    // FIXME: this is to keep 3.5 happy
 	    p_s_inode->u.reiserfs_i.i_first_direct_byte = U32_MAX;
-	    p_s_inode->i_blocks -= p_s_sb->s_blocksize / 512;
 	}
     }
-
 #ifdef CONFIG_REISERFS_CHECK
     if (n_is_inode_locked) {
 	struct item_head * le_ih = PATH_PITEM_HEAD (s_cut_balance.tb_path);
@@ -1817,7 +1862,7 @@
 
     set_le_key_k_offset (ITEM_VERSION_1, INODE_PKEY (inode), DOT_OFFSET);
     set_le_key_k_type (ITEM_VERSION_1, INODE_PKEY (inode), TYPE_DIRENTRY);
-    reiserfs_delete_solid_item (th, INODE_PKEY (inode));
+    reiserfs_delete_solid_item (th, inode, INODE_PKEY (inode));
 
     set_le_key_k_offset (ITEM_VERSION_1, INODE_PKEY (inode), SD_OFFSET);
     set_le_key_k_type (ITEM_VERSION_1, INODE_PKEY (inode), TYPE_STAT_DATA);    
@@ -1991,6 +2036,7 @@
 int reiserfs_paste_into_item (struct reiserfs_transaction_handle *th, 
 			      struct path         * p_s_search_path,	/* Path to the pasted item.          */
 			      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.             */
 {
@@ -2014,6 +2060,15 @@
 	check_research_for_paste (p_s_search_path, p_s_key);
 #endif
     }
+    if (retval == CARRY_ON) {
+#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(inode->i_sb, inode, n_pasted_size))
+	    retval = QUOTA_EXCEEDED;
+	else
+	    inode_add_bytes(inode, n_pasted_size);
+    }
 
     /* Perform balancing after all resources are collected by fix_nodes, and
        accessing them will not risk triggering schedule. */
@@ -2023,7 +2078,14 @@
     }
 
     unfix_nodes(&s_paste_balance);
-    return (retval == NO_DISK_SPACE) ? -ENOSPC : -EIO;
+    switch (retval) {
+	case NO_DISK_SPACE:
+	   return -ENOSPC;
+	case QUOTA_EXCEEDED:
+	    return -EDQUOT;
+	default:
+	    return -EIO;
+   }
 }
 
 
@@ -2032,6 +2094,7 @@
 			 struct path         * 	p_s_path,         /* Path to the inserteded item.         */
 			 struct cpu_key      * key,
 			 struct item_head    * 	p_s_ih,           /* Pointer to the item header to insert.*/
+			 struct inode	     * inode,		  /* Inode item belongs to */
 			 const char          * 	p_c_body)         /* Pointer to the bytes to insert.      */
 {
     struct tree_balance s_ins_balance;
@@ -2058,6 +2121,16 @@
 	    return -EEXIST;
 	}
     }
+ 
+    if (retval == CARRY_ON) {
+#ifdef REISERQUOTA_DEBUG
+	printk(KERN_DEBUG "reiserquota insert_item(): allocating %u id=%u type=%c\n", p_s_ih->ih_item_len, inode->i_uid, head2type(p_s_ih));
+#endif
+	if (DQUOT_ALLOC_SPACE(inode->i_sb, inode, p_s_ih->ih_item_len))
+	    retval = QUOTA_EXCEEDED;
+	else
+	    inode_add_bytes(inode, p_s_ih->ih_item_len);
+    }
 
     /* make balancing after all resources will be collected at a time */ 
     if ( retval == CARRY_ON ) {
@@ -2066,7 +2139,14 @@
     }
 
     unfix_nodes(&s_ins_balance);
-    return (retval == NO_DISK_SPACE) ? -ENOSPC : -EIO;
+    switch (retval) {
+	case NO_DISK_SPACE:
+	   return -ENOSPC;
+	case QUOTA_EXCEEDED:
+	    return -EDQUOT;
+	default:
+	    return -EIO;
+   }
 }
 
 
--- fs/reiserfs/namei.c	Tue Aug 29 01:58:06 2000
+++ fs/reiserfs/namei.c	Tue Aug 29 03:15:14 2000
@@ -7,6 +7,7 @@
 #include <linux/sched.h>
 #include <linux/reiserfs_fs.h>
 #include <linux/smp_lock.h>
+#include <linux/quotaops.h>
 
 #else
 
@@ -460,7 +461,7 @@
     }
   
     /* 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) {
@@ -469,7 +470,6 @@
     }
 
     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
@@ -714,6 +714,7 @@
     if (retval < 0)
 	goto end_rmdir;
 
+    DQUOT_INIT(inode);	/* init quotas on deleted directory - it will be truncated... */
     if (inode->i_nlink != 2)
 	printk ("reiserfs_rmdir: empty directory has nlink != 2 (%d)\n", inode->i_nlink);
 
@@ -723,7 +724,6 @@
 
     dir->i_nlink --;
     dir->i_size -= (DEH_SIZE + de.de_entrylen);
-    dir->i_blocks = ((dir->i_size + 511) >> 9);
     reiserfs_update_sd (&th, dir);
 
     pop_journal_writer(windex) ;
@@ -786,12 +786,12 @@
     if (retval < 0)
 	goto end_unlink;
 
+    DQUOT_INIT(inode);	/* Initialize quotas - inode might be truncated... */
     inode->i_nlink--;
     inode->i_ctime = CURRENT_TIME;
     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);
 
@@ -1043,6 +1043,8 @@
 	    return -EMLINK;
     }
 
+    if (new_inode)
+	DQUOT_INIT(new_inode);	/* Initialize quotas on inode - it will be unlinked */
 
     journal_begin(&th, old_dir->i_sb, jbegin_count) ;
     windex = push_journal_writer("reiserfs_rename") ;
@@ -1169,7 +1171,6 @@
 	reiserfs_warning ("vs-: reiserfs_rename: coudl 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);
--- fs/reiserfs/super.c	Tue Aug 29 01:58:06 2000
+++ fs/reiserfs/super.c	Tue Aug 29 03:17:06 2000
@@ -173,7 +173,7 @@
 	  	printk("reiserfs: hash option requires a value\n");
 		return 0 ;
 	    }
-	} else {
+ 	} else if (strcmp (this_char, "usrquota") && strcmp (this_char, "grpquota")) {	/* Ignore quota options */
 	    printk ("reiserfs: Unrecognized mount option %s\n", this_char);
 	    return 0;
 	}
--- fs/reiserfs/tail_conversion.c	Tue Aug 29 01:58:06 2000
+++ fs/reiserfs/tail_conversion.c	Tue Aug 29 03:23:17 2000
@@ -75,11 +75,11 @@
 	set_ih_free_space (&ind_ih, 0); /* delete at nearest future */
 	ind_ih.ih_item_len = cpu_to_le16 (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 ) {
@@ -280,7 +280,7 @@
     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
@@ -308,7 +308,6 @@
 
     /* 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 */
--- fs/reiserfs/ioctl.c	Tue Aug 29 03:39:03 2000
+++ fs/reiserfs/ioctl.c	Tue Aug 29 03:38:23 2000
@@ -76,7 +76,7 @@
 	    unsigned long tmp = unbh->b_blocknr;
 	    bforget (unbh);
 	    /* free what has been allocated by get_new_buffer */
-	    reiserfs_free_block (&th, tmp);
+	    reiserfs_free_block (&th, inode, tmp, 1);
 	}
     } else {    
 	ih = get_ih (&path);
@@ -85,11 +85,14 @@
 	    bh = get_bh (&path);
 	    /* allocate new unformatted node to place tail */
 	    if (!unbh) {
-		retval = get_new_buffer (&th, bh, &unbh, &path);
+		retval = get_new_buffer (&th, inode, bh, &unbh, &path);
 		if (!unbh) {
 		    /* can't allocate block */
 		    pathrelse (&path);
-		    exitcode = -ENOSPC;
+		    if (retval == QUOTA_EXCEEDED)
+			exitcode = -EDQUOT;
+		    else
+			exitcode = -ENOSPC;
 		    goto finish;
 		}
 		if (retval & SCHEDULE_OCCURRED) {
@@ -108,7 +111,7 @@
 		unsigned long tmp = unbh->b_blocknr;
 		bforget (unbh);
 		/* free what has been allocated by get_new_buffer */
-		reiserfs_free_block (&th, tmp);
+		reiserfs_free_block (&th, inode, tmp, 1);
 		inode->u.reiserfs_i.nopack = 0;
 		exitcode = -ENOSPC; /* FIXME: what error has to be returned here? -az */
 		goto finish;
--- include/linux/reiserfs_fs.h	Tue Aug 29 01:58:07 2000
+++ include/linux/reiserfs_fs.h	Tue Aug 29 03:08:17 2000
@@ -130,6 +130,7 @@
 #define NO_DISK_SPACE -3
 #define NO_BALANCING_NEEDED  (-4)
 #define NO_MORE_UNUSED_CONTIGUOUS_BLOCKS (-5)
+#define QUOTA_EXCEEDED -6
 
 //#define SCHEDULE_OCCURRED  	1
 //#define PATH_INCORRECT    	2
@@ -1636,11 +1637,14 @@
 int reiserfs_insert_item (struct reiserfs_transaction_handle *th, 
 			  struct path * path, 
 			  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,
 			      struct cpu_key * key,
+			      struct inode *inode,
 			      const char * body, int paste_size);
 
 int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th,
@@ -1815,7 +1819,7 @@
 extern struct inode_operations reiserfs_file_inode_operations;
 extern struct file_operations reiserfs_file_operations;
 extern struct address_space_operations reiserfs_address_space_operations ;
-int get_new_buffer (struct reiserfs_transaction_handle *th, struct buffer_head *,
+int get_new_buffer (struct reiserfs_transaction_handle *th, struct inode *, struct buffer_head *,
 		    struct buffer_head **, struct path *);
 
 
@@ -1894,10 +1898,11 @@
 
 /* bitmap.c */
 int is_reusable (struct super_block * s, unsigned long block, int bit_value);
-void reiserfs_free_block (struct reiserfs_transaction_handle *th, unsigned long);
+void reiserfs_free_block (struct reiserfs_transaction_handle *th, struct inode *inode, unsigned long, int);
 int reiserfs_new_blocknrs (struct reiserfs_transaction_handle *th,
 			   unsigned long * pblocknrs, unsigned long start_from, int amount_needed);
 int reiserfs_new_unf_blocknrs (struct reiserfs_transaction_handle *th,
+			       struct inode *inode,
 			       unsigned long * pblocknr, unsigned long start_from);
 #ifdef REISERFS_PREALLOCATE
 int reiserfs_new_unf_blocknrs2 (struct reiserfs_transaction_handle *th, 
