[Pkg-lustre-svn-commit] updated: [c4ed83a] lustre 1.8.1 has support for 2.6.27 sles11 kernels .. backported some features from the sles11 kernel to get the 2.6.27 support running

Patrick Winnertz winnie at debian.org
Thu Oct 8 12:42:47 UTC 2009


The following commit has been merged in the master branch:
commit c4ed83af03da935579d3265cda8d540dd3e21d99
Author: Patrick Winnertz <winnie at debian.org>
Date:   Thu Oct 8 14:40:14 2009 +0200

    lustre 1.8.1 has support for 2.6.27 sles11 kernels .. backported some
    features from the sles11 kernel to get the 2.6.27 support running
    
    Signed-off-by: Patrick Winnertz <winnie at debian.org>

diff --git a/debian/rules b/debian/rules
index 5878018..0b6acf8 100755
--- a/debian/rules
+++ b/debian/rules
@@ -30,7 +30,7 @@ TOP_DIR:=$(shell pwd)
 
 # Lustre version to use
 VERSION=`cat $(TOP_DIR)/debian/lustre-version`
-SUPPORTED_KERNELS=2.6.18 2.6.20 2.6.22
+SUPPORTED_KERNELS=2.6.18 2.6.20 2.6.22 2.6.24 2.6.26 2.6.27
 UPVERSION=`head -n1 $(TOP_DIR)/debian/changelog | awk '{print $$2}' | sed -e 's%[()]%%g'`
 
 # Packages
