[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