? patches/bug15018_quota_fix
Index: Documentation/filesystems/Locking
===================================================================
RCS file: /cvs/projects/linux-2.6.32/Documentation/filesystems/Locking,v
retrieving revision 1.1.1.1
diff -b -u -r1.1.1.1 Locking
--- Documentation/filesystems/Locking	15 Apr 2010 12:28:21 -0000	1.1.1.1
+++ Documentation/filesystems/Locking	29 Jun 2010 07:49:25 -0000
@@ -462,9 +462,7 @@
 prototypes:
 	int (*initialize) (struct inode *, int);
 	int (*drop) (struct inode *);
-	int (*alloc_space) (struct inode *, qsize_t, int);
 	int (*alloc_inode) (const struct inode *, unsigned long);
-	int (*free_space) (struct inode *, qsize_t);
 	int (*free_inode) (const struct inode *, unsigned long);
 	int (*transfer) (struct inode *, struct iattr *);
 	int (*write_dquot) (struct dquot *);
@@ -481,9 +479,7 @@
 		FS recursion	Held locks when called
 initialize:	yes		maybe dqonoff_sem
 drop:		yes		-
-alloc_space:	->mark_dirty()	-
 alloc_inode:	->mark_dirty()	-
-free_space:	->mark_dirty()	-
 free_inode:	->mark_dirty()	-
 transfer:	yes		-
 write_dquot:	yes		dqonoff_sem or dqptr_sem
@@ -495,7 +491,7 @@
 FS recursion means calling ->quota_read() and ->quota_write() from superblock
 operations.
 
-->alloc_space(), ->alloc_inode(), ->free_space(), ->free_inode() are called
+->alloc_inode(), ->free_inode() are called
 only directly by the filesystem and do not call any fs functions only
 the ->mark_dirty() operation.
 
Index: fs/ext2/balloc.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/ext2/balloc.c,v
retrieving revision 1.1.1.1
diff -b -u -r1.1.1.1 balloc.c
--- fs/ext2/balloc.c	15 Apr 2010 12:28:24 -0000	1.1.1.1
+++ fs/ext2/balloc.c	29 Jun 2010 07:49:28 -0000
@@ -570,7 +570,11 @@
 error_return:
 	brelse(bitmap_bh);
 	release_blocks(sb, freed);
+#ifdef SYNO_DQUOT_UPGRADE
+	dquot_free_block(inode, freed);
+#else
 	vfs_dq_free_block(inode, freed);
+#endif
 }
 
 /**
@@ -1236,6 +1240,9 @@
 	unsigned short windowsz = 0;
 	unsigned long ngroups;
 	unsigned long num = *count;
+#ifdef SYNO_DQUOT_UPGRADE
+	int ret;
+#endif
 
 	*errp = -ENOSPC;
 	sb = inode->i_sb;
@@ -1247,8 +1254,14 @@
 	/*
 	 * Check quota for allocation of this block.
 	 */
+#ifdef SYNO_DQUOT_UPGRADE
+	ret = dquot_alloc_block(inode, num);
+	if (ret) {
+		*errp = ret;
+#else
 	if (vfs_dq_alloc_block(inode, num)) {
 		*errp = -EDQUOT;
+#endif
 		return 0;
 	}
 
@@ -1409,7 +1422,11 @@
 
 	*errp = 0;
 	brelse(bitmap_bh);
+#ifdef SYNO_DQUOT_UPGRADE
+	dquot_free_block(inode, *count-num);
+#else
 	vfs_dq_free_block(inode, *count-num);
+#endif
 	*count = num;
 	return ret_block;
 
@@ -1420,7 +1437,11 @@
 	 * Undo the block allocation
 	 */
 	if (!performed_allocation)
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_block(inode, *count);
+#else
 		vfs_dq_free_block(inode, *count);
+#endif
 	brelse(bitmap_bh);
 	return 0;
 }
Index: fs/ext2/xattr.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/ext2/xattr.c,v
retrieving revision 1.1.1.1
diff -b -u -r1.1.1.1 xattr.c
--- fs/ext2/xattr.c	15 Apr 2010 12:28:24 -0000	1.1.1.1
+++ fs/ext2/xattr.c	29 Jun 2010 07:49:28 -0000
@@ -640,9 +640,13 @@
 				/* The old block is released after updating
 				   the inode.  */
 				ea_bdebug(new_bh, "reusing block");
-
+#ifdef SYNO_DQUOT_UPGRADE
+				error = dquot_alloc_block(inode, 1);
+				if (error) {
+#else
 				error = -EDQUOT;
 				if (vfs_dq_alloc_block(inode, 1)) {
+#endif
 					unlock_buffer(new_bh);
 					goto cleanup;
 				}
@@ -699,7 +703,11 @@
 		 * as if nothing happened and cleanup the unused block */
 		if (error && error != -ENOSPC) {
 			if (new_bh && new_bh != old_bh)
+#ifdef SYNO_DQUOT_UPGRADE
+				dquot_free_block(inode, 1);
+#else
 				vfs_dq_free_block(inode, 1);
+#endif
 			goto cleanup;
 		}
 	} else
@@ -731,7 +739,11 @@
 			le32_add_cpu(&HDR(old_bh)->h_refcount, -1);
 			if (ce)
 				mb_cache_entry_release(ce);
+#ifdef SYNO_DQUOT_UPGRADE
+			dquot_free_block(inode, 1);
+#else
 			vfs_dq_free_block(inode, 1);
+#endif
 			mark_buffer_dirty(old_bh);
 			ea_bdebug(old_bh, "refcount now=%d",
 				le32_to_cpu(HDR(old_bh)->h_refcount));
@@ -794,7 +806,11 @@
 		mark_buffer_dirty(bh);
 		if (IS_SYNC(inode))
 			sync_dirty_buffer(bh);
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_block(inode, 1);
+#else
 		vfs_dq_free_block(inode, 1);
+#endif
 	}
 	EXT2_I(inode)->i_file_acl = 0;
 
Index: fs/ext3/balloc.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/ext3/balloc.c,v
retrieving revision 1.2
diff -b -u -r1.2 balloc.c
--- fs/ext3/balloc.c	15 Apr 2010 15:13:35 -0000	1.2
+++ fs/ext3/balloc.c	29 Jun 2010 07:49:28 -0000
@@ -679,7 +679,11 @@
 	}
 	ext3_free_blocks_sb(handle, sb, block, count, &dquot_freed_blocks);
 	if (dquot_freed_blocks)
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_block(inode, dquot_freed_blocks);
+#else
 		vfs_dq_free_block(inode, dquot_freed_blocks);
+#endif
 	return;
 }
 
@@ -1505,8 +1509,14 @@
 	/*
 	 * Check quota for allocation of this block.
 	 */
+#ifdef SYNO_DQUOT_UPGRADE
+	err = dquot_alloc_block(inode, num);
+	if (err) {
+		*errp = err;
+#else
 	if (vfs_dq_alloc_block(inode, num)) {
 		*errp = -EDQUOT;
+#endif
 		return 0;
 	}
 
@@ -1719,7 +1729,11 @@
 
 	*errp = 0;
 	brelse(bitmap_bh);
+#ifdef SYNO_DQUOT_UPGRADE
+	dquot_free_block(inode, *count-num);
+#else
 	vfs_dq_free_block(inode, *count-num);
+#endif
 	*count = num;
 	return ret_block;
 
@@ -1734,7 +1748,11 @@
 	 * Undo the block allocation
 	 */
 	if (!performed_allocation)
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_block(inode, *count);
+#else
 		vfs_dq_free_block(inode, *count);
+#endif
 	brelse(bitmap_bh);
 	return 0;
 }
Index: fs/ext3/inode.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/ext3/inode.c,v
retrieving revision 1.3
diff -b -u -r1.3 inode.c
--- fs/ext3/inode.c	3 May 2010 13:19:17 -0000	1.3
+++ fs/ext3/inode.c	29 Jun 2010 07:49:28 -0000
@@ -3492,7 +3492,7 @@
  * i_size has been changed by generic_commit_write() and we thus need
  * to include the updated inode in the current transaction.
  *
- * Also, vfs_dq_alloc_space() will always dirty the inode when blocks
+ * Also, dquot_alloc_space() will always dirty the inode when blocks
  * are allocated to the file.
  *
  * If the inode is marked synchronous, we don't honour that here - doing
Index: fs/ext3/super.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/ext3/super.c,v
retrieving revision 1.3
diff -b -u -r1.3 super.c
--- fs/ext3/super.c	3 May 2010 13:19:17 -0000	1.3
+++ fs/ext3/super.c	29 Jun 2010 07:49:28 -0000
@@ -746,9 +746,13 @@
 static const struct dquot_operations ext3_quota_operations = {
 	.initialize	= dquot_initialize,
 	.drop		= dquot_drop,
+#ifndef SYNO_DQUOT_UPGRADE
 	.alloc_space	= dquot_alloc_space,
+#endif
 	.alloc_inode	= dquot_alloc_inode,
+#ifndef SYNO_DQUOT_UPGRADE
 	.free_space	= dquot_free_space,
+#endif
 	.free_inode	= dquot_free_inode,
 	.transfer	= dquot_transfer,
 	.write_dquot	= ext3_write_dquot,
Index: fs/ext3/xattr.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/ext3/xattr.c,v
retrieving revision 1.2
diff -b -u -r1.2 xattr.c
--- fs/ext3/xattr.c	3 May 2010 13:19:17 -0000	1.2
+++ fs/ext3/xattr.c	29 Jun 2010 07:49:28 -0000
@@ -497,7 +497,11 @@
 		error = ext3_journal_dirty_metadata(handle, bh);
 		if (IS_SYNC(inode))
 			handle->h_sync = 1;
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_block(inode, 1);
+#else
 		vfs_dq_free_block(inode, 1);
+#endif
 		ea_bdebug(bh, "refcount now=%d; releasing",
 			  le32_to_cpu(BHDR(bh)->h_refcount));
 		if (ce)
@@ -772,8 +776,13 @@
 			else {
 				/* The old block is released after updating
 				   the inode. */
+#ifdef SYNO_DQUOT_UPGRADE
+				error = dquot_alloc_block(inode, 1);
+				if (error)
+#else
 				error = -EDQUOT;
 				if (vfs_dq_alloc_block(inode, 1))
+#endif
 					goto cleanup;
 				error = ext3_journal_get_write_access(handle,
 								      new_bh);
@@ -847,7 +856,11 @@
 	return error;
 
 cleanup_dquot:
+#ifdef SYNO_DQUOT_UPGRADE
+	dquot_free_block(inode, 1);
+#else
 	vfs_dq_free_block(inode, 1);
+#endif
 	goto cleanup;
 
 bad_block:
Index: fs/ext4/balloc.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/ext4/balloc.c,v
retrieving revision 1.3
diff -b -u -r1.3 balloc.c
--- fs/ext4/balloc.c	3 May 2010 13:19:17 -0000	1.3
+++ fs/ext4/balloc.c	29 Jun 2010 07:49:28 -0000
@@ -501,6 +501,7 @@
 	return;
 }
 
+#ifndef SYNO_DQUOT_UPGRADE
 /**
  * ext4_free_blocks() -- Free given blocks and update quota
  * @handle:		handle for this transaction
@@ -538,6 +539,7 @@
 		vfs_dq_free_block(inode, dquot_freed_blocks);
 	return;
 }
+#endif
 
 /**
  * ext4_has_free_blocks()
@@ -645,14 +647,17 @@
 	ret = ext4_mb_new_blocks(handle, &ar, errp);
 	if (count)
 		*count = ar.len;
-
 	/*
-	 * Account for the allocated meta blocks
+	 * Account for the allocated meta blocks.  We will never
+	 * fail EDQUOT for metdata, but we do account for it.
 	 */
 	if (!(*errp) && EXT4_I(inode)->i_delalloc_reserved_flag) {
 		spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
 		EXT4_I(inode)->i_allocated_meta_blocks += ar.len;
 		spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_alloc_block_nofail(inode, ar.len);
+#endif
 	}
 	return ret;
 }