diff --git a/lustre/kernel_patches/patches/md-mmp-unplug-dev-2.6.27-vanilla.patch b/lustre/kernel_patches/patches/md-mmp-unplug-dev-2.6.27-vanilla.patch
new file mode 100644
index 0000000..c758cba
--- /dev/null
+++ b/lustre/kernel_patches/patches/md-mmp-unplug-dev-2.6.27-vanilla.patch
@@ -0,0 +1,22 @@
+Index: linux-2.6.27.36/drivers/md/raid5.c
+===================================================================
+--- linux-2.6.27.36.orig/drivers/md/raid5.c	2009-10-05 17:19:01.000000000 +0200
++++ linux-2.6.27.36/drivers/md/raid5.c	2009-10-08 15:06:10.000000000 +0200
+@@ -1726,6 +1726,8 @@
+ 		bi->bi_next = *bip;
+ 	*bip = bi;
+ 	bi->bi_phys_segments ++;
++        if (bio_sync(bi) && !forwrite)
++               clear_bit(R5_UPTODATE, &sh->dev[dd_idx].flags); /* force to read from disk. */
+ 	spin_unlock_irq(&conf->device_lock);
+ 	spin_unlock(&sh->lock);
+ 
+@@ -3478,6 +3480,8 @@
+ 
+ 		bio_endio(bi, 0);
+ 	}
++	if (bio_sync(bi))
++		raid5_unplug_device(q);
+ 	return 0;
+ }
+ 
diff --git a/lustre/kernel_patches/patches/quota-Split-off-quota-tree-handling-into-a-separate.patch b/lustre/kernel_patches/patches/quota-Split-off-quota-tree-handling-into-a-separate.patch
new file mode 100644
index 0000000..cc7e6b2
--- /dev/null
+++ b/lustre/kernel_patches/patches/quota-Split-off-quota-tree-handling-into-a-separate.patch
@@ -0,0 +1,1593 @@
+From: Jan Kara <jack at suse.cz>
+References: fate#302681
+Subject: [PATCH 12/28] quota: Split off quota tree handling into a separate file
+Patch-mainline: 2.6.29?
+
+There is going to be a new version of quota format having 64-bit
+quota limits and a new quota format for OCFS2. They are both
+going to use the same tree structure as VFSv0 quota format. So
+split out tree handling into a separate file and make size of
+leaf blocks, amount of space usable in each block (needed for
+checksumming) and structures contained in them configurable
+so that the code can be shared.
+
+Signed-off-by: Jan Kara <jack at suse.cz>
+---
+ fs/Kconfig                  |    5 
+ fs/Makefile                 |    1 
+ fs/quota_tree.c             |  645 ++++++++++++++++++++++++++++++++++++++++++++
+ fs/quota_tree.h             |   25 +
+ fs/quota_v2.c               |  598 +++-------------------------------------
+ fs/quotaio_v2.h             |   33 --
+ include/linux/dqblk_qtree.h |   56 +++
+ include/linux/dqblk_v2.h    |   19 -
+ 8 files changed, 800 insertions(+), 582 deletions(-)
+ create mode 100644 fs/quota_tree.c
+ create mode 100644 fs/quota_tree.h
+ create mode 100644 include/linux/dqblk_qtree.h
+
+Index: linux-2.6.27.36/fs/Kconfig
+===================================================================
+--- linux-2.6.27.36.orig/fs/Kconfig	2009-10-05 17:19:01.000000000 +0200
++++ linux-2.6.27.36/fs/Kconfig	2009-10-08 16:32:48.000000000 +0200
+@@ -569,6 +569,10 @@
+ 	  Note that this behavior is currently deprecated and may go away in
+ 	  future. Please use notification via netlink socket instead.
+ 
++# Generic support for tree structured quota files. Seleted when needed.
++config QUOTA_TREE
++	 tristate
++
+ config QFMT_V1
+ 	tristate "Old quota format support"
+ 	depends on QUOTA
+@@ -580,6 +584,7 @@
+ config QFMT_V2
+ 	tristate "Quota format v2 support"
+ 	depends on QUOTA
++	select QUOTA_TREE
+ 	help
+ 	  This quota format allows using quotas with 32-bit UIDs/GIDs. If you
+ 	  need this functionality say Y here.
+Index: linux-2.6.27.36/fs/Makefile
+===================================================================
+--- linux-2.6.27.36.orig/fs/Makefile	2009-10-05 17:19:01.000000000 +0200
++++ linux-2.6.27.36/fs/Makefile	2009-10-08 16:32:48.000000000 +0200
+@@ -53,6 +53,7 @@
+ obj-$(CONFIG_QUOTA)		+= dquot.o
+ obj-$(CONFIG_QFMT_V1)		+= quota_v1.o
+ obj-$(CONFIG_QFMT_V2)		+= quota_v2.o
++obj-$(CONFIG_QUOTA_TREE)	+= quota_tree.o
+ obj-$(CONFIG_QUOTACTL)		+= quota.o
+ 
+ obj-$(CONFIG_DNOTIFY)		+= dnotify.o
+Index: linux-2.6.27.36/include/linux/quotaio_v2.h
+===================================================================
+--- linux-2.6.27.36.orig/include/linux/quotaio_v2.h	2009-10-05 17:19:01.000000000 +0200
++++ linux-2.6.27.36/include/linux/quotaio_v2.h	2009-10-08 16:32:48.000000000 +0200
+@@ -21,6 +21,12 @@
+ 	0		/* GRPQUOTA */\
+ }
+ 
++/* First generic header */
++struct v2_disk_dqheader {
++	__le32 dqh_magic;	/* Magic number identifying file */
++	__le32 dqh_version;	/* File version */
++};
++
+ /*
+  * The following structure defines the format of the disk quota file
+  * (as it appears on disk) - the file is a radix tree whose leaves point
+@@ -38,15 +44,6 @@
+ 	__le64 dqb_itime;	/* time limit for excessive inode use */
+ };
+ 
+-/*
+- * Here are header structures as written on disk and their in-memory copies
+- */
+-/* First generic header */
+-struct v2_disk_dqheader {
+-	__le32 dqh_magic;	/* Magic number identifying file */
+-	__le32 dqh_version;	/* File version */
+-};
+-
+ /* Header with type and version specific information */
+ struct v2_disk_dqinfo {
+ 	__le32 dqi_bgrace;	/* Time before block soft limit becomes hard limit */
+@@ -57,23 +54,7 @@
+ 	__le32 dqi_free_entry;	/* Number of block with at least one free entry */
+ };
+ 
+-/*
+- *  Structure of header of block with quota structures. It is padded to 16 bytes so
+- *  there will be space for exactly 21 quota-entries in a block
+- */
+-struct v2_disk_dqdbheader {
+-	__le32 dqdh_next_free;	/* Number of next block with free entry */
+-	__le32 dqdh_prev_free;	/* Number of previous block with free entry */
+-	__le16 dqdh_entries;	/* Number of valid entries in block */
+-	__le16 dqdh_pad1;
+-	__le32 dqdh_pad2;
+-};
+-
+ #define V2_DQINFOOFF	sizeof(struct v2_disk_dqheader)	/* Offset of info header in file */
+-#define V2_DQBLKSIZE_BITS	10
+-#define V2_DQBLKSIZE	(1 << V2_DQBLKSIZE_BITS)	/* Size of block with quota structures */
+-#define V2_DQTREEOFF	1		/* Offset of tree in file in blocks */
+-#define V2_DQTREEDEPTH	4		/* Depth of quota tree */
+-#define V2_DQSTRINBLK	((V2_DQBLKSIZE - sizeof(struct v2_disk_dqdbheader)) / sizeof(struct v2_disk_dqblk))	/* Number of entries in one blocks */
++#define V2_DQBLKSIZE_BITS 10				/* Size of leaf block in tree */
+ 
+ #endif /* _LINUX_QUOTAIO_V2_H */
+Index: linux-2.6.27.36/fs/quota_tree.c
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.27.36/fs/quota_tree.c	2009-10-08 16:32:48.000000000 +0200
+@@ -0,0 +1,645 @@
++/*
++ *	vfsv0 quota IO operations on file
++ */
++
++#include <linux/errno.h>
++#include <linux/fs.h>
++#include <linux/mount.h>
++#include <linux/dqblk_v2.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/quotaops.h>
++
++#include <asm/byteorder.h>
++
++#include "quota_tree.h"
++
++MODULE_AUTHOR("Jan Kara");
++MODULE_DESCRIPTION("Quota trie support");
++MODULE_LICENSE("GPL");
++
++#define __QUOTA_QT_PARANOIA
++
++typedef char *dqbuf_t;
++
++static int get_index(struct qtree_mem_dqinfo *info, qid_t id, int depth)
++{
++	unsigned int epb = info->dqi_usable_bs >> 2;
++
++	depth = info->dqi_qtree_depth - depth - 1;
++	while (depth--)
++		id /= epb;
++	return id % epb;
++}
++
++/* Number of entries in one blocks */
++static inline int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info)
++{
++	return (info->dqi_usable_bs - sizeof(struct qt_disk_dqdbheader))
++	       / info->dqi_entry_size;
++}
++
++static dqbuf_t getdqbuf(size_t size)
++{
++	dqbuf_t buf = kmalloc(size, GFP_NOFS);
++	if (!buf)
++		printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n");
++	return buf;
++}
++
++static inline void freedqbuf(dqbuf_t buf)
++{
++	kfree(buf);
++}
++
++static inline ssize_t read_blk(struct qtree_mem_dqinfo *info, uint blk, dqbuf_t buf)
++{
++	struct super_block *sb = info->dqi_sb;
++
++	memset(buf, 0, info->dqi_usable_bs);
++	return sb->s_op->quota_read(sb, info->dqi_type, (char *)buf,
++	       info->dqi_usable_bs, blk << info->dqi_blocksize_bits);
++}
++
++static inline ssize_t write_blk(struct qtree_mem_dqinfo *info, uint blk, dqbuf_t buf)
++{
++	struct super_block *sb = info->dqi_sb;
++
++	return sb->s_op->quota_write(sb, info->dqi_type, (char *)buf,
++	       info->dqi_usable_bs, blk << info->dqi_blocksize_bits);
++}
++
++/* Remove empty block from list and return it */
++static int get_free_dqblk(struct qtree_mem_dqinfo *info)
++{
++	dqbuf_t buf = getdqbuf(info->dqi_usable_bs);
++	struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;
++	int ret, blk;
++
++	if (!buf)
++		return -ENOMEM;
++	if (info->dqi_free_blk) {
++		blk = info->dqi_free_blk;
++		ret = read_blk(info, blk, buf);
++		if (ret < 0)
++			goto out_buf;
++		info->dqi_free_blk = le32_to_cpu(dh->dqdh_next_free);
++	}
++	else {
++		memset(buf, 0, info->dqi_usable_bs);
++		/* Assure block allocation... */
++		ret = write_blk(info, info->dqi_blocks, buf);
++		if (ret < 0)
++			goto out_buf;
++		blk = info->dqi_blocks++;
++	}
++	mark_info_dirty(info->dqi_sb, info->dqi_type);
++	ret = blk;
++out_buf:
++	freedqbuf(buf);
++	return ret;
++}
++
++/* Insert empty block to the list */
++static int put_free_dqblk(struct qtree_mem_dqinfo *info, dqbuf_t buf, uint blk)
++{
++	struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;
++	int err;
++
++	dh->dqdh_next_free = cpu_to_le32(info->dqi_free_blk);
++	dh->dqdh_prev_free = cpu_to_le32(0);
++	dh->dqdh_entries = cpu_to_le16(0);
++	err = write_blk(info, blk, buf);
++	if (err < 0)
++		return err;
++	info->dqi_free_blk = blk;
++	mark_info_dirty(info->dqi_sb, info->dqi_type);
++	return 0;
++}
++
++/* Remove given block from the list of blocks with free entries */
++static int remove_free_dqentry(struct qtree_mem_dqinfo *info, dqbuf_t buf, uint blk)
++{
++	dqbuf_t tmpbuf = getdqbuf(info->dqi_usable_bs);
++	struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;
++	uint nextblk = le32_to_cpu(dh->dqdh_next_free);
++	uint prevblk = le32_to_cpu(dh->dqdh_prev_free);
++	int err;
++
++	if (!tmpbuf)
++		return -ENOMEM;
++	if (nextblk) {
++		err = read_blk(info, nextblk, tmpbuf);
++		if (err < 0)
++			goto out_buf;
++		((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free =
++							dh->dqdh_prev_free;
++		err = write_blk(info, nextblk, tmpbuf);
++		if (err < 0)
++			goto out_buf;
++	}
++	if (prevblk) {
++		err = read_blk(info, prevblk, tmpbuf);
++		if (err < 0)
++			goto out_buf;
++		((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_next_free =
++							dh->dqdh_next_free;
++		err = write_blk(info, prevblk, tmpbuf);
++		if (err < 0)
++			goto out_buf;
++	} else {
++		info->dqi_free_entry = nextblk;
++		mark_info_dirty(info->dqi_sb, info->dqi_type);
++	}
++	freedqbuf(tmpbuf);
++	dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0);
++	/* No matter whether write succeeds block is out of list */
++	if (write_blk(info, blk, buf) < 0)
++		printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk);
++	return 0;
++out_buf:
++	freedqbuf(tmpbuf);
++	return err;
++}
++
++/* Insert given block to the beginning of list with free entries */
++static int insert_free_dqentry(struct qtree_mem_dqinfo *info, dqbuf_t buf, uint blk)
++{
++	dqbuf_t tmpbuf = getdqbuf(info->dqi_usable_bs);
++	struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;
++	int err;
++
++	if (!tmpbuf)
++		return -ENOMEM;
++	dh->dqdh_next_free = cpu_to_le32(info->dqi_free_entry);
++	dh->dqdh_prev_free = cpu_to_le32(0);
++	err = write_blk(info, blk, buf);
++	if (err < 0)
++		goto out_buf;
++	if (info->dqi_free_entry) {
++		err = read_blk(info, info->dqi_free_entry, tmpbuf);
++		if (err < 0)
++			goto out_buf;
++		((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free =
++							cpu_to_le32(blk);
++		err = write_blk(info, info->dqi_free_entry, tmpbuf);
++		if (err < 0)
++			goto out_buf;
++	}
++	freedqbuf(tmpbuf);
++	info->dqi_free_entry = blk;
++	mark_info_dirty(info->dqi_sb, info->dqi_type);
++	return 0;
++out_buf:
++	freedqbuf(tmpbuf);
++	return err;
++}
++
++/* Is the entry in the block free? */
++int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk)
++{
++	int i;
++
++	for (i = 0; i < info->dqi_entry_size; i++)
++		if (disk[i])
++			return 0;
++	return 1;
++}
++EXPORT_SYMBOL(qtree_entry_unused);
++
++/* Find space for dquot */
++static uint find_free_dqentry(struct qtree_mem_dqinfo *info,
++			      struct dquot *dquot, int *err)
++{
++	uint blk, i;
++	struct qt_disk_dqdbheader *dh;
++	dqbuf_t buf = getdqbuf(info->dqi_usable_bs);
++	char *ddquot;
++
++	*err = 0;
++	if (!buf) {
++		*err = -ENOMEM;
++		return 0;
++	}
++	dh = (struct qt_disk_dqdbheader *)buf;
++	if (info->dqi_free_entry) {
++		blk = info->dqi_free_entry;
++		*err = read_blk(info, blk, buf);
++		if (*err < 0)
++			goto out_buf;
++	} else {
++		blk = get_free_dqblk(info);
++		if ((int)blk < 0) {
++			*err = blk;
++			freedqbuf(buf);
++			return 0;
++		}
++		memset(buf, 0, info->dqi_usable_bs);
++		/* This is enough as block is already zeroed and entry list is empty... */
++		info->dqi_free_entry = blk;
++		mark_info_dirty(dquot->dq_sb, dquot->dq_type);
++	}
++	/* Block will be full? */
++	if (le16_to_cpu(dh->dqdh_entries) + 1 >= qtree_dqstr_in_blk(info)) {
++		*err = remove_free_dqentry(info, buf, blk);
++		if (*err < 0) {
++			printk(KERN_ERR "VFS: find_free_dqentry(): Can't "
++			       "remove block (%u) from entry free list.\n",
++			       blk);
++			goto out_buf;
++		}
++	}
++	le16_add_cpu(&dh->dqdh_entries, 1);
++	/* Find free structure in block */
++	for (i = 0, ddquot = ((char *)buf) + sizeof(struct qt_disk_dqdbheader);
++	     i < qtree_dqstr_in_blk(info) && !qtree_entry_unused(info, ddquot);
++	     i++, ddquot += info->dqi_entry_size);
++#ifdef __QUOTA_QT_PARANOIA
++	if (i == qtree_dqstr_in_blk(info)) {
++		printk(KERN_ERR "VFS: find_free_dqentry(): Data block full "
++				"but it shouldn't.\n");
++		*err = -EIO;
++		goto out_buf;
++	}
++#endif
++	*err = write_blk(info, blk, buf);
++	if (*err < 0) {
++		printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota "
++				"data block %u.\n", blk);
++		goto out_buf;
++	}
++	dquot->dq_off = (blk << info->dqi_blocksize_bits) +
++			sizeof(struct qt_disk_dqdbheader) +
++			i * info->dqi_entry_size;
++	freedqbuf(buf);
++	return blk;
++out_buf:
++	freedqbuf(buf);
++	return 0;
++}
++
++/* Insert reference to structure into the trie */
++static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
++			  uint *treeblk, int depth)
++{
++	dqbuf_t buf = getdqbuf(info->dqi_usable_bs);
++	int ret = 0, newson = 0, newact = 0;
++	__le32 *ref;
++	uint newblk;
++
++	if (!buf)
++		return -ENOMEM;
++	if (!*treeblk) {
++		ret = get_free_dqblk(info);
++		if (ret < 0)
++			goto out_buf;
++		*treeblk = ret;
++		memset(buf, 0, info->dqi_usable_bs);
++		newact = 1;
++	} else {
++		ret = read_blk(info, *treeblk, buf);
++		if (ret < 0) {
++			printk(KERN_ERR "VFS: Can't read tree quota block "
++					"%u.\n", *treeblk);
++			goto out_buf;
++		}
++	}
++	ref = (__le32 *)buf;
++	newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
++	if (!newblk)
++		newson = 1;
++	if (depth == info->dqi_qtree_depth - 1) {
++#ifdef __QUOTA_QT_PARANOIA
++		if (newblk) {
++			printk(KERN_ERR "VFS: Inserting already present quota "
++					"entry (block %u).\n",
++			       le32_to_cpu(ref[get_index(info,
++						dquot->dq_id, depth)]));
++			ret = -EIO;
++			goto out_buf;
++		}
++#endif
++		newblk = find_free_dqentry(info, dquot, &ret);
++	} else {
++		ret = do_insert_tree(info, dquot, &newblk, depth+1);
++	}
++	if (newson && ret >= 0) {
++		ref[get_index(info, dquot->dq_id, depth)] =
++							cpu_to_le32(newblk);
++		ret = write_blk(info, *treeblk, buf);
++	} else if (newact && ret < 0) {
++		put_free_dqblk(info, buf, *treeblk);
++	}
++out_buf:
++	freedqbuf(buf);
++	return ret;
++}
++
++/* Wrapper for inserting quota structure into tree */
++static inline int dq_insert_tree(struct qtree_mem_dqinfo *info,
++				 struct dquot *dquot)
++{
++	int tmp = QT_TREEOFF;
++	return do_insert_tree(info, dquot, &tmp, 0);
++}
++
++/*
++ *	We don't have to be afraid of deadlocks as we never have quotas on quota files...
++ */
++int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
++{
++	int type = dquot->dq_type;
++	struct super_block *sb = dquot->dq_sb;
++	ssize_t ret;
++	dqbuf_t ddquot = getdqbuf(info->dqi_entry_size);
++
++	if (!ddquot)
++		return -ENOMEM;
++
++	/* dq_off is guarded by dqio_mutex */
++	if (!dquot->dq_off) {
++		ret = dq_insert_tree(info, dquot);
++		if (ret < 0) {
++			printk(KERN_ERR "VFS: Error %zd occurred while "
++					"creating quota.\n", ret);
++			freedqbuf(ddquot);
++			return ret;
++		}
++	}
++	spin_lock(&dq_data_lock);
++	info->dqi_ops->mem2disk_dqblk(ddquot, dquot);
++	spin_unlock(&dq_data_lock);
++	ret = sb->s_op->quota_write(sb, type, (char *)ddquot,
++					info->dqi_entry_size, dquot->dq_off);
++	if (ret != info->dqi_entry_size) {
++		printk(KERN_WARNING "VFS: dquota write failed on dev %s\n",
++		       sb->s_id);
++		if (ret >= 0)
++			ret = -ENOSPC;
++	} else {
++		ret = 0;
++	}
++	dqstats.writes++;
++	freedqbuf(ddquot);
++
++	return ret;
++}
++EXPORT_SYMBOL(qtree_write_dquot);
++
++/* Free dquot entry in data block */
++static int free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot,
++			uint blk)
++{
++	struct qt_disk_dqdbheader *dh;
++	dqbuf_t buf = getdqbuf(info->dqi_usable_bs);
++	int ret = 0;
++
++	if (!buf)
++		return -ENOMEM;
++	if (dquot->dq_off >> info->dqi_blocksize_bits != blk) {
++		printk(KERN_ERR "VFS: Quota structure has offset to other "
++		  "block (%u) than it should (%u).\n", blk,
++		  (uint)(dquot->dq_off >> info->dqi_blocksize_bits));
++		goto out_buf;
++	}
++	ret = read_blk(info, blk, buf);
++	if (ret < 0) {
++		printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk);
++		goto out_buf;
++	}
++	dh = (struct qt_disk_dqdbheader *)buf;
++	le16_add_cpu(&dh->dqdh_entries, -1);
++	if (!le16_to_cpu(dh->dqdh_entries)) {	/* Block got free? */
++		ret = remove_free_dqentry(info, buf, blk);
++		if (ret >= 0)
++			ret = put_free_dqblk(info, buf, blk);
++		if (ret < 0) {
++			printk(KERN_ERR "VFS: Can't move quota data block (%u) "
++			  "to free list.\n", blk);
++			goto out_buf;
++		}
++	} else {
++		memset(buf +
++		       (dquot->dq_off & ((1 << info->dqi_blocksize_bits) - 1)),
++		       0, info->dqi_entry_size);
++		if (le16_to_cpu(dh->dqdh_entries) ==
++		    qtree_dqstr_in_blk(info) - 1) {
++			/* Insert will write block itself */
++			ret = insert_free_dqentry(info, buf, blk);
++			if (ret < 0) {
++				printk(KERN_ERR "VFS: Can't insert quota data "
++				       "block (%u) to free entry list.\n", blk);
++				goto out_buf;
++			}
++		} else {
++			ret = write_blk(info, blk, buf);
++			if (ret < 0) {
++				printk(KERN_ERR "VFS: Can't write quota data "
++				  "block %u\n", blk);
++				goto out_buf;
++			}
++		}
++	}
++	dquot->dq_off = 0;	/* Quota is now unattached */
++out_buf:
++	freedqbuf(buf);
++	return ret;
++}
++
++/* Remove reference to dquot from tree */
++static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
++		       uint *blk, int depth)
++{
++	dqbuf_t buf = getdqbuf(info->dqi_usable_bs);
++	int ret = 0;
++	uint newblk;
++	__le32 *ref = (__le32 *)buf;
++
++	if (!buf)
++		return -ENOMEM;
++	ret = read_blk(info, *blk, buf);
++	if (ret < 0) {
++		printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk);
++		goto out_buf;
++	}
++	newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
++	if (depth == info->dqi_qtree_depth - 1) {
++		ret = free_dqentry(info, dquot, newblk);
++		newblk = 0;
++	} else {
++		ret = remove_tree(info, dquot, &newblk, depth+1);
++	}
++	if (ret >= 0 && !newblk) {
++		int i;
++		ref[get_index(info, dquot->dq_id, depth)] = cpu_to_le32(0);
++		/* Block got empty? */
++		for (i = 0;
++		     i < (info->dqi_usable_bs >> 2) && !ref[i];
++		     i++);
++		/* Don't put the root block into the free block list */
++		if (i == (info->dqi_usable_bs >> 2)
++		    && *blk != QT_TREEOFF) {
++			put_free_dqblk(info, buf, *blk);
++			*blk = 0;
++		} else {
++			ret = write_blk(info, *blk, buf);
++			if (ret < 0)
++				printk(KERN_ERR "VFS: Can't write quota tree "
++				  "block %u.\n", *blk);
++		}
++	}
++out_buf:
++	freedqbuf(buf);
++	return ret;
++}
++
++/* Delete dquot from tree */
++int qtree_delete_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
++{
++	uint tmp = QT_TREEOFF;
++
++	if (!dquot->dq_off)	/* Even not allocated? */
++		return 0;
++	return remove_tree(info, dquot, &tmp, 0);
++}
++EXPORT_SYMBOL(qtree_delete_dquot);
++
++/* Find entry in block */
++static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info,
++				 struct dquot *dquot, uint blk)
++{
++	dqbuf_t buf = getdqbuf(info->dqi_usable_bs);
++	loff_t ret = 0;
++	int i;
++	char *ddquot;
++
++	if (!buf)
++		return -ENOMEM;
++	ret = read_blk(info, blk, buf);
++	if (ret < 0) {
++		printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
++		goto out_buf;
++	}
++	for (i = 0, ddquot = ((char *)buf) + sizeof(struct qt_disk_dqdbheader);
++	     i < qtree_dqstr_in_blk(info) && !info->dqi_ops->is_id(ddquot, dquot);
++	     i++, ddquot += info->dqi_entry_size);
++	if (i == qtree_dqstr_in_blk(info)) {
++		printk(KERN_ERR "VFS: Quota for id %u referenced "
++		  "but not present.\n", dquot->dq_id);
++		ret = -EIO;
++		goto out_buf;
++	} else {
++		ret = (blk << info->dqi_blocksize_bits) + sizeof(struct
++		  qt_disk_dqdbheader) + i * info->dqi_entry_size;
++	}
++out_buf:
++	freedqbuf(buf);
++	return ret;
++}
++
++/* Find entry for given id in the tree */
++static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info,
++				struct dquot *dquot, uint blk, int depth)
++{
++	dqbuf_t buf = getdqbuf(info->dqi_usable_bs);
++	loff_t ret = 0;
++	__le32 *ref = (__le32 *)buf;
++
++	if (!buf)
++		return -ENOMEM;
++	ret = read_blk(info, blk, buf);
++	if (ret < 0) {
++		printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
++		goto out_buf;
++	}
++	ret = 0;
++	blk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
++	if (!blk)	/* No reference? */
++		goto out_buf;
++	if (depth < info->dqi_qtree_depth - 1)
++		ret = find_tree_dqentry(info, dquot, blk, depth+1);
++	else
++		ret = find_block_dqentry(info, dquot, blk);
++out_buf:
++	freedqbuf(buf);
++	return ret;
++}
++
++/* Find entry for given id in the tree - wrapper function */
++static inline loff_t find_dqentry(struct qtree_mem_dqinfo *info,
++				  struct dquot *dquot)
++{
++	return find_tree_dqentry(info, dquot, QT_TREEOFF, 0);
++}
++
++int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
++{
++	int type = dquot->dq_type;
++	struct super_block *sb = dquot->dq_sb;
++	loff_t offset;
++	dqbuf_t ddquot;
++	int ret = 0;
++
++#ifdef __QUOTA_QT_PARANOIA
++	/* Invalidated quota? */
++	if (!sb_dqopt(dquot->dq_sb)->files[type]) {
++		printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
++		return -EIO;
++	}
++#endif
++	/* Do we know offset of the dquot entry in the quota file? */
++	if (!dquot->dq_off) {
++		offset = find_dqentry(info, dquot);
++		if (offset <= 0) {	/* Entry not present? */
++			if (offset < 0)
++				printk(KERN_ERR "VFS: Can't read quota "
++				  "structure for id %u.\n", dquot->dq_id);
++			dquot->dq_off = 0;
++			set_bit(DQ_FAKE_B, &dquot->dq_flags);
++			memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
++			ret = offset;
++			goto out;
++		}
++		dquot->dq_off = offset;
++	}
++	ddquot = getdqbuf(info->dqi_entry_size);
++	if (!ddquot)
++		return -ENOMEM;
++	ret = sb->s_op->quota_read(sb, type, (char *)ddquot,
++				   info->dqi_entry_size, dquot->dq_off);
++	if (ret != info->dqi_entry_size) {
++		if (ret >= 0)
++			ret = -EIO;
++		printk(KERN_ERR "VFS: Error while reading quota "
++				"structure for id %u.\n", dquot->dq_id);
++		set_bit(DQ_FAKE_B, &dquot->dq_flags);
++		memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
++		freedqbuf(ddquot);
++		goto out;
++	}
++	spin_lock(&dq_data_lock);
++	info->dqi_ops->disk2mem_dqblk(dquot, ddquot);
++	if (!dquot->dq_dqb.dqb_bhardlimit &&
++	    !dquot->dq_dqb.dqb_bsoftlimit &&
++	    !dquot->dq_dqb.dqb_ihardlimit &&
++	    !dquot->dq_dqb.dqb_isoftlimit)
++		set_bit(DQ_FAKE_B, &dquot->dq_flags);
++	spin_unlock(&dq_data_lock);
++	freedqbuf(ddquot);
++out:
++	dqstats.reads++;
++	return ret;
++}
++EXPORT_SYMBOL(qtree_read_dquot);
++
++/* Check whether dquot should not be deleted. We know we are
++ * the only one operating on dquot (thanks to dq_lock) */
++int qtree_release_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
++{
++	if (test_bit(DQ_FAKE_B, &dquot->dq_flags) && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace))
++		return qtree_delete_dquot(info, dquot);
++	return 0;
++}
++EXPORT_SYMBOL(qtree_release_dquot);
+Index: linux-2.6.27.36/fs/quota_tree.h
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.27.36/fs/quota_tree.h	2009-10-08 16:32:48.000000000 +0200
+@@ -0,0 +1,25 @@
++/*
++ *	Definitions of structures for vfsv0 quota format
++ */
++
++#ifndef _LINUX_QUOTA_TREE_H
++#define _LINUX_QUOTA_TREE_H
++
++#include <linux/types.h>
++#include <linux/quota.h>
++
++/*
++ *  Structure of header of block with quota structures. It is padded to 16 bytes so
++ *  there will be space for exactly 21 quota-entries in a block
++ */
++struct qt_disk_dqdbheader {
++	__le32 dqdh_next_free;	/* Number of next block with free entry */
++	__le32 dqdh_prev_free;	/* Number of previous block with free entry */
++	__le16 dqdh_entries;	/* Number of valid entries in block */
++	__le16 dqdh_pad1;
++	__le32 dqdh_pad2;
++};
++
++#define QT_TREEOFF	1		/* Offset of tree in file in blocks */
++
++#endif /* _LINUX_QUOTAIO_TREE_H */
+Index: linux-2.6.27.36/fs/quota_v2.c
+===================================================================
+--- linux-2.6.27.36.orig/fs/quota_v2.c	2009-10-05 17:19:01.000000000 +0200
++++ linux-2.6.27.36/fs/quota_v2.c	2009-10-08 16:34:36.000000000 +0200
+@@ -6,6 +6,7 @@
+ #include <linux/fs.h>
+ #include <linux/mount.h>
+ #include <linux/dqblk_v2.h>
++#include "quota_tree.h"
+ #include <linux/quotaio_v2.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+@@ -15,16 +16,22 @@
+ 
+ #include <asm/byteorder.h>
+ 
++
+ MODULE_AUTHOR("Jan Kara");
+ MODULE_DESCRIPTION("Quota format v2 support");
+ MODULE_LICENSE("GPL");
+ 
+ #define __QUOTA_V2_PARANOIA
+ 
+-typedef char *dqbuf_t;
+-
+-#define GETIDINDEX(id, depth) (((id) >> ((V2_DQTREEDEPTH-(depth)-1)*8)) & 0xff)
+-#define GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)buf)+sizeof(struct v2_disk_dqdbheader)))
++static void v2_mem2diskdqb(void *dp, struct dquot *dquot);
++static void v2_disk2memdqb(struct dquot *dquot, void *dp);
++static int v2_is_id(void *dp, struct dquot *dquot);
++
++static struct qtree_fmt_operations v2_qtree_ops = {
++	.mem2disk_dqblk = v2_mem2diskdqb,
++	.disk2mem_dqblk = v2_disk2memdqb,
++	.is_id = v2_is_id,
++};
+ 
+ /* Check whether given file is really vfsv0 quotafile */
+ static int v2_check_quota_file(struct super_block *sb, int type)
+@@ -50,7 +57,7 @@
+ static int v2_read_file_info(struct super_block *sb, int type)
+ {
+ 	struct v2_disk_dqinfo dinfo;
+-	struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
++	struct mem_dqinfo *info = sb_dqinfo(sb, type);
+ 	ssize_t size;
+ 
+ 	size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
+@@ -66,9 +73,16 @@
+ 	info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
+ 	info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
+ 	info->dqi_flags = le32_to_cpu(dinfo.dqi_flags);
+-	info->u.v2_i.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
+-	info->u.v2_i.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
+-	info->u.v2_i.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
++	info->u.v2_i.i.dqi_sb = sb;
++	info->u.v2_i.i.dqi_type = type;
++	info->u.v2_i.i.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
++	info->u.v2_i.i.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
++	info->u.v2_i.i.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
++	info->u.v2_i.i.dqi_blocksize_bits = V2_DQBLKSIZE_BITS;
++	info->u.v2_i.i.dqi_usable_bs = 1 << V2_DQBLKSIZE_BITS;
++	info->u.v2_i.i.dqi_qtree_depth = qtree_depth(&info->u.v2_i.i);
++	info->u.v2_i.i.dqi_entry_size = sizeof(struct v2_disk_dqblk);
++	info->u.v2_i.i.dqi_ops = &v2_qtree_ops;
+ 	return 0;
+ }
+ 
+@@ -76,7 +90,7 @@
+ static int v2_write_file_info(struct super_block *sb, int type)
+ {
+ 	struct v2_disk_dqinfo dinfo;
+-	struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
++	struct mem_dqinfo *info = sb_dqinfo(sb, type);
+ 	ssize_t size;
+ 
+ 	spin_lock(&dq_data_lock);
+@@ -85,9 +99,9 @@
+ 	dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
+ 	dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK);
+ 	spin_unlock(&dq_data_lock);
+-	dinfo.dqi_blocks = cpu_to_le32(info->u.v2_i.dqi_blocks);
+-	dinfo.dqi_free_blk = cpu_to_le32(info->u.v2_i.dqi_free_blk);
+-	dinfo.dqi_free_entry = cpu_to_le32(info->u.v2_i.dqi_free_entry);
++	dinfo.dqi_blocks = cpu_to_le32(info->u.v2_i.i.dqi_blocks);
++	dinfo.dqi_free_blk = cpu_to_le32(info->u.v2_i.i.dqi_free_blk);
++	dinfo.dqi_free_entry = cpu_to_le32(info->u.v2_i.i.dqi_free_entry);
+ 	size = sb->s_op->quota_write(sb, type, (char *)&dinfo,
+ 	       sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
+ 	if (size != sizeof(struct v2_disk_dqinfo)) {
+@@ -98,8 +112,11 @@
+ 	return 0;
+ }
+ 
+-static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d)
++static void v2_disk2memdqb(struct dquot *dquot, void *dp)
+ {
++	struct v2_disk_dqblk *d = dp, empty;
++	struct mem_dqblk *m = &dquot->dq_dqb;
++
+ 	m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
+ 	m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit);
+ 	m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes);
+@@ -108,10 +125,20 @@
+ 	m->dqb_bsoftlimit = le32_to_cpu(d->dqb_bsoftlimit);
+ 	m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
+ 	m->dqb_btime = le64_to_cpu(d->dqb_btime);
++	/* We need to escape back all-zero structure */
++	memset(&empty, 0, sizeof(struct v2_disk_dqblk));
++	empty.dqb_itime = cpu_to_le64(1);
++	if (!memcmp(&empty, dp, sizeof(struct v2_disk_dqblk)))
++		m->dqb_itime = 0;
+ }
+ 
+-static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id)
++static void v2_mem2diskdqb(void *dp, struct dquot *dquot)
+ {
++	struct v2_disk_dqblk *d = dp;
++	struct mem_dqblk *m = &dquot->dq_dqb;
++	struct qtree_mem_dqinfo *info =
++			&sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i;
++
+ 	d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
+ 	d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
+ 	d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes);
+@@ -120,553 +147,35 @@
+ 	d->dqb_bsoftlimit = cpu_to_le32(m->dqb_bsoftlimit);
+ 	d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
+ 	d->dqb_btime = cpu_to_le64(m->dqb_btime);
+-	d->dqb_id = cpu_to_le32(id);
+-}
+-
+-static dqbuf_t getdqbuf(void)
+-{
+-	dqbuf_t buf = kmalloc(V2_DQBLKSIZE, GFP_NOFS);
+-	if (!buf)
+-		printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n");
+-	return buf;
+-}
+-
+-static inline void freedqbuf(dqbuf_t buf)
+-{
+-	kfree(buf);
+-}
+-
+-static inline ssize_t read_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf)
+-{
+-	memset(buf, 0, V2_DQBLKSIZE);
+-	return sb->s_op->quota_read(sb, type, (char *)buf,
+-	       V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS);
+-}
+-
+-static inline ssize_t write_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf)
+-{
+-	return sb->s_op->quota_write(sb, type, (char *)buf,
+-	       V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS);
++	d->dqb_id = cpu_to_le32(dquot->dq_id);
++	if (qtree_entry_unused(info, dp))
++		d->dqb_itime = cpu_to_le64(1);
+ }
+ 
+-/* Remove empty block from list and return it */
+-static int get_free_dqblk(struct super_block *sb, int type)
++static int v2_is_id(void *dp, struct dquot *dquot)
+ {
+-	dqbuf_t buf = getdqbuf();
+-	struct mem_dqinfo *info = sb_dqinfo(sb, type);
+-	struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
+-	int ret, blk;
++	struct v2_disk_dqblk *d = dp;
++	struct qtree_mem_dqinfo *info =
++			&sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i;
+ 
+-	if (!buf)
+-		return -ENOMEM;
+-	if (info->u.v2_i.dqi_free_blk) {
+-		blk = info->u.v2_i.dqi_free_blk;
+-		if ((ret = read_blk(sb, type, blk, buf)) < 0)
+-			goto out_buf;
+-		info->u.v2_i.dqi_free_blk = le32_to_cpu(dh->dqdh_next_free);
+-	}
+-	else {
+-		memset(buf, 0, V2_DQBLKSIZE);
+-		/* Assure block allocation... */
+-		if ((ret = write_blk(sb, type, info->u.v2_i.dqi_blocks, buf)) < 0)
+-			goto out_buf;
+-		blk = info->u.v2_i.dqi_blocks++;
+-	}
+-	mark_info_dirty(sb, type);
+-	ret = blk;
+-out_buf:
+-	freedqbuf(buf);
+-	return ret;
+-}
+-
+-/* Insert empty block to the list */
+-static int put_free_dqblk(struct super_block *sb, int type, dqbuf_t buf, uint blk)
+-{
+-	struct mem_dqinfo *info = sb_dqinfo(sb, type);
+-	struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
+-	int err;
+-
+-	dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_blk);
+-	dh->dqdh_prev_free = cpu_to_le32(0);
+-	dh->dqdh_entries = cpu_to_le16(0);
+-	info->u.v2_i.dqi_free_blk = blk;
+-	mark_info_dirty(sb, type);
+-	/* Some strange block. We had better leave it... */
+-	if ((err = write_blk(sb, type, blk, buf)) < 0)
+-		return err;
+-	return 0;
+-}
+-
+-/* Remove given block from the list of blocks with free entries */
+-static int remove_free_dqentry(struct super_block *sb, int type, dqbuf_t buf, uint blk)
+-{
+-	dqbuf_t tmpbuf = getdqbuf();
+-	struct mem_dqinfo *info = sb_dqinfo(sb, type);
+-	struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
+-	uint nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk = le32_to_cpu(dh->dqdh_prev_free);
+-	int err;
+-
+-	if (!tmpbuf)
+-		return -ENOMEM;
+-	if (nextblk) {
+-		if ((err = read_blk(sb, type, nextblk, tmpbuf)) < 0)
+-			goto out_buf;
+-		((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = dh->dqdh_prev_free;
+-		if ((err = write_blk(sb, type, nextblk, tmpbuf)) < 0)
+-			goto out_buf;
+-	}
+-	if (prevblk) {
+-		if ((err = read_blk(sb, type, prevblk, tmpbuf)) < 0)
+-			goto out_buf;
+-		((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_next_free = dh->dqdh_next_free;
+-		if ((err = write_blk(sb, type, prevblk, tmpbuf)) < 0)
+-			goto out_buf;
+-	}
+-	else {
+-		info->u.v2_i.dqi_free_entry = nextblk;
+-		mark_info_dirty(sb, type);
+-	}
+-	freedqbuf(tmpbuf);
+-	dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0);
+-	/* No matter whether write succeeds block is out of list */
+-	if (write_blk(sb, type, blk, buf) < 0)
+-		printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk);
+-	return 0;
+-out_buf:
+-	freedqbuf(tmpbuf);
+-	return err;
+-}
+-
+-/* Insert given block to the beginning of list with free entries */
+-static int insert_free_dqentry(struct super_block *sb, int type, dqbuf_t buf, uint blk)
+-{
+-	dqbuf_t tmpbuf = getdqbuf();
+-	struct mem_dqinfo *info = sb_dqinfo(sb, type);
+-	struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
+-	int err;
+-
+-	if (!tmpbuf)
+-		return -ENOMEM;
+-	dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_entry);
+-	dh->dqdh_prev_free = cpu_to_le32(0);
+-	if ((err = write_blk(sb, type, blk, buf)) < 0)
+-		goto out_buf;
+-	if (info->u.v2_i.dqi_free_entry) {
+-		if ((err = read_blk(sb, type, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
+-			goto out_buf;
+-		((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = cpu_to_le32(blk);
+-		if ((err = write_blk(sb, type, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
+-			goto out_buf;
+-	}
+-	freedqbuf(tmpbuf);
+-	info->u.v2_i.dqi_free_entry = blk;
+-	mark_info_dirty(sb, type);
+-	return 0;
+-out_buf:
+-	freedqbuf(tmpbuf);
+-	return err;
+-}
+-
+-/* Find space for dquot */
+-static uint find_free_dqentry(struct dquot *dquot, int *err)
+-{
+-	struct super_block *sb = dquot->dq_sb;
+-	struct mem_dqinfo *info = sb_dqopt(sb)->info+dquot->dq_type;
+-	uint blk, i;
+-	struct v2_disk_dqdbheader *dh;
+-	struct v2_disk_dqblk *ddquot;
+-	struct v2_disk_dqblk fakedquot;
+-	dqbuf_t buf;
+-
+-	*err = 0;
+-	if (!(buf = getdqbuf())) {
+-		*err = -ENOMEM;
++	if (qtree_entry_unused(info, dp))
+ 		return 0;
+-	}
+-	dh = (struct v2_disk_dqdbheader *)buf;
+-	ddquot = GETENTRIES(buf);
+-	if (info->u.v2_i.dqi_free_entry) {
+-		blk = info->u.v2_i.dqi_free_entry;
+-		if ((*err = read_blk(sb, dquot->dq_type, blk, buf)) < 0)
+-			goto out_buf;
+-	}
+-	else {
+-		blk = get_free_dqblk(sb, dquot->dq_type);
+-		if ((int)blk < 0) {
+-			*err = blk;
+-			freedqbuf(buf);
+-			return 0;
+-		}
+-		memset(buf, 0, V2_DQBLKSIZE);
+-		/* This is enough as block is already zeroed and entry list is empty... */
+-		info->u.v2_i.dqi_free_entry = blk;
+-		mark_info_dirty(sb, dquot->dq_type);
+-	}
+-	if (le16_to_cpu(dh->dqdh_entries)+1 >= V2_DQSTRINBLK)	/* Block will be full? */
+-		if ((*err = remove_free_dqentry(sb, dquot->dq_type, buf, blk)) < 0) {
+-			printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk);
+-			goto out_buf;
+-		}
+-	le16_add_cpu(&dh->dqdh_entries, 1);
+-	memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
+-	/* Find free structure in block */
+-	for (i = 0; i < V2_DQSTRINBLK && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)); i++);
+-#ifdef __QUOTA_V2_PARANOIA
+-	if (i == V2_DQSTRINBLK) {
+-		printk(KERN_ERR "VFS: find_free_dqentry(): Data block full but it shouldn't.\n");
+-		*err = -EIO;
+-		goto out_buf;
+-	}
+-#endif
+-	if ((*err = write_blk(sb, dquot->dq_type, blk, buf)) < 0) {
+-		printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk);
+-		goto out_buf;
+-	}
+-	dquot->dq_off = (blk<<V2_DQBLKSIZE_BITS)+sizeof(struct v2_disk_dqdbheader)+i*sizeof(struct v2_disk_dqblk);
+-	freedqbuf(buf);
+-	return blk;
+-out_buf:
+-	freedqbuf(buf);
+-	return 0;
+-}
+-
+-/* Insert reference to structure into the trie */
+-static int do_insert_tree(struct dquot *dquot, uint *treeblk, int depth)
+-{
+-	struct super_block *sb = dquot->dq_sb;
+-	dqbuf_t buf;
+-	int ret = 0, newson = 0, newact = 0;
+-	__le32 *ref;
+-	uint newblk;
+-
+-	if (!(buf = getdqbuf()))
+-		return -ENOMEM;
+-	if (!*treeblk) {
+-		ret = get_free_dqblk(sb, dquot->dq_type);
+-		if (ret < 0)
+-			goto out_buf;
+-		*treeblk = ret;
+-		memset(buf, 0, V2_DQBLKSIZE);
+-		newact = 1;
+-	}
+-	else {
+-		if ((ret = read_blk(sb, dquot->dq_type, *treeblk, buf)) < 0) {
+-			printk(KERN_ERR "VFS: Can't read tree quota block %u.\n", *treeblk);
+-			goto out_buf;
+-		}
+-	}
+-	ref = (__le32 *)buf;
+-	newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
+-	if (!newblk)
+-		newson = 1;
+-	if (depth == V2_DQTREEDEPTH-1) {
+-#ifdef __QUOTA_V2_PARANOIA
+-		if (newblk) {
+-			printk(KERN_ERR "VFS: Inserting already present quota entry (block %u).\n", le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]));
+-			ret = -EIO;
+-			goto out_buf;
+-		}
+-#endif
+-		newblk = find_free_dqentry(dquot, &ret);
+-	}
+-	else
+-		ret = do_insert_tree(dquot, &newblk, depth+1);
+-	if (newson && ret >= 0) {
+-		ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(newblk);
+-		ret = write_blk(sb, dquot->dq_type, *treeblk, buf);
+-	}
+-	else if (newact && ret < 0)
+-		put_free_dqblk(sb, dquot->dq_type, buf, *treeblk);
+-out_buf:
+-	freedqbuf(buf);
+-	return ret;
++	return le32_to_cpu(d->dqb_id) == dquot->dq_id;
+ }
+ 
+-/* Wrapper for inserting quota structure into tree */
+-static inline int dq_insert_tree(struct dquot *dquot)
++static int v2_read_dquot(struct dquot *dquot)
+ {
+-	int tmp = V2_DQTREEOFF;
+-	return do_insert_tree(dquot, &tmp, 0);
++	return qtree_read_dquot(&sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i, dquot);
+ }
+ 
+-/*
+- *	We don't have to be afraid of deadlocks as we never have quotas on quota files...
+- */
+ static int v2_write_dquot(struct dquot *dquot)
+ {
+-	int type = dquot->dq_type;
+-	ssize_t ret;
+-	struct v2_disk_dqblk ddquot, empty;
+-
+-	/* dq_off is guarded by dqio_mutex */
+-	if (!dquot->dq_off)
+-		if ((ret = dq_insert_tree(dquot)) < 0) {
+-			printk(KERN_ERR "VFS: Error %zd occurred while creating quota.\n", ret);
+-			return ret;
+-		}
+-	spin_lock(&dq_data_lock);
+-	mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
+-	/* Argh... We may need to write structure full of zeroes but that would be
+-	 * treated as an empty place by the rest of the code. Format change would
+-	 * be definitely cleaner but the problems probably are not worth it */
+-	memset(&empty, 0, sizeof(struct v2_disk_dqblk));
+-	if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
+-		ddquot.dqb_itime = cpu_to_le64(1);
+-	spin_unlock(&dq_data_lock);
+-	ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
+-	      (char *)&ddquot, sizeof(struct v2_disk_dqblk), dquot->dq_off);
+-	if (ret != sizeof(struct v2_disk_dqblk)) {
+-		printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", dquot->dq_sb->s_id);
+-		if (ret >= 0)
+-			ret = -ENOSPC;
+-	}
+-	else
+-		ret = 0;
+-	dqstats.writes++;
+-
+-	return ret;
+-}
+-
+-/* Free dquot entry in data block */
+-static int free_dqentry(struct dquot *dquot, uint blk)
+-{
+-	struct super_block *sb = dquot->dq_sb;
+-	int type = dquot->dq_type;
+-	struct v2_disk_dqdbheader *dh;
+-	dqbuf_t buf = getdqbuf();
+-	int ret = 0;
+-
+-	if (!buf)
+-		return -ENOMEM;
+-	if (dquot->dq_off >> V2_DQBLKSIZE_BITS != blk) {
+-		printk(KERN_ERR "VFS: Quota structure has offset to other "
+-		  "block (%u) than it should (%u).\n", blk,
+-		  (uint)(dquot->dq_off >> V2_DQBLKSIZE_BITS));
+-		goto out_buf;
+-	}
+-	if ((ret = read_blk(sb, type, blk, buf)) < 0) {
+-		printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk);
+-		goto out_buf;
+-	}
+-	dh = (struct v2_disk_dqdbheader *)buf;
+-	le16_add_cpu(&dh->dqdh_entries, -1);
+-	if (!le16_to_cpu(dh->dqdh_entries)) {	/* Block got free? */
+-		if ((ret = remove_free_dqentry(sb, type, buf, blk)) < 0 ||
+-		    (ret = put_free_dqblk(sb, type, buf, blk)) < 0) {
+-			printk(KERN_ERR "VFS: Can't move quota data block (%u) "
+-			  "to free list.\n", blk);
+-			goto out_buf;
+-		}
+-	}
+-	else {
+-		memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0,
+-		  sizeof(struct v2_disk_dqblk));
+-		if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) {
+-			/* Insert will write block itself */
+-			if ((ret = insert_free_dqentry(sb, type, buf, blk)) < 0) {
+-				printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk);
+-				goto out_buf;
+-			}
+-		}
+-		else
+-			if ((ret = write_blk(sb, type, blk, buf)) < 0) {
+-				printk(KERN_ERR "VFS: Can't write quota data "
+-				  "block %u\n", blk);
+-				goto out_buf;
+-			}
+-	}
+-	dquot->dq_off = 0;	/* Quota is now unattached */
+-out_buf:
+-	freedqbuf(buf);
+-	return ret;
+-}
+-
+-/* Remove reference to dquot from tree */
+-static int remove_tree(struct dquot *dquot, uint *blk, int depth)
+-{
+-	struct super_block *sb = dquot->dq_sb;
+-	int type = dquot->dq_type;
+-	dqbuf_t buf = getdqbuf();
+-	int ret = 0;
+-	uint newblk;
+-	__le32 *ref = (__le32 *)buf;
+-	
+-	if (!buf)
+-		return -ENOMEM;
+-	if ((ret = read_blk(sb, type, *blk, buf)) < 0) {
+-		printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk);
+-		goto out_buf;
+-	}
+-	newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
+-	if (depth == V2_DQTREEDEPTH-1) {
+-		ret = free_dqentry(dquot, newblk);
+-		newblk = 0;
+-	}
+-	else
+-		ret = remove_tree(dquot, &newblk, depth+1);
+-	if (ret >= 0 && !newblk) {
+-		int i;
+-		ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0);
+-		for (i = 0; i < V2_DQBLKSIZE && !buf[i]; i++);	/* Block got empty? */
+-		/* Don't put the root block into the free block list */
+-		if (i == V2_DQBLKSIZE && *blk != V2_DQTREEOFF) {
+-			put_free_dqblk(sb, type, buf, *blk);
+-			*blk = 0;
+-		}
+-		else
+-			if ((ret = write_blk(sb, type, *blk, buf)) < 0)
+-				printk(KERN_ERR "VFS: Can't write quota tree "
+-				  "block %u.\n", *blk);
+-	}
+-out_buf:
+-	freedqbuf(buf);
+-	return ret;	
+-}
+-
+-/* Delete dquot from tree */
+-static int v2_delete_dquot(struct dquot *dquot)
+-{
+-	uint tmp = V2_DQTREEOFF;
+-
+-	if (!dquot->dq_off)	/* Even not allocated? */
+-		return 0;
+-	return remove_tree(dquot, &tmp, 0);
+-}
+-
+-/* Find entry in block */
+-static loff_t find_block_dqentry(struct dquot *dquot, uint blk)
+-{
+-	dqbuf_t buf = getdqbuf();
+-	loff_t ret = 0;
+-	int i;
+-	struct v2_disk_dqblk *ddquot = GETENTRIES(buf);
+-
+-	if (!buf)
+-		return -ENOMEM;
+-	if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) {
+-		printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
+-		goto out_buf;
+-	}
+-	if (dquot->dq_id)
+-		for (i = 0; i < V2_DQSTRINBLK &&
+-		     le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++);
+-	else {	/* ID 0 as a bit more complicated searching... */
+-		struct v2_disk_dqblk fakedquot;
+-
+-		memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
+-		for (i = 0; i < V2_DQSTRINBLK; i++)
+-			if (!le32_to_cpu(ddquot[i].dqb_id) &&
+-			    memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)))
+-				break;
+-	}
+-	if (i == V2_DQSTRINBLK) {
+-		printk(KERN_ERR "VFS: Quota for id %u referenced "
+-		  "but not present.\n", dquot->dq_id);
+-		ret = -EIO;
+-		goto out_buf;
+-	}
+-	else
+-		ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct
+-		  v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk);
+-out_buf:
+-	freedqbuf(buf);
+-	return ret;
+-}
+-
+-/* Find entry for given id in the tree */
+-static loff_t find_tree_dqentry(struct dquot *dquot, uint blk, int depth)
+-{
+-	dqbuf_t buf = getdqbuf();
+-	loff_t ret = 0;
+-	__le32 *ref = (__le32 *)buf;
+-
+-	if (!buf)
+-		return -ENOMEM;
+-	if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) {
+-		printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
+-		goto out_buf;
+-	}
+-	ret = 0;
+-	blk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
+-	if (!blk)	/* No reference? */
+-		goto out_buf;
+-	if (depth < V2_DQTREEDEPTH-1)
+-		ret = find_tree_dqentry(dquot, blk, depth+1);
+-	else
+-		ret = find_block_dqentry(dquot, blk);
+-out_buf:
+-	freedqbuf(buf);
+-	return ret;
++	return qtree_write_dquot(&sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i, dquot);
+ }
+ 
+-/* Find entry for given id in the tree - wrapper function */
+-static inline loff_t find_dqentry(struct dquot *dquot)
+-{
+-	return find_tree_dqentry(dquot, V2_DQTREEOFF, 0);
+-}
+-
+-static int v2_read_dquot(struct dquot *dquot)
+-{
+-	int type = dquot->dq_type;
+-	loff_t offset;
+-	struct v2_disk_dqblk ddquot, empty;
+-	int ret = 0;
+-
+-#ifdef __QUOTA_V2_PARANOIA
+-	/* Invalidated quota? */
+-	if (!dquot->dq_sb || !sb_dqopt(dquot->dq_sb)->files[type]) {
+-		printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
+-		return -EIO;
+-	}
+-#endif
+-	offset = find_dqentry(dquot);
+-	if (offset <= 0) {	/* Entry not present? */
+-		if (offset < 0)
+-			printk(KERN_ERR "VFS: Can't read quota "
+-			  "structure for id %u.\n", dquot->dq_id);
+-		dquot->dq_off = 0;
+-		set_bit(DQ_FAKE_B, &dquot->dq_flags);
+-		memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
+-		ret = offset;
+-	}
+-	else {
+-		dquot->dq_off = offset;
+-		if ((ret = dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type,
+-		    (char *)&ddquot, sizeof(struct v2_disk_dqblk), offset))
+-		    != sizeof(struct v2_disk_dqblk)) {
+-			if (ret >= 0)
+-				ret = -EIO;
+-			printk(KERN_ERR "VFS: Error while reading quota "
+-			  "structure for id %u.\n", dquot->dq_id);
+-			memset(&ddquot, 0, sizeof(struct v2_disk_dqblk));
+-		}
+-		else {
+-			ret = 0;
+-			/* We need to escape back all-zero structure */
+-			memset(&empty, 0, sizeof(struct v2_disk_dqblk));
+-			empty.dqb_itime = cpu_to_le64(1);
+-			if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
+-				ddquot.dqb_itime = 0;
+-		}
+-		disk2memdqb(&dquot->dq_dqb, &ddquot);
+-		if (!dquot->dq_dqb.dqb_bhardlimit &&
+-			!dquot->dq_dqb.dqb_bsoftlimit &&
+-			!dquot->dq_dqb.dqb_ihardlimit &&
+-			!dquot->dq_dqb.dqb_isoftlimit)
+-			set_bit(DQ_FAKE_B, &dquot->dq_flags);
+-	}
+-	dqstats.reads++;
+-
+-	return ret;
+-}
+-
+-/* Check whether dquot should not be deleted. We know we are
+- * the only one operating on dquot (thanks to dq_lock) */
+ static int v2_release_dquot(struct dquot *dquot)
+ {
+-	if (test_bit(DQ_FAKE_B, &dquot->dq_flags) && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace))
+-		return v2_delete_dquot(dquot);
+-	return 0;
++	return qtree_release_dquot(&sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i, dquot);
+ }
+ 
+ static struct quota_format_ops v2_format_ops = {
+Index: linux-2.6.27.36/include/linux/dqblk_qtree.h
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.27.36/include/linux/dqblk_qtree.h	2009-10-08 16:32:48.000000000 +0200
+@@ -0,0 +1,56 @@
++/*
++ *	Definitions of structures and functions for quota formats using trie
++ */
++
++#ifndef _LINUX_DQBLK_QTREE_H
++#define _LINUX_DQBLK_QTREE_H
++
++#include <linux/types.h>
++
++/* Numbers of blocks needed for updates - we count with the smallest
++ * possible block size (1024) */
++#define QTREE_INIT_ALLOC 4
++#define QTREE_INIT_REWRITE 2
++#define QTREE_DEL_ALLOC 0
++#define QTREE_DEL_REWRITE 6
++
++struct dquot;
++
++/* Operations */
++struct qtree_fmt_operations {
++	void (*mem2disk_dqblk)(void *disk, struct dquot *dquot);	/* Convert given entry from in memory format to disk one */
++	void (*disk2mem_dqblk)(struct dquot *dquot, void *disk);	/* Convert given entry from disk format to in memory one */
++	int (*is_id)(void *disk, struct dquot *dquot);	/* Is this structure for given id? */
++};
++
++/* Inmemory copy of version specific information */
++struct qtree_mem_dqinfo {
++	struct super_block *dqi_sb;	/* Sb quota is on */
++	int dqi_type;			/* Quota type */
++	unsigned int dqi_blocks;	/* # of blocks in quota file */
++	unsigned int dqi_free_blk;	/* First block in list of free blocks */
++	unsigned int dqi_free_entry;	/* First block with free entry */
++	unsigned int dqi_blocksize_bits;	/* Block size of quota file */
++	unsigned int dqi_entry_size;	/* Size of quota entry in quota file */
++	unsigned int dqi_usable_bs;	/* Space usable in block for quota data */
++	unsigned int dqi_qtree_depth;	/* Precomputed depth of quota tree */
++	struct qtree_fmt_operations *dqi_ops;	/* Operations for entry manipulation */
++};
++
++int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot);
++int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot);
++int qtree_delete_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot);
++int qtree_release_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot);
++int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk);
++static inline int qtree_depth(struct qtree_mem_dqinfo *info)
++{
++	unsigned int epb = info->dqi_usable_bs >> 2;
++	unsigned long long entries = epb;
++	int i;
++
++	for (i = 1; entries < (1ULL << 32); i++)
++		entries *= epb;
++	return i;
++}
++
++#endif /* _LINUX_DQBLK_QTREE_H */
+Index: linux-2.6.27.36/include/linux/dqblk_v2.h
+===================================================================
+--- linux-2.6.27.36.orig/include/linux/dqblk_v2.h	2009-10-05 17:19:01.000000000 +0200
++++ linux-2.6.27.36/include/linux/dqblk_v2.h	2009-10-08 16:32:48.000000000 +0200
+@@ -1,26 +1,23 @@
+ /*
+- *	Definitions of structures for vfsv0 quota format
++ *  Definitions for vfsv0 quota format
+  */
+ 
+ #ifndef _LINUX_DQBLK_V2_H
+ #define _LINUX_DQBLK_V2_H
+ 
+-#include <linux/types.h>
++#include <linux/dqblk_qtree.h>
+ 
+-/* id numbers of quota format */
++/* Id number of quota format */
+ #define QFMT_VFS_V0 2
+ 
+ /* Numbers of blocks needed for updates */
+-#define V2_INIT_ALLOC 4
+-#define V2_INIT_REWRITE 2
+-#define V2_DEL_ALLOC 0
+-#define V2_DEL_REWRITE 6
++#define V2_INIT_ALLOC QTREE_INIT_ALLOC
++#define V2_INIT_REWRITE QTREE_INIT_REWRITE
++#define V2_DEL_ALLOC QTREE_DEL_ALLOC
++#define V2_DEL_REWRITE QTREE_DEL_REWRITE
+ 
+-/* Inmemory copy of version specific information */
+ struct v2_mem_dqinfo {
+-	unsigned int dqi_blocks;
+-	unsigned int dqi_free_blk;
+-	unsigned int dqi_free_entry;
++	struct qtree_mem_dqinfo i;
+ };
+ 
+ #endif /* _LINUX_DQBLK_V2_H */
diff --git a/lustre/kernel_patches/patches/quota-support-64-bit-quota-format.patch b/lustre/kernel_patches/patches/quota-support-64-bit-quota-format-2.6.27-vanilla.patch
similarity index 80%
copy from lustre/kernel_patches/patches/quota-support-64-bit-quota-format.patch
copy to lustre/kernel_patches/patches/quota-support-64-bit-quota-format-2.6.27-vanilla.patch
index 14fe9a8..b359ee0 100644
--- a/lustre/kernel_patches/patches/quota-support-64-bit-quota-format.patch
+++ b/lustre/kernel_patches/patches/quota-support-64-bit-quota-format-2.6.27-vanilla.patch
@@ -13,10 +13,11 @@ Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
  fs/quotaio_v2.h |   26 ++++++--
  2 files changed, 132 insertions(+), 34 deletions(-)
 
-diff -puN fs/quota_v2.c~quota-support-64-bit-quota-format fs/quota_v2.c
---- a/fs/quota_v2.c~quota-support-64-bit-quota-format
-+++ a/fs/quota_v2.c
-@@ -23,14 +23,24 @@ MODULE_LICENSE("GPL");
+Index: linux-2.6.27.36/fs/quota_v2.c
+===================================================================
+--- linux-2.6.27.36.orig/fs/quota_v2.c	2009-10-08 16:34:36.000000000 +0200
++++ linux-2.6.27.36/fs/quota_v2.c	2009-10-08 16:39:29.000000000 +0200
+@@ -23,18 +23,27 @@
  
  #define __QUOTA_V2_PARANOIA
  
@@ -36,8 +37,10 @@ diff -puN fs/quota_v2.c~quota-support-64-bit-quota-format fs/quota_v2.c
 +	.mem2disk_dqblk = v2r0_mem2diskdqb,
 +	.disk2mem_dqblk = v2r0_disk2memdqb,
 +	.is_id = v2r0_is_id,
-+};
-+
+ };
+ 
+-/* Check whether given file is really vfsv0 quotafile */
+-static int v2_check_quota_file(struct super_block *sb, int type)
 +static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot);
 +static void v2r1_disk2memdqb(struct dquot *dquot, void *dp);
 +static int v2r1_is_id(void *dp, struct dquot *dquot);