Index: fs/ext4/ext4.h
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/ext4/ext4.h,v
retrieving revision 1.5
diff -b -u -r1.5 ext4.h
--- fs/ext4/ext4.h	16 Jun 2010 09:23:16 -0000	1.5
+++ fs/ext4/ext4.h	29 Jun 2010 07:49:28 -0000
@@ -1471,8 +1471,10 @@
 			ext4_fsblk_t goal, unsigned long *count, int *errp);
 extern int ext4_claim_free_blocks(struct ext4_sb_info *sbi, s64 nblocks);
 extern int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks);
+#ifndef SYNO_DQUOT_UPGRADE
 extern void ext4_free_blocks(handle_t *handle, struct inode *inode,
 			ext4_fsblk_t block, unsigned long count, int metadata);
+#endif
 extern void ext4_add_groupblocks(handle_t *handle, struct super_block *sb,
 				ext4_fsblk_t block, unsigned long count);
 extern ext4_fsblk_t ext4_count_free_blocks(struct super_block *);
@@ -1531,8 +1533,14 @@
 extern void ext4_discard_preallocations(struct inode *);
 extern int __init init_ext4_mballoc(void);
 extern void exit_ext4_mballoc(void);
+#ifdef SYNO_DQUOT_UPGRADE
+extern void ext4_free_blocks(handle_t *handle, struct inode *inode,
+			     ext4_fsblk_t block, unsigned long count,
+			     int metadata);
+#else
 extern void ext4_mb_free_blocks(handle_t *, struct inode *,
 		ext4_fsblk_t, unsigned long, int, unsigned long *);
+#endif
 extern int ext4_mb_add_groupinfo(struct super_block *sb,
 		ext4_group_t i, struct ext4_group_desc *desc);
 extern int ext4_mb_get_buddy_cache_lock(struct super_block *, ext4_group_t);