@@ -46,20 +49,13 @@ diff -puN fs/quota_v2.c~quota-support-64-bit-quota-format fs/quota_v2.c
 +	.mem2disk_dqblk = v2r1_mem2diskdqb,
 +	.disk2mem_dqblk = v2r1_disk2memdqb,
 +	.is_id = v2r1_is_id,
- };
- 
- #define QUOTABLOCK_BITS 10
-@@ -46,8 +56,7 @@ static inline qsize_t v2_qbtos(qsize_t b
- 	return blocks << QUOTABLOCK_BITS;
- }
- 
--/* Check whether given file is really vfsv0 quotafile */
--static int v2_check_quota_file(struct super_block *sb, int type)
++};
++
 +static int v2_check_quota_file_header(struct super_block *sb, int type)
  {
  	struct v2_disk_dqheader dqhead;
  	ssize_t size;
-@@ -58,12 +67,20 @@ static int v2_check_quota_file(struct su
+@@ -45,12 +54,20 @@
  	if (size != sizeof(struct v2_disk_dqheader)) {
  		printk("quota_v2: failed read expected=%zd got=%zd\n",
  			sizeof(struct v2_disk_dqheader), size);
@@ -85,9 +81,9 @@ diff -puN fs/quota_v2.c~quota-support-64-bit-quota-format fs/quota_v2.c
  }
  
  /* Read information header from quota file */
-@@ -73,7 +90,13 @@ static int v2_read_file_info(struct supe
+@@ -59,7 +76,13 @@
+ 	struct v2_disk_dqinfo dinfo;
  	struct mem_dqinfo *info = sb_dqinfo(sb, type);
- 	struct qtree_mem_dqinfo *qinfo;
  	ssize_t size;
 +	int version = v2_check_quota_file_header(sb, type);
  
@@ -99,41 +95,40 @@ diff -puN fs/quota_v2.c~quota-support-64-bit-quota-format fs/quota_v2.c
  	size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
  	       sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
  	if (size != sizeof(struct v2_disk_dqinfo)) {
-@@ -88,9 +111,14 @@ static int v2_read_file_info(struct supe
+@@ -68,8 +91,14 @@
  		return -1;
  	}
- 	qinfo = info->dqi_priv;
--	/* limits are stored as unsigned 32-bit data */
+ 	/* limits are stored as unsigned 32-bit data */
 -	info->dqi_maxblimit = 0xffffffff;
 -	info->dqi_maxilimit = 0xffffffff;
-+	if (version == 0) {
-+		/* limits are stored as unsigned 32-bit data */
-+		info->dqi_maxblimit = 0xffffffff;
-+		info->dqi_maxilimit = 0xffffffff;
-+	} else {
-+		info->dqi_maxblimit = 0x7fffffffffffffffULL;
-+		info->dqi_maxilimit = 0x7fffffffffffffffULL;
-+	}
++        if (version == 0) {
++                /* limits are stored as unsigned 32-bit data */
++                info->dqi_maxblimit = 0xffffffff;
++                info->dqi_maxilimit = 0xffffffff;
++        } else {
++                info->dqi_maxblimit = 0x7fffffffffffffffULL;
++                info->dqi_maxilimit = 0x7fffffffffffffffULL;
++        }
  	info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
  	info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
  	info->dqi_flags = le32_to_cpu(dinfo.dqi_flags);
-@@ -102,8 +130,13 @@ static int v2_read_file_info(struct supe
- 	qinfo->dqi_blocksize_bits = V2_DQBLKSIZE_BITS;
- 	qinfo->dqi_usable_bs = 1 << V2_DQBLKSIZE_BITS;
- 	qinfo->dqi_qtree_depth = qtree_depth(qinfo);
--	qinfo->dqi_entry_size = sizeof(struct v2_disk_dqblk);
--	qinfo->dqi_ops = &v2_qtree_ops;
-+	if (version == 0) {
-+		qinfo->dqi_entry_size = sizeof(struct v2r0_disk_dqblk);
-+		qinfo->dqi_ops = &v2r0_qtree_ops;
-+	} else {
-+		qinfo->dqi_entry_size = sizeof(struct v2r1_disk_dqblk);
-+		qinfo->dqi_ops = &v2r1_qtree_ops;
-+	}
+@@ -81,8 +110,13 @@
+ 	info->u.v2_i.i.dqi_blocksize_bits = V2_DQBLKSIZE_BITS;
+ 	info->u.v2_i.i.dqi_usable_bs = 1 << V2_DQBLKSIZE_BITS;
+ 	info->u.v2_i.i.dqi_qtree_depth = qtree_depth(&info->u.v2_i.i);
+-	info->u.v2_i.i.dqi_entry_size = sizeof(struct v2_disk_dqblk);
+-	info->u.v2_i.i.dqi_ops = &v2_qtree_ops;
++        if (version == 0) {
++                qinfo->dqi_entry_size = sizeof(struct v2r0_disk_dqblk);
++                qinfo->dqi_ops = &v2r0_qtree_ops;
++        } else {
++                qinfo->dqi_entry_size = sizeof(struct v2r1_disk_dqblk);
++                qinfo->dqi_ops = &v2r1_qtree_ops;
++        }
  	return 0;
  }
  
-@@ -134,9 +167,9 @@ static int v2_write_file_info(struct sup
+@@ -112,9 +146,9 @@
  	return 0;
  }
  
@@ -145,7 +140,7 @@ diff -puN fs/quota_v2.c~quota-support-64-bit-quota-format fs/quota_v2.c
  	struct mem_dqblk *m = &dquot->dq_dqb;
  
  	m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
-@@ -148,15 +181,15 @@ static void v2_disk2memdqb(struct dquot 
+@@ -126,15 +160,15 @@
  	m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
  	m->dqb_btime = le64_to_cpu(d->dqb_btime);
  	/* We need to escape back all-zero structure */
@@ -164,8 +159,8 @@ diff -puN fs/quota_v2.c~quota-support-64-bit-quota-format fs/quota_v2.c
 +	struct v2r0_disk_dqblk *d = dp;
  	struct mem_dqblk *m = &dquot->dq_dqb;
  	struct qtree_mem_dqinfo *info =
- 			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
-@@ -174,9 +207,60 @@ static void v2_mem2diskdqb(void *dp, str
+ 			&sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i;
+@@ -152,9 +186,60 @@
  		d->dqb_itime = cpu_to_le64(1);
  }
  
@@ -226,11 +221,12 @@ diff -puN fs/quota_v2.c~quota-support-64-bit-quota-format fs/quota_v2.c
 -	struct v2_disk_dqblk *d = dp;
 +	struct v2r1_disk_dqblk *d = dp;
  	struct qtree_mem_dqinfo *info =
- 			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+ 			&sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i;
  
-diff -puN fs/quotaio_v2.h~quota-support-64-bit-quota-format fs/quotaio_v2.h
---- a/fs/quotaio_v2.h~quota-support-64-bit-quota-format
-+++ a/fs/quotaio_v2.h
+Index: linux-2.6.27.36/include/linux/quotaio_v2.h
+===================================================================
+--- linux-2.6.27.36.orig/include/linux/quotaio_v2.h	2009-10-08 16:32:48.000000000 +0200
++++ linux-2.6.27.36/include/linux/quotaio_v2.h	2009-10-08 16:36:48.000000000 +0200
 @@ -17,8 +17,8 @@
  }
  
@@ -242,7 +238,7 @@ diff -puN fs/quotaio_v2.h~quota-support-64-bit-quota-format fs/quotaio_v2.h
  }
  
  /* First generic header */
-@@ -28,11 +28,11 @@ struct v2_disk_dqheader {
+@@ -28,11 +28,11 @@
  };
  
  /*
@@ -258,7 +254,7 @@ diff -puN fs/quotaio_v2.h~quota-support-64-bit-quota-format fs/quotaio_v2.h
  	__le32 dqb_id;		/* id this quota applies to */
  	__le32 dqb_ihardlimit;	/* absolute limit on allocated inodes */
  	__le32 dqb_isoftlimit;	/* preferred inode limit */
-@@ -44,6 +44,20 @@ struct v2_disk_dqblk {
+@@ -44,6 +44,20 @@
  	__le64 dqb_itime;	/* time limit for excessive inode use */
  };
  
@@ -279,4 +275,3 @@ diff -puN fs/quotaio_v2.h~quota-support-64-bit-quota-format fs/quotaio_v2.h
  /* Header with type and version specific information */
  struct v2_disk_dqinfo {
  	__le32 dqi_bgrace;	/* Time before block soft limit becomes hard limit */
-_
diff --git a/lustre/kernel_patches/series/2.6-sles11.series b/lustre/kernel_patches/series/2.6.27-vanilla.series
similarity index 70%
copy from lustre/kernel_patches/series/2.6-sles11.series
copy to lustre/kernel_patches/series/2.6.27-vanilla.series
index 860be33..f292811 100644
--- a/lustre/kernel_patches/series/2.6-sles11.series
+++ b/lustre/kernel_patches/series/2.6.27-vanilla.series
@@ -7,7 +7,8 @@ dev_read_only-2.6.27-vanilla.patch
 export-2.6.27-vanilla.patch 
 export-show_task-2.6.27-vanilla.patch 
 sd_iostats-2.6.27-vanilla.patch
-md-mmp-unplug-dev-sles11.patch
-quota-support-64-bit-quota-format.patch
+md-mmp-unplug-dev-2.6.27-vanilla.patch
+quota-Split-off-quota-tree-handling-into-a-separate.patch
+quota-support-64-bit-quota-format-2.6.27-vanilla.patch
 jbd2-jcberr-2.6-sles11.patch
 jbd2-commit-timer-no-jiffies-rounding.diff

-- 
Lustre Debian Packaging 



More information about the Pkg-lustre-svn-commit mailing list