Index: fs/ext4/inode.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/ext4/inode.c,v
retrieving revision 1.8
diff -b -u -r1.8 inode.c
--- fs/ext4/inode.c	26 Jun 2010 08:02:15 -0000	1.8
+++ fs/ext4/inode.c	29 Jun 2010 07:49:28 -0000
@@ -1105,7 +1105,9 @@
 {
 	struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
 	struct ext4_inode_info *ei = EXT4_I(inode);
+#ifndef SYNO_DQUOT_UPGRADE
 	int mdb_free = 0, allocated_meta_blocks = 0;
+#endif
 
 	spin_lock(&ei->i_block_reservation_lock);
 	if (unlikely(used > ei->i_reserved_data_blocks)) {
@@ -1119,11 +1121,20 @@
 
 	/* Update per-inode reservations */
 	ei->i_reserved_data_blocks -= used;
+#ifndef SYNO_DQUOT_UPGRADE
 	used += ei->i_allocated_meta_blocks;
+#endif
 	ei->i_reserved_meta_blocks -= ei->i_allocated_meta_blocks;
+#ifdef SYNO_DQUOT_UPGRADE
+	percpu_counter_sub(&sbi->s_dirtyblocks_counter,
+			   used + ei->i_allocated_meta_blocks);
+#else
 	allocated_meta_blocks = ei->i_allocated_meta_blocks;
+#endif
 	ei->i_allocated_meta_blocks = 0;
+#ifndef SYNO_DQUOT_UPGRADE
 	percpu_counter_sub(&sbi->s_dirtyblocks_counter, used);
+#endif
 
 	if (ei->i_reserved_data_blocks == 0) {
 		/*
@@ -1131,31 +1142,46 @@
 		 * only when we have written all of the delayed
 		 * allocation blocks.
 		 */
+#ifdef SYNO_DQUOT_UPGRADE
+		percpu_counter_sub(&sbi->s_dirtyblocks_counter,
+				   ei->i_reserved_meta_blocks);
+#else
 		mdb_free = ei->i_reserved_meta_blocks;
+#endif
 		ei->i_reserved_meta_blocks = 0;
 		ei->i_da_metadata_calc_len = 0;
+#ifndef SYNO_DQUOT_UPGRADE
 		percpu_counter_sub(&sbi->s_dirtyblocks_counter, mdb_free);
+#endif
 	}
 	spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
 
+#ifdef SYNO_DQUOT_UPGRADE
+	/* Update quota subsystem for data blocks */
+	if (quota_claim)
+		dquot_claim_block(inode, used);
+	else {
+#else
 	/* Update quota subsystem */
 	if (quota_claim) {
 		vfs_dq_claim_block(inode, used);
 		if (mdb_free)
 			vfs_dq_release_reservation_block(inode, mdb_free);
 	} else {
+#endif
 		/*
 		 * We did fallocate with an offset that is already delayed
 		 * allocated. So on delayed allocated writeback we should
-		 * not update the quota for allocated blocks. But then
-		 * converting an fallocate region to initialized region would
-		 * have caused a metadata allocation. So claim quota for
-		 * that
+		 * not re-claim the quota for fallocated blocks.
 		 */
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_release_reservation_block(inode, used);
+#else
 		if (allocated_meta_blocks)
 			vfs_dq_claim_block(inode, allocated_meta_blocks);
 		vfs_dq_release_reservation_block(inode, mdb_free + used -
 						allocated_meta_blocks);
+#endif
 	}
 
 	/*
@@ -1883,7 +1909,12 @@
 	int retries = 0;
 	struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
 	struct ext4_inode_info *ei = EXT4_I(inode);
+#ifdef SYNO_DQUOT_UPGRADE
+	unsigned long md_needed;
+	int ret;
+#else
 	unsigned long md_needed, md_reserved;
+#endif
 
 	/*
 	 * recalculate the amount of metadata blocks to reserve
@@ -1892,20 +1923,36 @@
 	 */
 repeat:
 	spin_lock(&ei->i_block_reservation_lock);                                                   
+#ifndef SYNO_DQUOT_UPGRADE
 	md_reserved = ei->i_reserved_meta_blocks;                                                   
+#endif
 	md_needed = ext4_calc_metadata_amount(inode, lblock);
 	spin_unlock(&ei->i_block_reservation_lock);   
 
 	/*
-	 * Make quota reservation here to prevent quota overflow
-	 * later. Real quota accounting is done at pages writeout
-	 * time.
+	 * We will charge metadata quota at writeout time; this saves
+	 * us from metadata over-estimation, though we may go over by
+	 * a small amount in the end.  Here we just reserve for data.
 	 */
+#ifdef SYNO_DQUOT_UPGRADE
+	ret = dquot_reserve_block(inode, 1);
+	if (ret)
+		return ret;
+#endif
+	/*
+	 * We do still charge estimated metadata to the sb though;
+	 * we cannot afford to run out of free blocks.
+	 */
+#ifndef SYNO_DQUOT_UPGRADE
 	if (vfs_dq_reserve_block(inode, md_needed + 1))
 			return -EDQUOT;                                                                     
-
+#endif
 	if (ext4_claim_free_blocks(sbi, md_needed + 1)) {
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_release_reservation_block(inode, 1);
+#else
 		vfs_dq_release_reservation_block(inode, md_needed + 1);
+#endif
 		if (ext4_should_retry_alloc(inode->i_sb, &retries)) {
 			yield();
 			goto repeat;
@@ -1952,17 +1999,26 @@
 		 * only when we have written all of the delayed
 		 * allocation blocks.
 		 */
+#ifdef SYNO_DQUOT_UPGRADE
+		percpu_counter_sub(&sbi->s_dirtyblocks_counter,
+				   ei->i_reserved_meta_blocks);
+#else
 		to_free += ei->i_reserved_meta_blocks;
+#endif
 		ei->i_reserved_meta_blocks = 0;
 		ei->i_da_metadata_calc_len = 0;
 	}
 
-	/* update fs dirty blocks counter */
+	/* update fs dirty data blocks counter */
 	percpu_counter_sub(&sbi->s_dirtyblocks_counter, to_free);
 
 	spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
 
+#ifdef SYNO_DQUOT_UPGRADE
+	dquot_release_reservation_block(inode, to_free);
+#else
 	vfs_dq_release_reservation_block(inode, to_free);
+#endif
 }
 
 static void ext4_da_page_release_reservation(struct page *page,
@@ -3097,7 +3153,11 @@
 			       loff_t pos, unsigned len, unsigned flags,
 			       struct page **pagep, void **fsdata)
 {
+#ifdef SYNO_DQUOT_UPGRADE
+	int ret, retries = 0;
+#else
 	int ret, retries = 0, quota_retries = 0;
+#endif
 	struct page *page;
 	pgoff_t index;
 	unsigned from, to;
@@ -3158,6 +3218,7 @@
 	if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
 		goto retry;
 
+#ifndef SYNO_DQUOT_UPGRADE
 	if ((ret == -EDQUOT) &&
 	    EXT4_I(inode)->i_reserved_meta_blocks &&
 	    (quota_retries++ < 3)) {
@@ -3168,11 +3229,12 @@
 		 * be enough space once we write the data blocks and
 		 * find out how many meta data blocks were _really_
 		 * required.  So try forcing the inode write to see if
-		 * that helps.
+		* that helps
 		 */
 		write_inode_now(inode, (quota_retries == 3));
 		goto retry;
 	}
+#endif
 out:
 	return ret;
 }
@@ -5785,7 +5847,7 @@
  * i_size has been changed by generic_commit_write() and we thus need
  * to include the updated inode in the current transaction.
  *
- * Also, vfs_dq_alloc_block() will always dirty the inode when blocks
+ * Also, dquot_alloc_block() will always dirty the inode when blocks
  * are allocated to the file.
  *
  * If the inode is marked synchronous, we don't honour that here - doing
Index: fs/ext4/mballoc.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/ext4/mballoc.c,v
retrieving revision 1.3
diff -b -u -r1.3 mballoc.c
--- fs/ext4/mballoc.c	11 Jun 2010 03:00:45 -0000	1.3
+++ fs/ext4/mballoc.c	29 Jun 2010 07:49:28 -0000
@@ -4300,7 +4300,11 @@
 			return 0;
 		}
 		reserv_blks = ar->len;
+#ifdef SYNO_DQUOT_UPGRADE
+		while (ar->len && dquot_alloc_block(ar->inode, ar->len)) {
+#else
 		while (ar->len && vfs_dq_alloc_block(ar->inode, ar->len)) {
+#endif
 			ar->flags |= EXT4_MB_HINT_NOPREALLOC;
 			ar->len--;
 		}
@@ -4377,7 +4381,11 @@
 	kmem_cache_free(ext4_ac_cachep, ac);
 out1:
 	if (inquota && ar->len < inquota)
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_block(ar->inode, inquota - ar->len);
+#else
 		vfs_dq_free_block(ar->inode, inquota - ar->len);
+#endif
 out3:
 	if (!ar->len) {
 		if (!EXT4_I(ar->inode)->i_delalloc_reserved_flag)
@@ -4486,18 +4494,32 @@
 	return 0;
 }
 
-/*
- * Main entry point into mballoc to free blocks
+/**
+ * ext4_free_blocks() -- Free given blocks and update quota
+ * @handle:		handle for this transaction
+ * @inode:		inode
+ * @block:		start physical block to free
+ * @count:		number of blocks to count
+ * @metadata: 		Are these metadata blocks
  */
+#ifdef SYNO_DQUOT_UPGRADE
+void ext4_free_blocks(handle_t *handle, struct inode *inode,
+		      ext4_fsblk_t block, unsigned long count,
+		      int metadata)
+#else
 void ext4_mb_free_blocks(handle_t *handle, struct inode *inode,
 			ext4_fsblk_t block, unsigned long count,
 			int metadata, unsigned long *freed)
+#endif
 {
 	struct buffer_head *bitmap_bh = NULL;
 	struct super_block *sb = inode->i_sb;
 	struct ext4_allocation_context *ac = NULL;
 	struct ext4_group_desc *gdp;
 	struct ext4_super_block *es;
+#ifdef SYNO_DQUOT_UPGRADE
+	unsigned long freed = 0;
+#endif
 	unsigned int overflow;
 	ext4_grpblk_t bit;
 	struct buffer_head *gd_bh;
@@ -4507,7 +4529,19 @@
 	int err = 0;
 	int ret;
 
+#ifdef SYNO_DQUOT_UPGRADE
+	/* 
+	 * We need to make sure we don't reuse the freed block until
+	 * after the transaction is committed, which we can do by
+	 * treating the block as metadata, below.  We make an
+	 * exception if the inode is to be written in writeback mode
+	 * since writeback mode has weak data consistency guarantees.
+	 */
+	if (!ext4_should_writeback_data(inode))
+		metadata = 1;
+#else
 	*freed = 0;
+#endif
 
 	sbi = EXT4_SB(sb);
 	es = EXT4_SB(sb)->s_es;
@@ -4636,7 +4670,11 @@
 
 	ext4_mb_unload_buddy(&e4b);
 
+#ifdef SYNO_DQUOT_UPGRADE
+	freed += count;
+#else
 	*freed += count;
+#endif
 
 	/* We dirtied the bitmap block */
 	BUFFER_TRACE(bitmap_bh, "dirtied bitmap block");
@@ -4656,6 +4694,10 @@
 	}
 	sb->s_dirt = 1;
 error_return:
+#ifdef SYNO_DQUOT_UPGRADE
+	if (freed)
+		dquot_free_block(inode, freed);
+#endif
 	brelse(bitmap_bh);
 	ext4_std_error(sb, err);
 	if (ac)
Index: fs/ext4/super.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/ext4/super.c,v
retrieving revision 1.6
diff -b -u -r1.6 super.c
--- fs/ext4/super.c	16 Jun 2010 09:23:16 -0000	1.6
+++ fs/ext4/super.c	29 Jun 2010 07:49:28 -0000
@@ -1035,15 +1035,19 @@
 static const struct dquot_operations ext4_quota_operations = {
 	.initialize	= dquot_initialize,
 	.drop		= dquot_drop,
+#ifndef SYNO_DQUOT_UPGRADE
 	.alloc_space	= dquot_alloc_space,
 	.reserve_space	= dquot_reserve_space,
 	.claim_space	= dquot_claim_space,
 	.release_rsv	= dquot_release_reserved_space,
+#endif
 #ifdef CONFIG_QUOTA
 	.get_reserved_space = ext4_get_reserved_space,
 #endif
 	.alloc_inode	= dquot_alloc_inode,
+#ifndef SYNO_DQUOT_UPGRADE
 	.free_space	= dquot_free_space,
+#endif
 	.free_inode	= dquot_free_inode,
 	.transfer	= dquot_transfer,
 	.write_dquot	= ext4_write_dquot,
Index: fs/ext4/xattr.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/ext4/xattr.c,v
retrieving revision 1.4
diff -b -u -r1.4 xattr.c
--- fs/ext4/xattr.c	16 Jun 2010 09:23:16 -0000	1.4
+++ fs/ext4/xattr.c	29 Jun 2010 07:49:28 -0000
@@ -494,7 +494,11 @@
 		error = ext4_handle_dirty_metadata(handle, inode, bh);
 		if (IS_SYNC(inode))
 			ext4_handle_sync(handle);
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_block(inode, 1);
+#else
 		vfs_dq_free_block(inode, 1);
+#endif
 		ea_bdebug(bh, "refcount now=%d; releasing",
 			  le32_to_cpu(BHDR(bh)->h_refcount));
 		if (ce)
@@ -787,8 +791,13 @@
 			else {
 				/* The old block is released after updating
 				   the inode. */
+#ifdef SYNO_DQUOT_UPGRADE
+				error = dquot_alloc_block(inode, 1);
+				if (error)
+#else
 				error = -EDQUOT;
 				if (vfs_dq_alloc_block(inode, 1))
+#endif
 					goto cleanup;
 				error = ext4_journal_get_write_access(handle,
 								      new_bh);
@@ -875,7 +884,11 @@
 	return error;
 
 cleanup_dquot:
+#ifdef SYNO_DQUOT_UPGRADE
+	dquot_free_block(inode, 1);
+#else
 	vfs_dq_free_block(inode, 1);
+#endif
 	goto cleanup;
 
 bad_block:
Index: fs/jfs/jfs_dtree.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/jfs/jfs_dtree.c,v
retrieving revision 1.1.1.1
diff -b -u -r1.1.1.1 jfs_dtree.c
--- fs/jfs/jfs_dtree.c	15 Apr 2010 12:28:24 -0000	1.1.1.1
+++ fs/jfs/jfs_dtree.c	29 Jun 2010 07:49:28 -0000
@@ -381,10 +381,18 @@
 		 * It's time to move the inline table to an external
 		 * page and begin to build the xtree
 		 */
+#ifdef SYNO_DQUOT_UPGRADE
+		if (dquot_alloc_block(ip, sbi->nbperpage))
+#else
 		if (vfs_dq_alloc_block(ip, sbi->nbperpage))
+#endif
 			goto clean_up;
 		if (dbAlloc(ip, 0, sbi->nbperpage, &xaddr)) {
+#ifdef SYNO_DQUOT_UPGRADE
+			dquot_free_block(ip, sbi->nbperpage);
+#else
 			vfs_dq_free_block(ip, sbi->nbperpage);
+#endif
 			goto clean_up;
 		}
 
@@ -408,7 +416,11 @@
 			memcpy(&jfs_ip->i_dirtable, temp_table,
 			       sizeof (temp_table));
 			dbFree(ip, xaddr, sbi->nbperpage);
+#ifdef SYNO_DQUOT_UPGRADE
+			dquot_free_block(ip, sbi->nbperpage);
+#else
 			vfs_dq_free_block(ip, sbi->nbperpage);
+#endif
 			goto clean_up;
 		}
 		ip->i_size = PSIZE;
@@ -1027,8 +1039,13 @@
 			n = xlen;
 
 		/* Allocate blocks to quota. */
+#ifdef SYNO_DQUOT_UPGRADE
+		rc = dquot_alloc_block(ip, n);
+		if (rc) {
+#else
 		if (vfs_dq_alloc_block(ip, n)) {
 			rc = -EDQUOT;
+#endif
 			goto extendOut;
 		}
 		quota_allocation += n;
@@ -1308,7 +1325,11 @@
 
 	/* Rollback quota allocation */
 	if (rc && quota_allocation)
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_block(ip, quota_allocation);
+#else
 		vfs_dq_free_block(ip, quota_allocation);
+#endif
 
       dtSplitUp_Exit:
 
@@ -1369,9 +1390,18 @@
 		return -EIO;
 
 	/* Allocate blocks to quota. */
+#ifdef SYNO_DQUOT_UPGRADE
+	rc = dquot_alloc_block(ip, lengthPXD(pxd));
+	if (rc) {
+#else
 	if (vfs_dq_alloc_block(ip, lengthPXD(pxd))) {
+#endif
 		release_metapage(rmp);
+#ifdef SYNO_DQUOT_UPGRADE
+		return rc;
+#else
 		return -EDQUOT;
+#endif
 	}
 
 	jfs_info("dtSplitPage: ip:0x%p smp:0x%p rmp:0x%p", ip, smp, rmp);
@@ -1892,6 +1922,9 @@
 	struct dt_lock *dtlck;
 	struct tlock *tlck;
 	struct lv *lv;
+#ifdef SYNO_DQUOT_UPGRADE
+	int rc;
+#endif
 
 	/* get split root page */
 	smp = split->mp;
@@ -1916,9 +1949,18 @@
 	rp = rmp->data;
 
 	/* Allocate blocks to quota. */
+#ifdef SYNO_DQUOT_UPGRADE
+	rc = dquot_alloc_block(ip, lengthPXD(pxd));
+	if (rc) {
+#else
 	if (vfs_dq_alloc_block(ip, lengthPXD(pxd))) {
+#endif
 		release_metapage(rmp);
+#ifdef SYNO_DQUOT_UPGRADE
+		return rc;
+#else
 		return -EDQUOT;
+#endif
 	}
 
 	BT_MARK_DIRTY(rmp, ip);
@@ -2287,7 +2329,11 @@
 	xlen = lengthPXD(&fp->header.self);
 
 	/* Free quota allocation. */
+#ifdef SYNO_DQUOT_UPGRADE
+	dquot_free_block(ip, xlen);
+#else
 	vfs_dq_free_block(ip, xlen);
+#endif
 
 	/* free/invalidate its buffer page */
 	discard_metapage(fmp);
@@ -2363,7 +2409,11 @@
 				xlen = lengthPXD(&p->header.self);
 
 				/* Free quota allocation */
+#ifdef SYNO_DQUOT_UPGRADE
+				dquot_free_block(ip, xlen);
+#else
 				vfs_dq_free_block(ip, xlen);
+#endif
 
 				/* free/invalidate its buffer page */
 				discard_metapage(mp);
Index: fs/jfs/jfs_extent.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/jfs/jfs_extent.c,v
retrieving revision 1.1.1.1
diff -b -u -r1.1.1.1 jfs_extent.c
--- fs/jfs/jfs_extent.c	15 Apr 2010 12:28:24 -0000	1.1.1.1
+++ fs/jfs/jfs_extent.c	29 Jun 2010 07:49:28 -0000
@@ -141,10 +141,19 @@
 	}
 
 	/* Allocate blocks to quota. */
+#ifdef SYNO_DQUOT_UPGRADE
+	rc = dquot_alloc_block(ip, nxlen);
+	if (rc) {
+#else
 	if (vfs_dq_alloc_block(ip, nxlen)) {
+#endif
 		dbFree(ip, nxaddr, (s64) nxlen);
 		mutex_unlock(&JFS_IP(ip)->commit_mutex);
+#ifdef SYNO_DQUOT_UPGRADE
+		return rc;
+#else
 		return -EDQUOT;
+#endif
 	}
 
 	/* determine the value of the extent flag */
@@ -164,7 +173,11 @@
 	 */
 	if (rc) {
 		dbFree(ip, nxaddr, nxlen);
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_block(ip, nxlen);
+#else
 		vfs_dq_free_block(ip, nxlen);
+#endif
 		mutex_unlock(&JFS_IP(ip)->commit_mutex);
 		return (rc);
 	}
@@ -256,10 +269,19 @@
 		goto exit;
 
 	/* Allocat blocks to quota. */
+#ifdef SYNO_DQUOT_UPGRADE
+	rc = dquot_alloc_block(ip, nxlen);
+	if (rc) {
+#else
 	if (vfs_dq_alloc_block(ip, nxlen)) {
+#endif
 		dbFree(ip, nxaddr, (s64) nxlen);
 		mutex_unlock(&JFS_IP(ip)->commit_mutex);
+#ifdef SYNO_DQUOT_UPGRADE
+		return rc;
+#else
 		return -EDQUOT;
+#endif
 	}
 
 	delta = nxlen - xlen;
@@ -297,7 +319,11 @@
 		/* extend the extent */
 		if ((rc = xtExtend(0, ip, xoff + xlen, (int) nextend, 0))) {
 			dbFree(ip, xaddr + xlen, delta);
+#ifdef SYNO_DQUOT_UPGRADE
+			dquot_free_block(ip, nxlen);
+#else
 			vfs_dq_free_block(ip, nxlen);
+#endif
 			goto exit;
 		}
 	} else {
@@ -308,7 +334,11 @@
 		 */
 		if ((rc = xtTailgate(0, ip, xoff, (int) ntail, nxaddr, 0))) {
 			dbFree(ip, nxaddr, nxlen);
+#ifdef SYNO_DQUOT_UPGRADE
+			dquot_free_block(ip, nxlen);
+#else
 			vfs_dq_free_block(ip, nxlen);
+#endif
 			goto exit;
 		}
 	}
Index: fs/jfs/jfs_xtree.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/jfs/jfs_xtree.c,v
retrieving revision 1.1.1.1
diff -b -u -r1.1.1.1 jfs_xtree.c
--- fs/jfs/jfs_xtree.c	15 Apr 2010 12:28:24 -0000	1.1.1.1
+++ fs/jfs/jfs_xtree.c	29 Jun 2010 07:49:28 -0000
@@ -585,10 +585,18 @@
 			hint = addressXAD(xad) + lengthXAD(xad) - 1;
 		} else
 			hint = 0;
+#ifdef SYNO_DQUOT_UPGRADE
+		if ((rc = dquot_alloc_block(ip, xlen)))
+#else
 		if ((rc = vfs_dq_alloc_block(ip, xlen)))
+#endif
 			goto out;
 		if ((rc = dbAlloc(ip, hint, (s64) xlen, &xaddr))) {
+#ifdef SYNO_DQUOT_UPGRADE
+			dquot_free_block(ip, xlen);
+#else
 			vfs_dq_free_block(ip, xlen);
+#endif
 			goto out;
 		}
 	}
@@ -617,7 +625,11 @@
 			/* undo data extent allocation */
 			if (*xaddrp == 0) {
 				dbFree(ip, xaddr, (s64) xlen);
+#ifdef SYNO_DQUOT_UPGRADE
+				dquot_free_block(ip, xlen);
+#else
 				vfs_dq_free_block(ip, xlen);
+#endif
 			}
 			return rc;
 		}
@@ -985,8 +997,13 @@
 	rbn = addressPXD(pxd);
 
 	/* Allocate blocks to quota. */
+#ifdef SYNO_DQUOT_UPGRADE
+	rc = dquot_alloc_block(ip, lengthPXD(pxd));
+	if (rc) {
+#else
 	if (vfs_dq_alloc_block(ip, lengthPXD(pxd))) {
 		rc = -EDQUOT;
+#endif
 		goto clean_up;
 	}
 
@@ -1195,7 +1212,11 @@
 
 	/* Rollback quota allocation. */
 	if (quota_allocation)
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_block(ip, quota_allocation);
+#else
 		vfs_dq_free_block(ip, quota_allocation);
+#endif
 
 	return (rc);
 }
@@ -1235,6 +1256,9 @@
 	struct pxdlist *pxdlist;
 	struct tlock *tlck;
 	struct xtlock *xtlck;
+#ifdef SYNO_DQUOT_UPGRADE
+	int rc;
+#endif
 
 	sp = &JFS_IP(ip)->i_xtroot;
 
@@ -1252,9 +1276,18 @@
 		return -EIO;
 
 	/* Allocate blocks to quota. */
+#ifdef SYNO_DQUOT_UPGRADE
+	rc = dquot_alloc_block(ip, lengthPXD(pxd));
+	if (rc) {
+#else
 	if (vfs_dq_alloc_block(ip, lengthPXD(pxd))) {
+#endif
 		release_metapage(rmp);
+#ifdef SYNO_DQUOT_UPGRADE
+		return rc;
+#else
 		return -EDQUOT;
+#endif
 	}
 
 	jfs_info("xtSplitRoot: ip:0x%p rmp:0x%p", ip, rmp);
@@ -3680,7 +3713,11 @@
 		ip->i_size = newsize;
 
 	/* update quota allocation to reflect freed blocks */
+#ifdef SYNO_DQUOT_UPGRADE
+	dquot_free_block(ip, nfreed);
+#else
 	vfs_dq_free_block(ip, nfreed);
+#endif
 
 	/*
 	 * free tlock of invalidated pages
Index: fs/jfs/xattr.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/jfs/xattr.c,v
retrieving revision 1.1.1.1
diff -b -u -r1.1.1.1 xattr.c
--- fs/jfs/xattr.c	15 Apr 2010 12:28:24 -0000	1.1.1.1
+++ fs/jfs/xattr.c	29 Jun 2010 07:49:28 -0000
@@ -260,14 +260,24 @@
 	nblocks = (size + (sb->s_blocksize - 1)) >> sb->s_blocksize_bits;
 
 	/* Allocate new blocks to quota. */
+#ifdef SYNO_DQUOT_UPGRADE
+	rc = dquot_alloc_block(ip, nblocks);
+	if (rc)
+		return rc;
+#else
 	if (vfs_dq_alloc_block(ip, nblocks)) {
 		return -EDQUOT;
 	}
+#endif
 
 	rc = dbAlloc(ip, INOHINT(ip), nblocks, &blkno);
 	if (rc) {
 		/*Rollback quota allocation. */
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_block(ip, nblocks);
+#else
 		vfs_dq_free_block(ip, nblocks);
+#endif
 		return rc;
 	}
 
@@ -332,7 +342,11 @@
 
       failed:
 	/* Rollback quota allocation. */
+#ifdef SYNO_DQUOT_UPGRADE
+	dquot_free_block(ip, nblocks);
+#else
 	vfs_dq_free_block(ip, nblocks);
+#endif
 
 	dbFree(ip, blkno, nblocks);
 	return rc;
@@ -538,7 +552,12 @@
 
 	if (blocks_needed > current_blocks) {
 		/* Allocate new blocks to quota. */
+#ifdef SYNO_DQUOT_UPGRADE
+		rc = dquot_alloc_block(inode, blocks_needed);
+		if (rc)
+#else
 		if (vfs_dq_alloc_block(inode, blocks_needed))
+#endif
 			return -EDQUOT;
 
 		quota_allocation = blocks_needed;
@@ -602,7 +621,11 @@
       clean_up:
 	/* Rollback quota allocation */
 	if (quota_allocation)
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_block(inode, quota_allocation);
+#else
 		vfs_dq_free_block(inode, quota_allocation);
+#endif
 
 	return (rc);
 }
@@ -677,7 +700,11 @@
 
 	/* If old blocks exist, they must be removed from quota allocation. */
 	if (old_blocks)
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_block(inode, old_blocks);
+#else
 		vfs_dq_free_block(inode, old_blocks);
+#endif
 
 	inode->i_ctime = CURRENT_TIME;
 
Index: fs/ocfs2/alloc.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/ocfs2/alloc.c,v
retrieving revision 1.1.1.1
diff -b -u -r1.1.1.1 alloc.c
--- fs/ocfs2/alloc.c	15 Apr 2010 12:28:24 -0000	1.1.1.1
+++ fs/ocfs2/alloc.c	29 Jun 2010 07:49:28 -0000
@@ -5712,7 +5712,11 @@
 		goto out;
 	}
 
+#ifdef SYNO_DQUOT_UPGRADE
+	dquot_free_space_nodirty(inode,
+#else
 	vfs_dq_free_space_nodirty(inode,
+#endif
 				  ocfs2_clusters_to_bytes(inode->i_sb, len));
 
 	ret = ocfs2_remove_extent(handle, et, cpos, len, meta_ac, dealloc);
@@ -6935,7 +6939,11 @@
 		goto bail;
 	}
 
+#ifdef SYNO_DQUOT_UPGRADE
+	dquot_free_space_nodirty(inode,
+#else
 	vfs_dq_free_space_nodirty(inode,
+#endif
 			ocfs2_clusters_to_bytes(osb->sb, clusters_to_del));
 	spin_lock(&OCFS2_I(inode)->ip_lock);
 	OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters) -
@@ -7300,9 +7308,15 @@
 		unsigned int page_end;
 		u64 phys;
 
+#ifdef SYNO_DQUOT_UPGRADE
+		ret = dquot_alloc_space_nodirty(inode,
+				       ocfs2_clusters_to_bytes(osb->sb, 1));
+		if (ret) {
+#else
 		if (vfs_dq_alloc_space_nodirty(inode,
 				       ocfs2_clusters_to_bytes(osb->sb, 1))) {
 			ret = -EDQUOT;
+#endif
 			goto out_commit;
 		}
 		did_quota = 1;
@@ -7380,7 +7394,11 @@
 
 out_commit:
 	if (ret < 0 && did_quota)
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_space_nodirty(inode,
+#else
 		vfs_dq_free_space_nodirty(inode,
+#endif
 					  ocfs2_clusters_to_bytes(osb->sb, 1));
 
 	ocfs2_commit_trans(osb, handle);
Index: fs/ocfs2/aops.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/ocfs2/aops.c,v
retrieving revision 1.2
diff -b -u -r1.2 aops.c
--- fs/ocfs2/aops.c	3 May 2010 13:19:17 -0000	1.2
+++ fs/ocfs2/aops.c	29 Jun 2010 07:49:28 -0000
@@ -1790,9 +1790,16 @@
 
 	wc->w_handle = handle;
 
+#ifdef SYNO_DQUOT_UPGRADE
+	if (clusters_to_alloc) {
+		ret = dquot_alloc_space_nodirty(inode,
+			ocfs2_clusters_to_bytes(osb->sb, clusters_to_alloc));
+		if (ret)
+#else
 	if (clusters_to_alloc && vfs_dq_alloc_space_nodirty(inode,
 			ocfs2_clusters_to_bytes(osb->sb, clusters_to_alloc))) {
 		ret = -EDQUOT;
+#endif
 		goto out_commit;
 	}
 	/*
@@ -1836,7 +1843,11 @@
 	return 0;
 out_quota:
 	if (clusters_to_alloc)
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_space(inode,
+#else
 		vfs_dq_free_space(inode,
+#endif
 			  ocfs2_clusters_to_bytes(osb->sb, clusters_to_alloc));
 out_commit:
 	ocfs2_commit_trans(osb, handle);
Index: fs/ocfs2/dir.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/ocfs2/dir.c,v
retrieving revision 1.1.1.1
diff -b -u -r1.1.1.1 dir.c
--- fs/ocfs2/dir.c	15 Apr 2010 12:28:24 -0000	1.1.1.1
+++ fs/ocfs2/dir.c	29 Jun 2010 07:49:28 -0000
@@ -2964,10 +2964,16 @@
 		goto out;
 	}
 
+#ifdef SYNO_DQUOT_UPGRADE
+	ret = dquot_alloc_space_nodirty(dir,
+		ocfs2_clusters_to_bytes(osb->sb, alloc + dx_alloc));
+	if (ret) {
+#else
 	if (vfs_dq_alloc_space_nodirty(dir,
 				ocfs2_clusters_to_bytes(osb->sb,
 							alloc + dx_alloc))) {
 		ret = -EDQUOT;
+#endif
 		goto out_commit;
 	}
 	did_quota = 1;
@@ -3178,7 +3184,11 @@
 
 out_commit:
 	if (ret < 0 && did_quota)
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_space_nodirty(dir, bytes_allocated);
+#else
 		vfs_dq_free_space_nodirty(dir, bytes_allocated);
+#endif
 
 	ocfs2_commit_trans(osb, handle);
 
@@ -3221,9 +3231,15 @@
 	if (extend) {
 		u32 offset = OCFS2_I(dir)->ip_clusters;
 
+#ifdef SYNO_DQUOT_UPGRADE
+		status = dquot_alloc_space_nodirty(dir,
+					ocfs2_clusters_to_bytes(sb, 1));
+		if (status) {
+#else
 		if (vfs_dq_alloc_space_nodirty(dir,
 					ocfs2_clusters_to_bytes(sb, 1))) {
 			status = -EDQUOT;
+#endif
 			goto bail;
 		}
 		did_quota = 1;
@@ -3254,7 +3270,11 @@
 	status = 0;
 bail:
 	if (did_quota && status < 0)
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_space_nodirty(dir, ocfs2_clusters_to_bytes(sb, 1));
+#else
 		vfs_dq_free_space_nodirty(dir, ocfs2_clusters_to_bytes(sb, 1));
+#endif
 	mlog_exit(status);
 	return status;
 }
@@ -3889,9 +3909,15 @@
 		goto out;
 	}
 
+#ifdef SYNO_DQUOT_UPGRADE
+	ret = dquot_alloc_space_nodirty(dir,
+				       ocfs2_clusters_to_bytes(dir->i_sb, 1));
+	if (ret) {
+#else
 	if (vfs_dq_alloc_space_nodirty(dir,
 				       ocfs2_clusters_to_bytes(dir->i_sb, 1))) {
 		ret = -EDQUOT;
+#endif
 		goto out_commit;
 	}
 	did_quota = 1;
@@ -3983,7 +4009,11 @@
 
 out_commit:
 	if (ret < 0 && did_quota)
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_space_nodirty(dir,
+#else
 		vfs_dq_free_space_nodirty(dir,
+#endif
 				ocfs2_clusters_to_bytes(dir->i_sb, 1));
 
 	ocfs2_commit_trans(osb, handle);
@@ -4165,9 +4195,15 @@
 		goto out;
 	}
 
+#ifdef SYNO_DQUOT_UPGRADE
+	ret = dquot_alloc_space_nodirty(dir,
+				       ocfs2_clusters_to_bytes(osb->sb, 1));
+	if (ret) {
+#else
 	if (vfs_dq_alloc_space_nodirty(dir,
 				       ocfs2_clusters_to_bytes(osb->sb, 1))) {
 		ret = -EDQUOT;
+#endif
 		goto out_commit;
 	}
 	did_quota = 1;
@@ -4229,7 +4265,11 @@
 
 out_commit:
 	if (ret < 0 && did_quota)
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_space_nodirty(dir,
+#else
 		vfs_dq_free_space_nodirty(dir,
+#endif
 					  ocfs2_clusters_to_bytes(dir->i_sb, 1));
 
 	ocfs2_commit_trans(osb, handle);
Index: fs/ocfs2/file.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/ocfs2/file.c,v
retrieving revision 1.1.1.1
diff -b -u -r1.1.1.1 file.c
--- fs/ocfs2/file.c	15 Apr 2010 12:28:24 -0000	1.1.1.1
+++ fs/ocfs2/file.c	29 Jun 2010 07:49:28 -0000
@@ -629,9 +629,15 @@
 	}
 
 restarted_transaction:
+#ifdef SYNO_DQUOT_UPGRADE
+	status = dquot_alloc_space_nodirty(inode,
+			ocfs2_clusters_to_bytes(osb->sb, clusters_to_add));
+	if (status) {
+#else
 	if (vfs_dq_alloc_space_nodirty(inode, ocfs2_clusters_to_bytes(osb->sb,
 	    clusters_to_add))) {
 		status = -EDQUOT;
+#endif
 		goto leave;
 	}
 	did_quota = 1;
@@ -674,7 +680,11 @@
 	clusters_to_add -= (OCFS2_I(inode)->ip_clusters - prev_clusters);
 	spin_unlock(&OCFS2_I(inode)->ip_lock);
 	/* Release unused quota reservation */
+#ifdef SYNO_DQUOT_UPGRADE
+	dquot_free_space(inode,
+#else
 	vfs_dq_free_space(inode,
+#endif
 			ocfs2_clusters_to_bytes(osb->sb, clusters_to_add));
 	did_quota = 0;
 
@@ -710,7 +720,11 @@
 
 leave:
 	if (status < 0 && did_quota)
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_space(inode,
+#else
 		vfs_dq_free_space(inode,
+#endif
 			ocfs2_clusters_to_bytes(osb->sb, clusters_to_add));
 	if (handle) {
 		ocfs2_commit_trans(osb, handle);
Index: fs/ocfs2/namei.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/ocfs2/namei.c,v
retrieving revision 1.1.1.1
diff -b -u -r1.1.1.1 namei.c
--- fs/ocfs2/namei.c	15 Apr 2010 12:28:24 -0000	1.1.1.1
+++ fs/ocfs2/namei.c	29 Jun 2010 07:49:28 -0000
@@ -1716,9 +1716,15 @@
 		u32 offset = 0;
 
 		inode->i_op = &ocfs2_symlink_inode_operations;
+#ifdef SYNO_DQUOT_UPGRADE
+		status = dquot_alloc_space_nodirty(inode,
+		    ocfs2_clusters_to_bytes(osb->sb, 1));
+		if (status) {
+#else
 		if (vfs_dq_alloc_space_nodirty(inode,
 		    ocfs2_clusters_to_bytes(osb->sb, 1))) {
 			status = -EDQUOT;
+#endif
 			goto bail;
 		}
 		did_quota = 1;
@@ -1788,7 +1794,11 @@
 	d_instantiate(dentry, inode);
 bail:
 	if (status < 0 && did_quota)
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_space_nodirty(inode,
+#else
 		vfs_dq_free_space_nodirty(inode,
+#endif
 					ocfs2_clusters_to_bytes(osb->sb, 1));
 	if (status < 0 && did_quota_inode)
 		vfs_dq_free_inode(inode);
Index: fs/ocfs2/quota_global.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/ocfs2/quota_global.c,v
retrieving revision 1.1.1.1
diff -b -u -r1.1.1.1 quota_global.c
--- fs/ocfs2/quota_global.c	15 Apr 2010 12:28:24 -0000	1.1.1.1
+++ fs/ocfs2/quota_global.c	29 Jun 2010 07:49:28 -0000
@@ -853,9 +853,13 @@
 const struct dquot_operations ocfs2_quota_operations = {
 	.initialize	= dquot_initialize,
 	.drop		= dquot_drop,
+#ifndef SYNO_DQUOT_UPGRADE
 	.alloc_space	= dquot_alloc_space,
+#endif
 	.alloc_inode	= dquot_alloc_inode,
+#ifndef SYNO_DQUOT_UPGRADE
 	.free_space	= dquot_free_space,
+#endif
 	.free_inode	= dquot_free_inode,
 	.transfer	= dquot_transfer,
 	.write_dquot	= ocfs2_write_dquot,
Index: fs/quota/dquot.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/quota/dquot.c,v
retrieving revision 1.4
diff -b -u -r1.4 dquot.c
--- fs/quota/dquot.c	3 May 2010 13:19:17 -0000	1.4
+++ fs/quota/dquot.c	29 Jun 2010 07:49:28 -0000
@@ -104,9 +104,13 @@
  *
  * Any operation working on dquots via inode pointers must hold dqptr_sem.  If
  * operation is just reading pointers from inode (or not using them at all) the
- * read lock is enough. If pointers are altered function must hold write lock
- * (these locking rules also apply for S_NOQUOTA flag in the inode - note that
- * for altering the flag i_mutex is also needed).
+ * read lock is enough. If pointers are altered function must hold write lock.
+ * Special care needs to be taken about S_NOQUOTA inode flag (marking that
+ * inode is a quota file). Functions adding pointers from inode to dquots have
+ * to check this flag under dqptr_sem and then (if S_NOQUOTA is not set) they
+ * have to do all pointer modifications before dropping dqptr_sem. This makes
+ * sure they cannot race with quotaon which first sets S_NOQUOTA flag and
+ * then drops all pointers to dquots from an inode.
  *
  * Each dquot has its dq_lock mutex. Locked dquots might not be referenced
  * from inodes (dquot_alloc_space() and such don't check the dq_lock).
@@ -1357,7 +1361,6 @@
 	}
 
 	down_write(&sb_dqopt(sb)->dqptr_sem);
-	/* Having dqptr_sem we know NOQUOTA flags can't be altered... */
 	if (IS_NOQUOTA(inode))
 		goto out_err;
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
@@ -1498,38 +1501,57 @@
 }
 
 /*
- * Following four functions update i_blocks+i_bytes fields and
- * quota information (together with appropriate checks)
- * NOTE: We absolutely rely on the fact that caller dirties
- * the inode (usually macros in quotaops.h care about this) and
- * holds a handle for the current transaction so that dquot write and
- * inode write go into the same transaction.
+ * This functions updates i_blocks+i_bytes fields and quota information
+ * (together with appropriate checks).
+ *
+ * NOTE: We absolutely rely on the fact that caller dirties the inode
+ * (usually helpers in quotaops.h care about this) and holds a handle for
+ * the current transaction so that dquot write and inode write go into the
+ * same transaction.
  */
 
 /*
  * This operation can block, but only after everything is updated
  */
+#ifdef SYNO_DQUOT_UPGRADE
+int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags)
+#else
 int __dquot_alloc_space(struct inode *inode, qsize_t number,
 			int warn, int reserve)
+#endif
 {
+#ifdef SYNO_DQUOT_UPGRADE
+	int cnt, ret = 0;
+#else
 	int cnt, ret = QUOTA_OK;
+#endif
 	char warntype[MAXQUOTAS];
+#ifdef SYNO_DQUOT_UPGRADE
+	int warn = flags & DQUOT_SPACE_WARN;
+	int reserve = flags & DQUOT_SPACE_RESERVE;
+	int nofail = flags & DQUOT_SPACE_NOFAIL;
+#endif
 
 	/*
 	 * First test before acquiring mutex - solves deadlocks when we
 	 * re-enter the quota code and are already holding the mutex
 	 */
+#ifdef SYNO_DQUOT_UPGRADE
+	if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode)) {
+#else
 	if (IS_NOQUOTA(inode)) {
+#endif
 		inode_incr_space(inode, number, reserve);
 		goto out;
 	}
 
 	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+#ifndef SYNO_DQUOT_UPGRADE
 	if (IS_NOQUOTA(inode)) {
 		inode_incr_space(inode, number, reserve);
 		goto out_unlock;
 	}
-
+#endif
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
 		warntype[cnt] = QUOTA_NL_NOWARN;
 
@@ -1537,9 +1559,15 @@
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 		if (!inode->i_dquot[cnt])
 			continue;
+#ifdef SYNO_DQUOT_UPGRADE
+		if (check_bdq(inode->i_dquot[cnt], number, !warn, warntype+cnt)
+				== NO_QUOTA && !nofail) {
+			ret = -EDQUOT;
+#else
 		if (check_bdq(inode->i_dquot[cnt], number, warn, warntype+cnt)
 		    == NO_QUOTA) {
 			ret = NO_QUOTA;
+#endif
 			spin_unlock(&dq_data_lock);
 			goto out_flush_warn;
 		}
@@ -1563,12 +1591,18 @@
 			mark_dquot_dirty(inode->i_dquot[cnt]);
 out_flush_warn:
 	flush_warnings(inode->i_dquot, warntype);
+#ifndef SYNO_DQUOT_UPGRADE
 out_unlock:
+#endif
 	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
 out:
 	return ret;
 }
+#ifdef SYNO_DQUOT_UPGRADE
+EXPORT_SYMBOL(__dquot_alloc_space);
+#endif
 
+#ifndef SYNO_DQUOT_UPGRADE
 int dquot_alloc_space(struct inode *inode, qsize_t number, int warn)
 {
 	return __dquot_alloc_space(inode, number, warn, 0);
@@ -1580,6 +1614,7 @@
 	return __dquot_alloc_space(inode, number, warn, 1);
 }
 EXPORT_SYMBOL(dquot_reserve_space);
+#endif
 
 /*
  * This operation can block, but only after everything is updated
@@ -1596,10 +1631,12 @@
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
 		warntype[cnt] = QUOTA_NL_NOWARN;
 	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+#ifndef SYNO_DQUOT_UPGRADE
 	if (IS_NOQUOTA(inode)) {
 		up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
 		return QUOTA_OK;
 	}
+#endif
 	spin_lock(&dq_data_lock);
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 		if (!inode->i_dquot[cnt])
@@ -1628,23 +1665,41 @@
 }
 EXPORT_SYMBOL(dquot_alloc_inode);
 
+/*
+ * Convert in-memory reserved quotas to real consumed quotas
+ */
+#ifdef SYNO_DQUOT_UPGRADE
+int dquot_claim_space_nodirty(struct inode *inode, qsize_t number)
+#else
 int dquot_claim_space(struct inode *inode, qsize_t number)
+#endif
 {
 	int cnt;
+#ifndef SYNO_DQUOT_UPGRADE
 	int ret = QUOTA_OK;
+#endif
 
+#ifdef SYNO_DQUOT_UPGRADE
+	if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode)) {
+#else
 	if (IS_NOQUOTA(inode)) {
+#endif
 		inode_claim_rsv_space(inode, number);
+#ifdef SYNO_DQUOT_UPGRADE
+		return 0;
+#else
 		goto out;
+#endif
 	}
 
 	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+#ifndef SYNO_DQUOT_UPGRADE
 	if (IS_NOQUOTA(inode))	{
 		up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
 		inode_claim_rsv_space(inode, number);
 		goto out;
 	}
-
+#endif
 	spin_lock(&dq_data_lock);
 	/* Claim reserved quotas to allocated quotas */
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
@@ -1660,33 +1715,56 @@
 		if (inode->i_dquot[cnt])
 			mark_dquot_dirty(inode->i_dquot[cnt]);
 	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+#ifdef SYNO_DQUOT_UPGRADE
+	return 0;
+#else
 out:
 	return ret;
+#endif
 }
+#ifdef SYNO_DQUOT_UPGRADE
+EXPORT_SYMBOL(dquot_claim_space_nodirty);
+#else
 EXPORT_SYMBOL(dquot_claim_space);
+#endif
 
 /*
  * This operation can block, but only after everything is updated
  */
+#ifdef SYNO_DQUOT_UPGRADE
+void __dquot_free_space(struct inode *inode, qsize_t number, int flags)
+#else
 int __dquot_free_space(struct inode *inode, qsize_t number, int reserve)
+#endif
 {
 	unsigned int cnt;
 	char warntype[MAXQUOTAS];
+#ifdef SYNO_DQUOT_UPGRADE
+	int reserve = flags & DQUOT_SPACE_RESERVE;
+#endif
 
 	/* First test before acquiring mutex - solves deadlocks when we
          * re-enter the quota code and are already holding the mutex */
+#ifdef SYNO_DQUOT_UPGRADE
+	if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode)) {
+		inode_decr_space(inode, number, reserve);
+		return;
+	}
+#else
 	if (IS_NOQUOTA(inode)) {
 out_sub:
 		inode_decr_space(inode, number, reserve);
 		return QUOTA_OK;
 	}
+#endif
 
 	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
-	/* Now recheck reliably when holding dqptr_sem */
+#ifndef SYNO_DQUOT_UPGRADE
 	if (IS_NOQUOTA(inode)) {
 		up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
 		goto out_sub;
 	}
+#endif
 	spin_lock(&dq_data_lock);
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 		if (!inode->i_dquot[cnt])
@@ -1709,9 +1787,13 @@
 out_unlock:
 	flush_warnings(inode->i_dquot, warntype);
 	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+#ifndef SYNO_DQUOT_UPGRADE
 	return QUOTA_OK;
+#endif
 }
-
+#ifdef SYNO_DQUOT_UPGRADE
+EXPORT_SYMBOL(__dquot_free_space);
+#else
 int dquot_free_space(struct inode *inode, qsize_t number)
 {
 	return  __dquot_free_space(inode, number, 0);
@@ -1719,14 +1801,15 @@
 EXPORT_SYMBOL(dquot_free_space);
 
 /*
- * Release reserved quota space
- */
+* Release reserved quota space
+*/
 void dquot_release_reserved_space(struct inode *inode, qsize_t number)
 {
 	__dquot_free_space(inode, number, 1);
 
 }
 EXPORT_SYMBOL(dquot_release_reserved_space);
+#endif
 
 /*
  * This operation can block, but only after everything is updated
@@ -1742,11 +1825,13 @@
 		return QUOTA_OK;
 
 	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+#ifndef SYNO_DQUOT_UPGRADE
 	/* Now recheck reliably when holding dqptr_sem */
 	if (IS_NOQUOTA(inode)) {
 		up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
 		return QUOTA_OK;
 	}
+#endif
 	spin_lock(&dq_data_lock);
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 		if (!inode->i_dquot[cnt])
@@ -1801,7 +1886,6 @@
 					      GRPQUOTA);
 
 	down_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
-	/* Now recheck reliably when holding dqptr_sem */
 	if (IS_NOQUOTA(inode)) {	/* File without quota accounting? */
 		up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
 		goto put_all;
@@ -1916,9 +2000,13 @@
 const struct dquot_operations dquot_operations = {
 	.initialize	= dquot_initialize,
 	.drop		= dquot_drop,
+#ifndef SYNO_DQUOT_UPGRADE
 	.alloc_space	= dquot_alloc_space,
+#endif
 	.alloc_inode	= dquot_alloc_inode,
+#ifndef SYNO_DQUOT_UPGRADE
 	.free_space	= dquot_free_space,
+#endif
 	.free_inode	= dquot_free_inode,
 	.transfer	= dquot_transfer,
 	.write_dquot	= dquot_commit,
@@ -2126,13 +2214,21 @@
 		/* We don't want quota and atime on quota files (deadlocks
 		 * possible) Also nobody should write to the file - we use
 		 * special IO operations which ignore the immutable bit. */
+#ifndef SYNO_DQUOT_UPGRADE
 		down_write(&dqopt->dqptr_sem);
+#endif
 		mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
 		oldflags = inode->i_flags & (S_NOATIME | S_IMMUTABLE |
 					     S_NOQUOTA);
 		inode->i_flags |= S_NOQUOTA | S_NOATIME | S_IMMUTABLE;
 		mutex_unlock(&inode->i_mutex);
+#ifndef SYNO_DQUOT_UPGRADE
 		up_write(&dqopt->dqptr_sem);
+#endif
+		/*
+		 * When S_NOQUOTA is set, remove dquot references as no more
+		 * references can be added
+		 */
 		sb->dq_op->drop(inode);
 	}
 
@@ -2169,14 +2265,18 @@
 	iput(inode);
 out_lock:
 	if (oldflags != -1) {
+#ifndef SYNO_DQUOT_UPGRADE
 		down_write(&dqopt->dqptr_sem);
+#endif
 		mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
 		/* Set the flags back (in the case of accidental quotaon()
 		 * on a wrong file we don't want to mess up the flags) */
 		inode->i_flags &= ~(S_NOATIME | S_NOQUOTA | S_IMMUTABLE);
 		inode->i_flags |= oldflags;
 		mutex_unlock(&inode->i_mutex);
+#ifndef SYNO_DQUOT_UPGRADE
 		up_write(&dqopt->dqptr_sem);
+#endif
 	}
 	mutex_unlock(&dqopt->dqonoff_mutex);
 out_fmt:
Index: fs/reiserfs/bitmap.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/reiserfs/bitmap.c,v
retrieving revision 1.1.1.1
diff -b -u -r1.1.1.1 bitmap.c
--- fs/reiserfs/bitmap.c	15 Apr 2010 12:28:24 -0000	1.1.1.1
+++ fs/reiserfs/bitmap.c	29 Jun 2010 07:49:28 -0000
@@ -425,7 +425,11 @@
 
 	journal_mark_dirty(th, s, sbh);
 	if (for_unformatted)
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_block_nodirty(inode, 1);
+#else
 		vfs_dq_free_block_nodirty(inode, 1);
+#endif
 }
 
 void reiserfs_free_block(struct reiserfs_transaction_handle *th,
@@ -1049,7 +1053,11 @@
 			       amount_needed, hint->inode->i_uid);
 #endif
 		quota_ret =
+#ifdef SYNO_DQUOT_UPGRADE
+		    dquot_alloc_block_nodirty(hint->inode, amount_needed);
+#else
 		    vfs_dq_alloc_block_nodirty(hint->inode, amount_needed);
+#endif
 		if (quota_ret)	/* Quota exceeded? */
 			return QUOTA_EXCEEDED;
 		if (hint->preallocate && hint->prealloc_size) {
@@ -1058,7 +1066,11 @@
 				       "reiserquota: allocating (prealloc) %d blocks id=%u",
 				       hint->prealloc_size, hint->inode->i_uid);
 #endif
+#ifdef SYNO_DQUOT_UPGRADE
+			quota_ret = dquot_prealloc_block_nodirty(hint->inode,
+#else
 			quota_ret = vfs_dq_prealloc_block_nodirty(hint->inode,
+#endif
 							 hint->prealloc_size);
 			if (quota_ret)
 				hint->preallocate = hint->prealloc_size = 0;
@@ -1092,7 +1104,11 @@
 					       hint->inode->i_uid);
 #endif
 				/* Free not allocated blocks */
+#ifdef SYNO_DQUOT_UPGRADE
+				dquot_free_block_nodirty(hint->inode,
+#else
 				vfs_dq_free_block_nodirty(hint->inode,
+#endif
 					amount_needed + hint->prealloc_size -
 					nr_allocated);
 			}
@@ -1125,7 +1141,11 @@
 			       REISERFS_I(hint->inode)->i_prealloc_count,
 			       hint->inode->i_uid);
 #endif
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_block_nodirty(hint->inode, amount_needed +
+#else
 		vfs_dq_free_block_nodirty(hint->inode, amount_needed +
+#endif
 					 hint->prealloc_size - nr_allocated -
 					 REISERFS_I(hint->inode)->
 					 i_prealloc_count);
Index: fs/reiserfs/stree.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/reiserfs/stree.c,v
retrieving revision 1.1.1.1
diff -b -u -r1.1.1.1 stree.c
--- fs/reiserfs/stree.c	15 Apr 2010 12:28:24 -0000	1.1.1.1
+++ fs/reiserfs/stree.c	29 Jun 2010 07:49:28 -0000
@@ -1262,7 +1262,11 @@
 		       "reiserquota delete_item(): freeing %u, id=%u type=%c",
 		       quota_cut_bytes, inode->i_uid, head2type(&s_ih));
 #endif
+#ifdef SYNO_DQUOT_UPGRADE
+	dquot_free_space_nodirty(inode, quota_cut_bytes);
+#else
 	vfs_dq_free_space_nodirty(inode, quota_cut_bytes);
+#endif
 
 	/* Return deleted body length */
 	return ret_value;
@@ -1346,7 +1350,11 @@
 					       quota_cut_bytes, inode->i_uid,
 					       key2type(key));
 #endif
+#ifdef SYNO_DQUOT_UPGRADE
+				dquot_free_space_nodirty(inode,
+#else
 				vfs_dq_free_space_nodirty(inode,
+#endif
 							 quota_cut_bytes);
 			}
 			break;
@@ -1696,7 +1704,11 @@
 		       "reiserquota cut_from_item(): freeing %u id=%u type=%c",
 		       quota_cut_bytes, inode->i_uid, '?');
 #endif
+#ifdef SYNO_DQUOT_UPGRADE
+	dquot_free_space_nodirty(inode, quota_cut_bytes);
+#else
 	vfs_dq_free_space_nodirty(inode, quota_cut_bytes);
+#endif
 	return ret_value;
 }
 
@@ -1931,9 +1943,18 @@
 		       key2type(&(key->on_disk_key)));
 #endif
 
+#ifdef SYNO_DQUOT_UPGRADE
+	retval = dquot_alloc_space_nodirty(inode, pasted_size);
+	if (retval) {
+#else
 	if (vfs_dq_alloc_space_nodirty(inode, pasted_size)) {
+#endif
 		pathrelse(search_path);
+#ifdef SYNO_DQUOT_UPGRADE
+		return retval;
+#else
 		return -EDQUOT;
+#endif
 	}
 	init_tb_struct(th, &s_paste_balance, th->t_super, search_path,
 		       pasted_size);
@@ -1987,7 +2008,11 @@
 		       pasted_size, inode->i_uid,
 		       key2type(&(key->on_disk_key)));
 #endif
+#ifdef SYNO_DQUOT_UPGRADE
+	dquot_free_space_nodirty(inode, pasted_size);
+#else
 	vfs_dq_free_space_nodirty(inode, pasted_size);
+#endif
 	return retval;
 }
 
@@ -2025,9 +2050,18 @@
 #endif
 		/* We can't dirty inode here. It would be immediately written but
 		 * appropriate stat item isn't inserted yet... */
+#ifdef SYNO_DQUOT_UPGRADE
+		retval = dquot_alloc_space_nodirty(inode, quota_bytes);
+		if (retval) {
+#else
 		if (vfs_dq_alloc_space_nodirty(inode, quota_bytes)) {
+#endif
 			pathrelse(path);
+#ifdef SYNO_DQUOT_UPGRADE
+			return retval;
+#else
 			return -EDQUOT;
+#endif
 		}
 	}
 	init_tb_struct(th, &s_ins_balance, th->t_super, path,
@@ -2076,6 +2110,10 @@
 		       quota_bytes, inode->i_uid, head2type(ih));
 #endif
 	if (inode)
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_space_nodirty(inode, quota_bytes);
+#else
 		vfs_dq_free_space_nodirty(inode, quota_bytes);
+#endif
 	return retval;
 }
Index: fs/reiserfs/super.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/reiserfs/super.c,v
retrieving revision 1.1.1.1
diff -b -u -r1.1.1.1 super.c
--- fs/reiserfs/super.c	15 Apr 2010 12:28:24 -0000	1.1.1.1
+++ fs/reiserfs/super.c	29 Jun 2010 07:49:28 -0000
@@ -615,9 +615,13 @@
 static const struct dquot_operations reiserfs_quota_operations = {
 	.initialize = dquot_initialize,
 	.drop = dquot_drop,
+#ifndef SYNO_DQUOT_UPGRADE
 	.alloc_space = dquot_alloc_space,
+#endif
 	.alloc_inode = dquot_alloc_inode,
+#ifndef SYNO_DQUOT_UPGRADE
 	.free_space = dquot_free_space,
+#endif
 	.free_inode = dquot_free_inode,
 	.transfer = dquot_transfer,
 	.write_dquot = reiserfs_write_dquot,
Index: fs/udf/balloc.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/udf/balloc.c,v
retrieving revision 1.1.1.1
diff -b -u -r1.1.1.1 balloc.c
--- fs/udf/balloc.c	15 Apr 2010 12:28:24 -0000	1.1.1.1
+++ fs/udf/balloc.c	29 Jun 2010 07:49:28 -0000
@@ -208,7 +208,11 @@
 					((char *)bh->b_data)[(bit + i) >> 3]);
 			} else {
 				if (inode)
+#ifdef SYNO_DQUOT_UPGRADE
+					dquot_free_block(inode, 1);
+#else
 					vfs_dq_free_block(inode, 1);
+#endif
 				udf_add_free_space(sb, sbi->s_partition, 1);
 			}
 		}
@@ -260,11 +264,19 @@
 		while (bit < (sb->s_blocksize << 3) && block_count > 0) {
 			if (!udf_test_bit(bit, bh->b_data))
 				goto out;
+#ifdef SYNO_DQUOT_UPGRADE
+			else if (dquot_prealloc_block(inode, 1))
+#else
 			else if (vfs_dq_prealloc_block(inode, 1))
+#endif
 				goto out;
 			else if (!udf_clear_bit(bit, bh->b_data)) {
 				udf_debug("bit already cleared for block %d\n", bit);
+#ifdef SYNO_DQUOT_UPGRADE
+				dquot_free_block(inode, 1);
+#else
 				vfs_dq_free_block(inode, 1);
+#endif
 				goto out;
 			}
 			block_count--;
@@ -390,11 +402,23 @@
 	/*
 	 * Check quota for allocation of this block.
 	 */
+#ifdef SYNO_DQUOT_UPGRADE
+	if (inode) {
+		int ret = dquot_alloc_block(inode, 1);
+
+		if (ret) {
+			mutex_unlock(&sbi->s_alloc_mutex);
+			*err = ret;
+			return 0;
+		}
+	}
+#else
 	if (inode && vfs_dq_alloc_block(inode, 1)) {
 		mutex_unlock(&sbi->s_alloc_mutex);
 		*err = -EDQUOT;
 		return 0;
 	}
+#endif
 
 	newblock = bit + (block_group << (sb->s_blocksize_bits + 3)) -
 		(sizeof(struct spaceBitmapDesc) << 3);
@@ -449,7 +473,11 @@
 	/* We do this up front - There are some error conditions that
 	   could occure, but.. oh well */
 	if (inode)
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_block(inode, count);
+#else
 		vfs_dq_free_block(inode, count);
+#endif
 	udf_add_free_space(sb, sbi->s_partition, count);
 
 	start = bloc->logicalBlockNum + offset;
@@ -694,7 +722,11 @@
 		epos.offset -= adsize;
 
 		alloc_count = (elen >> sb->s_blocksize_bits);
+#ifdef SYNO_DQUOT_UPGRADE
+		if (inode && dquot_prealloc_block(inode,
+#else
 		if (inode && vfs_dq_prealloc_block(inode,
+#endif
 			alloc_count > block_count ? block_count : alloc_count))
 			alloc_count = 0;
 		else if (alloc_count > block_count) {
@@ -797,13 +829,23 @@
 	newblock = goal_eloc.logicalBlockNum;
 	goal_eloc.logicalBlockNum++;
 	goal_elen -= sb->s_blocksize;
-
+#ifdef SYNO_DQUOT_UPGRADE
+	if (inode) {
+		*err = dquot_alloc_block(inode, 1);
+		if (*err) {
+			brelse(goal_epos.bh);
+			mutex_unlock(&sbi->s_alloc_mutex);
+			return 0;
+		}
+	}
+#else
 	if (inode && vfs_dq_alloc_block(inode, 1)) {
 		brelse(goal_epos.bh);
 		mutex_unlock(&sbi->s_alloc_mutex);
 		*err = -EDQUOT;
 		return 0;
 	}
+#endif
 
 	if (goal_elen)
 		udf_write_aext(table, &goal_epos, &goal_eloc, goal_elen, 1);
Index: fs/ufs/balloc.c
===================================================================
RCS file: /cvs/projects/linux-2.6.32/fs/ufs/balloc.c,v
retrieving revision 1.1.1.1
diff -b -u -r1.1.1.1 balloc.c
--- fs/ufs/balloc.c	15 Apr 2010 12:28:25 -0000	1.1.1.1
+++ fs/ufs/balloc.c	29 Jun 2010 07:49:28 -0000
@@ -85,7 +85,11 @@
 				   "bit already cleared for fragment %u", i);
 	}
 	
+#ifdef SYNO_DQUOT_UPGRADE
+	dquot_free_block(inode, count);
+#else
 	vfs_dq_free_block(inode, count);
+#endif
 
 	
 	fs32_add(sb, &ucg->cg_cs.cs_nffree, count);
@@ -195,7 +199,11 @@
 		ubh_setblock(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
 		if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
 			ufs_clusteracct (sb, ucpi, blkno, 1);
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_block(inode, uspi->s_fpb);
+#else
 		vfs_dq_free_block(inode, uspi->s_fpb);
+#endif
 
 		fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1);
 		uspi->cs_total.cs_nbfree++;
@@ -511,6 +519,9 @@
 	struct ufs_cg_private_info * ucpi;
 	struct ufs_cylinder_group * ucg;
 	unsigned cgno, fragno, fragoff, count, fragsize, i;
+#ifdef SYNO_DQUOT_UPGRADE
+	int ret;
+#endif
 	
 	UFSD("ENTER, fragment %llu, oldcount %u, newcount %u\n",
 	     (unsigned long long)fragment, oldcount, newcount);
@@ -556,8 +567,14 @@
 		fs32_add(sb, &ucg->cg_frsum[fragsize - count], 1);
 	for (i = oldcount; i < newcount; i++)
 		ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i);
+#ifdef SYNO_DQUOT_UPGRADE
+	ret = dquot_alloc_block(inode, count);
+	if (ret) {
+		*err = ret;
+#else
 	if (vfs_dq_alloc_block(inode, count)) {
 		*err = -EDQUOT;
+#endif
 		return 0;
 	}
 
@@ -596,6 +613,9 @@
 	struct ufs_cylinder_group * ucg;
 	unsigned oldcg, i, j, k, allocsize;
 	u64 result;
+#ifdef SYNO_DQUOT_UPGRADE
+	int ret;
+#endif
 	
 	UFSD("ENTER, ino %lu, cgno %u, goal %llu, count %u\n",
 	     inode->i_ino, cgno, (unsigned long long)goal, count);
@@ -664,7 +684,11 @@
 		for (i = count; i < uspi->s_fpb; i++)
 			ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, goal + i);
 		i = uspi->s_fpb - count;
+#ifdef SYNO_DQUOT_UPGRADE
+		dquot_free_block(inode, i);
+#else
 		vfs_dq_free_block(inode, i);
+#endif
 
 		fs32_add(sb, &ucg->cg_cs.cs_nffree, i);
 		uspi->cs_total.cs_nffree += i;
@@ -676,8 +700,14 @@
 	result = ufs_bitmap_search (sb, ucpi, goal, allocsize);
 	if (result == INVBLOCK)
 		return 0;
+#ifdef SYNO_DQUOT_UPGRADE
+	ret = dquot_alloc_block(inode, count);
+	if (ret) {
+		*err = ret;
+#else
 	if (vfs_dq_alloc_block(inode, count)) {
 		*err = -EDQUOT;
+#endif
 		return 0;
 	}
 	for (i = 0; i < count; i++)
@@ -714,6 +744,9 @@
 	struct ufs_super_block_first * usb1;
 	struct ufs_cylinder_group * ucg;
 	u64 result, blkno;
+#ifdef SYNO_DQUOT_UPGRADE
+	int ret;
+#endif
 
 	UFSD("ENTER, goal %llu\n", (unsigned long long)goal);
 
@@ -747,8 +780,14 @@
 	ubh_clrblock (UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
 	if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
 		ufs_clusteracct (sb, ucpi, blkno, -1);
+#ifdef SYNO_DQUOT_UPGRADE
+	ret = dquot_alloc_block(inode, uspi->s_fpb);
+	if (ret) {
+		*err = ret;
+#else
 	if (vfs_dq_alloc_block(inode, uspi->s_fpb)) {
 		*err = -EDQUOT;
+#endif
 		return INVBLOCK;
 	}
 
Index: include/linux/quota.h
===================================================================
RCS file: /cvs/projects/linux-2.6.32/include/linux/quota.h,v
retrieving revision 1.2
diff -b -u -r1.2 quota.h
--- include/linux/quota.h	3 May 2010 13:19:18 -0000	1.2
+++ include/linux/quota.h	29 Jun 2010 07:49:28 -0000
@@ -295,9 +295,13 @@
 struct dquot_operations {
 	int (*initialize) (struct inode *, int);
 	int (*drop) (struct inode *);
+#ifndef SYNO_DQUOT_UPGRADE
 	int (*alloc_space) (struct inode *, qsize_t, int);
+#endif
 	int (*alloc_inode) (const struct inode *, qsize_t);
+#ifndef SYNO_DQUOT_UPGRADE
 	int (*free_space) (struct inode *, qsize_t);
+#endif
 	int (*free_inode) (const struct inode *, qsize_t);
 	int (*transfer) (struct inode *, struct iattr *);
 	int (*write_dquot) (struct dquot *);		/* Ordinary dquot write */
@@ -307,12 +311,14 @@
 	int (*release_dquot) (struct dquot *);		/* Quota is going to be deleted from disk */
 	int (*mark_dirty) (struct dquot *);		/* Dquot is marked dirty */
 	int (*write_info) (struct super_block *, int);	/* Write of quota "superblock" */
+#ifndef SYNO_DQUOT_UPGRADE
 	/* reserve quota for delayed block allocation */
 	int (*reserve_space) (struct inode *, qsize_t, int);
 	/* claim reserved quota for delayed alloc */
 	int (*claim_space) (struct inode *, qsize_t);
 	/* release rsved quota for delayed alloc */
 	void (*release_rsv) (struct inode *, qsize_t);
+#endif
 	/* get reserved quota for delayed alloc, value returned is managed by
 	 * quota code only */
 	qsize_t *(*get_reserved_space) (struct inode *);
Index: include/linux/quotaops.h
===================================================================
RCS file: /cvs/projects/linux-2.6.32/include/linux/quotaops.h,v
retrieving revision 1.2
diff -b -u -r1.2 quotaops.h
--- include/linux/quotaops.h	3 May 2010 13:19:18 -0000	1.2
+++ include/linux/quotaops.h	29 Jun 2010 07:49:28 -0000
@@ -9,6 +9,12 @@
 
 #include <linux/fs.h>
 
+#ifdef SYNO_DQUOT_UPGRADE
+#define DQUOT_SPACE_WARN	0x1
+#define DQUOT_SPACE_RESERVE	0x2
+#define DQUOT_SPACE_NOFAIL	0x4
+#endif
+
 static inline struct quota_info *sb_dqopt(struct super_block *sb)
 {
 	return &sb->s_dquot;
@@ -40,14 +46,27 @@
 struct dquot *dquot_alloc(struct super_block *sb, int type);
 void dquot_destroy(struct dquot *dquot);
 
+#ifdef SYNO_DQUOT_UPGRADE
+int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags);
+void __dquot_free_space(struct inode *inode, qsize_t number, int flags);
+#else
 int dquot_alloc_space(struct inode *inode, qsize_t number, int prealloc);
 int dquot_alloc_inode(const struct inode *inode, qsize_t number);
+#endif
 
+#ifdef SYNO_DQUOT_UPGRADE
+int dquot_alloc_inode(const struct inode *inode, qsize_t number);
+#else
 int dquot_reserve_space(struct inode *inode, qsize_t number, int prealloc);
 int dquot_claim_space(struct inode *inode, qsize_t number);
 void dquot_release_reserved_space(struct inode *inode, qsize_t number);
+#endif
 
+#ifdef SYNO_DQUOT_UPGRADE
+int dquot_claim_space_nodirty(struct inode *inode, qsize_t number);
+#else
 int dquot_free_space(struct inode *inode, qsize_t number);
+#endif
 int dquot_free_inode(const struct inode *inode, qsize_t number);
 
 int dquot_transfer(struct inode *inode, struct iattr *iattr);
@@ -153,6 +172,7 @@
 		inode->i_sb->dq_op->initialize(inode, -1);
 }
 
+#ifndef SYNO_DQUOT_UPGRADE
 /* The following allocation/freeing/transfer functions *must* be called inside
  * a transaction (deadlocks possible otherwise) */
 static inline int vfs_dq_prealloc_space_nodirty(struct inode *inode, qsize_t nr)
@@ -206,6 +226,7 @@
 		inode_add_rsv_space(inode, nr);
 	return 0;
 }
+#endif
 
 static inline int vfs_dq_alloc_inode(struct inode *inode)
 {
@@ -217,6 +238,7 @@
 	return 0;
 }
 
+#ifndef SYNO_DQUOT_UPGRADE
 /*
  * Convert in-memory reserved quotas to real consumed quotas
  */
@@ -257,6 +279,7 @@
 	vfs_dq_free_space_nodirty(inode, nr);
 	mark_inode_dirty(inode);
 }
+#endif
 
 static inline void vfs_dq_free_inode(struct inode *inode)
 {
@@ -363,6 +386,28 @@
 	return 0;
 }
 
+#ifdef SYNO_DQUOT_UPGRADE
+static inline int __dquot_alloc_space(struct inode *inode, qsize_t number,
+		int flags)
+{
+	if (!(flags & DQUOT_SPACE_RESERVE))
+		inode_add_bytes(inode, number);
+	return 0;
+}
+
+static inline void __dquot_free_space(struct inode *inode, qsize_t number,
+		int flags)
+{
+	if (!(flags & DQUOT_SPACE_RESERVE))
+		inode_sub_bytes(inode, number);
+}
+
+static inline int dquot_claim_space_nodirty(struct inode *inode, qsize_t number)
+{
+	inode_add_bytes(inode, number);
+	return 0;
+}
+#else
 static inline int vfs_dq_prealloc_space_nodirty(struct inode *inode, qsize_t nr)
 {
 	inode_add_bytes(inode, nr);
@@ -415,9 +460,104 @@
 	vfs_dq_free_space_nodirty(inode, nr);
 	mark_inode_dirty(inode);
 }	
-
+#endif
 #endif /* CONFIG_QUOTA */
 
+#ifdef SYNO_DQUOT_UPGRADE
+static inline int dquot_alloc_space_nodirty(struct inode *inode, qsize_t nr)
+{
+	return __dquot_alloc_space(inode, nr, DQUOT_SPACE_WARN);
+}
+
+static inline void dquot_alloc_space_nofail(struct inode *inode, qsize_t nr)
+{
+	__dquot_alloc_space(inode, nr, DQUOT_SPACE_WARN|DQUOT_SPACE_NOFAIL);
+	mark_inode_dirty(inode);
+}
+
+static inline int dquot_alloc_space(struct inode *inode, qsize_t nr)
+{
+	int ret;
+
+	ret = dquot_alloc_space_nodirty(inode, nr);
+	if (!ret)
+		mark_inode_dirty(inode);
+	return ret;
+}
+
+static inline int dquot_alloc_block_nodirty(struct inode *inode, qsize_t nr)
+{
+	return dquot_alloc_space_nodirty(inode, nr << inode->i_blkbits);
+}
+
+static inline void dquot_alloc_block_nofail(struct inode *inode, qsize_t nr)
+{
+	dquot_alloc_space_nofail(inode, nr << inode->i_blkbits);
+}
+
+static inline int dquot_alloc_block(struct inode *inode, qsize_t nr)
+{
+	return dquot_alloc_space(inode, nr << inode->i_blkbits);
+}
+
+static inline int dquot_prealloc_block_nodirty(struct inode *inode, qsize_t nr)
+{
+	return __dquot_alloc_space(inode, nr << inode->i_blkbits, 0);
+}
+
+static inline int dquot_prealloc_block(struct inode *inode, qsize_t nr)
+{
+	int ret;
+
+	ret = dquot_prealloc_block_nodirty(inode, nr);
+	if (!ret)
+		mark_inode_dirty(inode);
+	return ret;
+}
+
+static inline int dquot_reserve_block(struct inode *inode, qsize_t nr)
+{
+	return __dquot_alloc_space(inode, nr << inode->i_blkbits,
+				DQUOT_SPACE_WARN|DQUOT_SPACE_RESERVE);
+}
+
+static inline int dquot_claim_block(struct inode *inode, qsize_t nr)
+{
+	int ret;
+
+	ret = dquot_claim_space_nodirty(inode, nr << inode->i_blkbits);
+	if (!ret)
+		mark_inode_dirty(inode);
+	return ret;
+}
+
+static inline void dquot_free_space_nodirty(struct inode *inode, qsize_t nr)
+{
+	__dquot_free_space(inode, nr, 0);
+}
+
+static inline void dquot_free_space(struct inode *inode, qsize_t nr)
+{
+	dquot_free_space_nodirty(inode, nr);
+	mark_inode_dirty(inode);
+}
+
+static inline void dquot_free_block_nodirty(struct inode *inode, qsize_t nr)
+{
+	dquot_free_space_nodirty(inode, nr << inode->i_blkbits);
+}
+
+static inline void dquot_free_block(struct inode *inode, qsize_t nr)
+{
+	dquot_free_space(inode, nr << inode->i_blkbits);
+}
+
+static inline void dquot_release_reservation_block(struct inode *inode,
+		qsize_t nr)
+{
+	__dquot_free_space(inode, nr << inode->i_blkbits, DQUOT_SPACE_RESERVE);
+}
+#else
 static inline int vfs_dq_prealloc_block_nodirty(struct inode *inode, qsize_t nr)
 {
 	return vfs_dq_prealloc_space_nodirty(inode, nr << inode->i_blkbits);
@@ -463,5 +603,5 @@
 {
 	vfs_dq_free_space(inode, nr << inode->i_blkbits);
 }
-
+#endif
 #endif /* _LINUX_QUOTAOPS_ */
Index: include/linux/syno.h
===================================================================
RCS file: /cvs/projects/linux-2.6.32/include/linux/syno.h,v
retrieving revision 1.32
diff -b -u -r1.32 syno.h
--- include/linux/syno.h	24 Jun 2010 13:50:13 -0000	1.32
+++ include/linux/syno.h	29 Jun 2010 07:49:28 -0000
@@ -781,6 +781,13 @@
 
 /******************************* File System **************************************/
 /**
+ * Fix bug #15018
+ * Upgrade dquot for correct.
+ * patches: 26245c9, 44338711, 5dd4056d, 56246f9a, 0e05842b, 72b8ab9.
+ */
+#define SYNO_DQUOT_UPGRADE
+
+/**
  * Dsc: Add syno force umount function.  It will scan all the
  * opened files which are on the mounted file system. And force
  * to decrease it's f_ount, d_count, and mnt_count.  After
