--- lustre-1.8.3.orig/ldiskfs/kernel_patches/series/ldiskfs-2.6.18-debian.series
+++ lustre-1.8.3/ldiskfs/kernel_patches/series/ldiskfs-2.6.18-debian.series
@@ -0,0 +1,20 @@
+ext3-wantedi-2.6-rhel4.patch
+iopen-2.6-fc5.patch
+ext3-map_inode_page-2.6.18.patch
+export-ext3-2.6-rhel4.patch
+ext3-include-fixes-2.6-rhel4.patch
+ext3-extents-2.6.18-vanilla.patch
+ext3-mballoc3-core.patch
+ext3-mballoc3-2.6.18.patch
+ext3-nlinks-2.6.9.patch
+ext3-ialloc-2.6.patch
+ext3-remove-cond_resched-calls-2.6.12.patch
+ext3-filterdata-sles10.patch
+ext3-16tb-overflow-fixes.patch
+ext3-uninit-2.6.18.patch
+ext3-nanosecond-2.6.18-vanilla.patch
+ext3-inode-version-2.6.18-vanilla.patch
+ext3-ea-expand-lose-block.patch
+ext3-mmp-2.6.18-vanilla.patch
+ext3-fiemap-2.6.18-vanilla.patch
+ext3-lookup-dotdot-2.6.9.patch
--- lustre-1.8.3.orig/lustre/kernel_patches/patches/quota-support-64-bit-quota-format-2.6.27-vanilla.patch
+++ lustre-1.8.3/lustre/kernel_patches/patches/quota-support-64-bit-quota-format-2.6.27-vanilla.patch
@@ -0,0 +1,282 @@
+From: Jan Kara <jack@suse.cz>
+
+Implement conversion functions for new version (version 1) of quota format
+which supports 64-bit block and inode limits and 64-bit inode usage.  The
+original implementation has been written by Andrew Perepechko.
+
+Signed-off-by: Andrew Perepechko <andrew.perepechko@sun.com>
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+---
+
+ fs/quota_v2.c   |  140 ++++++++++++++++++++++++++++++++++++----------
+ fs/quotaio_v2.h |   26 ++++++--
+ 2 files changed, 132 insertions(+), 34 deletions(-)
+
+Index: linux-2.6.27.36/fs/quota_v2.c
+===================================================================
+--- linux-2.6.27.36.orig/fs/quota_v2.c	2009-10-09 17:00:48.000000000 +0200
++++ linux-2.6.27.36/fs/quota_v2.c	2009-10-09 17:03:35.000000000 +0200
+@@ -23,14 +23,24 @@
+ 
+ #define __QUOTA_V2_PARANOIA
+ 
+-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,
++static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot);
++static void v2r0_disk2memdqb(struct dquot *dquot, void *dp);
++static int v2r0_is_id(void *dp, struct dquot *dquot);
++
++static struct qtree_fmt_operations v2r0_qtree_ops = {
++      .mem2disk_dqblk = v2r0_mem2diskdqb,
++      .disk2mem_dqblk = v2r0_disk2memdqb,
++      .is_id = v2r0_is_id,
++};
++
++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);
++
++static struct qtree_fmt_operations v2r1_qtree_ops = {
++      .mem2disk_dqblk = v2r1_mem2diskdqb,
++      .disk2mem_dqblk = v2r1_disk2memdqb,
++      .is_id = v2r1_is_id,
+ };
+ 
+ #define QUOTABLOCK_BITS 10
+@@ -46,8 +56,7 @@
+ 	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 @@
+ 	if (size != sizeof(struct v2_disk_dqheader)) {
+ 		printk("quota_v2: failed read expected=%zd got=%zd\n",
+ 			sizeof(struct v2_disk_dqheader), size);
+-		return 0;
++		return -EIO;
+ 	}
+-	if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
+-	    le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
+-		return 0;
+-	return 1;
++	if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type])
++		return -ENOENT;
++	if (le32_to_cpu(dqhead.dqh_version) > quota_versions[type])
++		return -EOPNOTSUPP;
++	return le32_to_cpu(dqhead.dqh_version);
++}
++
++
++/* Check whether given file is really vfsv0 quotafile */
++static int v2_check_quota_file(struct super_block *sb, int type)
++{
++	return v2_check_quota_file_header(sb, type) >= 0;
+ }
+ 
+ /* Read information header from quota file */
+@@ -72,7 +89,13 @@
+ 	struct v2_disk_dqinfo dinfo;
+ 	struct mem_dqinfo *info = sb_dqinfo(sb, type);
+ 	ssize_t size;
++	int version = v2_check_quota_file_header(sb, type);
+ 
++	if (version < 0) {
++		printk(KERN_WARNING "Cannot identify quota file version on "
++		       "device %s: %d\n", sb->s_id, version);
++		return -1;
++	}
+ 	size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
+ 	       sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
+ 	if (size != sizeof(struct v2_disk_dqinfo)) {
+@@ -81,8 +104,14 @@
+ 		return -1;
+ 	}
+ 	/* 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;
++        }
+ 	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);
+@@ -94,8 +123,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;
+ }
+ 
+@@ -125,9 +159,9 @@
+ 	return 0;
+ }
+ 
+-static void v2_disk2memdqb(struct dquot *dquot, void *dp)
++static void v2r0_disk2memdqb(struct dquot *dquot, void *dp)
+ {
+-	struct v2_disk_dqblk *d = dp, empty;
++	struct v2r0_disk_dqblk *d = dp, empty;
+ 	struct mem_dqblk *m = &dquot->dq_dqb;
+ 
+ 	m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
+@@ -139,15 +173,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 */
+-	memset(&empty, 0, sizeof(struct v2_disk_dqblk));
++	memset(&empty, 0, sizeof(struct v2r0_disk_dqblk));
+ 	empty.dqb_itime = cpu_to_le64(1);
+-	if (!memcmp(&empty, dp, sizeof(struct v2_disk_dqblk)))
++	if (!memcmp(&empty, dp, sizeof(struct v2r0_disk_dqblk)))
+ 		m->dqb_itime = 0;
+ }
+ 
+-static void v2_mem2diskdqb(void *dp, struct dquot *dquot)
++static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
+ {
+-	struct v2_disk_dqblk *d = dp;
++	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)->u.v2_i.i;
+@@ -165,9 +199,60 @@
+ 		d->dqb_itime = cpu_to_le64(1);
+ }
+ 
+-static int v2_is_id(void *dp, struct dquot *dquot)
++static int v2r0_is_id(void *dp, struct dquot *dquot)
++{
++	struct v2r0_disk_dqblk *d = dp;
++	struct qtree_mem_dqinfo *info =
++			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
++
++	if (qtree_entry_unused(info, dp))
++		return 0;
++	return le32_to_cpu(d->dqb_id) == dquot->dq_id;
++}
++
++static void v2r1_disk2memdqb(struct dquot *dquot, void *dp)
++{
++	struct v2r1_disk_dqblk *d = dp, empty;
++	struct mem_dqblk *m = &dquot->dq_dqb;
++
++	m->dqb_ihardlimit = le64_to_cpu(d->dqb_ihardlimit);
++	m->dqb_isoftlimit = le64_to_cpu(d->dqb_isoftlimit);
++	m->dqb_curinodes = le64_to_cpu(d->dqb_curinodes);
++	m->dqb_itime = le64_to_cpu(d->dqb_itime);
++	m->dqb_bhardlimit = v2_qbtos(le64_to_cpu(d->dqb_bhardlimit));
++	m->dqb_bsoftlimit = v2_qbtos(le64_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 v2r1_disk_dqblk));
++	empty.dqb_itime = cpu_to_le64(1);
++	if (!memcmp(&empty, dp, sizeof(struct v2r1_disk_dqblk)))
++		m->dqb_itime = 0;
++}
++
++static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
++{
++	struct v2r1_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;
++
++	d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
++	d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
++	d->dqb_curinodes = cpu_to_le64(m->dqb_curinodes);
++	d->dqb_itime = cpu_to_le64(m->dqb_itime);
++	d->dqb_bhardlimit = cpu_to_le64(v2_stoqb(m->dqb_bhardlimit));
++	d->dqb_bsoftlimit = cpu_to_le64(v2_stoqb(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(dquot->dq_id);
++	if (qtree_entry_unused(info, dp))
++		d->dqb_itime = cpu_to_le64(1);
++}
++
++static int v2r1_is_id(void *dp, struct dquot *dquot)
+ {
+-	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)->u.v2_i.i;
+ 
+Index: linux-2.6.27.36/include/linux/quotaio_v2.h
+===================================================================
+--- linux-2.6.27.36.orig/include/linux/quotaio_v2.h	2009-10-09 17:00:48.000000000 +0200
++++ linux-2.6.27.36/include/linux/quotaio_v2.h	2009-10-09 17:00:56.000000000 +0200
+@@ -17,8 +17,8 @@
+ }
+ 
+ #define V2_INITQVERSIONS {\
+-	0,		/* USRQUOTA */\
+-	0		/* GRPQUOTA */\
++	1,		/* USRQUOTA */\
++	1		/* GRPQUOTA */\
+ }
+ 
+ /* First generic header */
+@@ -28,11 +28,11 @@
+ };
+ 
+ /*
+- * 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
+- * to blocks of these structures.
++ * The following structure defines the format of the disk quota file in version
++ * 0 - the file is a radix tree whose leaves point to blocks of these
++ * structures.
+  */
+-struct v2_disk_dqblk {
++struct v2r0_disk_dqblk {
+ 	__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 @@
+ 	__le64 dqb_itime;	/* time limit for excessive inode use */
+ };
+ 
++/* The same structure in quota file version 1 */
++struct v2r1_disk_dqblk {
++	__le32 dqb_id;		/* id this quota applies to */
++	__le32 dqb_padding;	/* padding field */
++	__le64 dqb_ihardlimit;	/* absolute limit on allocated inodes */
++	__le64 dqb_isoftlimit;	/* preferred inode limit */
++	__le64 dqb_curinodes;	/* current # allocated inodes */
++	__le64 dqb_bhardlimit;	/* absolute limit on disk space */
++	__le64 dqb_bsoftlimit;	/* preferred limit on disk space */
++	__le64 dqb_curspace;	/* current space occupied (in bytes) */
++	__le64 dqb_btime;	/* time limit for excessive disk use */
++	__le64 dqb_itime;	/* time limit for excessive inode use */
++};
++
+ /* Header with type and version specific information */
+ struct v2_disk_dqinfo {
+ 	__le32 dqi_bgrace;	/* Time before block soft limit becomes hard limit */
--- lustre-1.8.3.orig/lustre/kernel_patches/patches/export-2.6.26-vanilla.patch
+++ lustre-1.8.3/lustre/kernel_patches/patches/export-2.6.26-vanilla.patch
@@ -0,0 +1,24 @@
+Index: linux-source-2.6.26/fs/jbd2/journal.c
+===================================================================
+--- linux-source-2.6.26.orig/fs/jbd2/journal.c	2009-10-09 13:49:43.000000000 +0200
++++ linux-source-2.6.26/fs/jbd2/journal.c	2009-10-09 13:49:50.000000000 +0200
+@@ -460,6 +460,7 @@
+ 	spin_unlock(&journal->j_state_lock);
+ 	return ret;
+ }
++EXPORT_SYMBOL(jbd2_log_start_commit);
+ 
+ /*
+  * Force and wait upon a commit if the calling process is not within
+Index: linux-source-2.6.26/security/security.c
+===================================================================
+--- linux-source-2.6.26.orig/security/security.c	2009-10-09 13:49:43.000000000 +0200
++++ linux-source-2.6.26/security/security.c	2009-10-09 13:49:50.000000000 +0200
+@@ -68,6 +68,7 @@
+ 
+ 	return 0;
+ }
++EXPORT_SYMBOL(security_inode_unlink);
+ 
+ /* Save user chosen LSM */
+ static int __init choose_lsm(char *str)
--- lustre-1.8.3.orig/lustre/kernel_patches/patches/quota-Split-off-quota-tree-handling-into-a-separate.patch
+++ lustre-1.8.3/lustre/kernel_patches/patches/quota-Split-off-quota-tree-handling-into-a-separate.patch
@@ -0,0 +1,1593 @@
+From: Jan Kara <jack@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@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 */
--- lustre-1.8.3.orig/lustre/kernel_patches/patches/sd_iostats-2.6.26-vanilla.patch
+++ lustre-1.8.3/lustre/kernel_patches/patches/sd_iostats-2.6.26-vanilla.patch
@@ -0,0 +1,579 @@
+Index: linux-source-2.6.26/drivers/scsi/Kconfig
+===================================================================
+--- linux-source-2.6.26.orig/drivers/scsi/Kconfig	2009-10-09 13:33:25.000000000 +0200
++++ linux-source-2.6.26/drivers/scsi/Kconfig	2009-10-09 13:39:06.000000000 +0200
+@@ -81,6 +81,14 @@
+ 	  In this case, do not compile the driver for your SCSI host adapter
+ 	  (below) as a module either.
+ 
++config SD_IOSTATS
++   bool "Enable SCSI disk I/O stats"
++   depends on BLK_DEV_SD
++   default y
++   ---help---
++     This enables SCSI disk I/O stats collection.  You must also enable
++     /proc file system support if you want this feature.
++
+ config CHR_DEV_ST
+ 	tristate "SCSI tape support"
+ 	depends on SCSI
+Index: linux-source-2.6.26/drivers/scsi/scsi_proc.c
+===================================================================
+--- linux-source-2.6.26.orig/drivers/scsi/scsi_proc.c	2009-10-09 13:33:25.000000000 +0200
++++ linux-source-2.6.26/drivers/scsi/scsi_proc.c	2009-10-09 13:39:06.000000000 +0200
+@@ -40,7 +40,8 @@
+ /* 4K page size, but our output routines, use some slack for overruns */
+ #define PROC_BLOCK_SIZE (3*1024)
+ 
+-static struct proc_dir_entry *proc_scsi;
++struct proc_dir_entry *proc_scsi;
++EXPORT_SYMBOL(proc_scsi);
+ 
+ /* Protect sht->present and sht->proc_dir */
+ static DEFINE_MUTEX(global_host_template_mutex);
+Index: linux-source-2.6.26/drivers/scsi/sd.c
+===================================================================
+--- linux-source-2.6.26.orig/drivers/scsi/sd.c	2009-10-09 13:33:25.000000000 +0200
++++ linux-source-2.6.26/drivers/scsi/sd.c	2009-10-09 13:39:50.000000000 +0200
+@@ -107,6 +107,24 @@
+  * object after last put) */
+ static DEFINE_MUTEX(sd_ref_mutex);
+ 
++#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
++# include <linux/proc_fs.h>
++# include <linux/seq_file.h>
++struct proc_dir_entry *sd_iostats_procdir = NULL;
++char sd_iostats_procdir_name[] = "sd_iostats";
++static struct file_operations sd_iostats_proc_fops;
++
++extern void sd_iostats_init(void);
++extern void sd_iostats_fini(void);
++void sd_iostats_start_req(struct scsi_cmnd *SCpnt);
++void sd_iostats_finish_req(struct scsi_cmnd *SCpnt);
++#else
++static inline void sd_iostats_init(void) {}
++static inline void sd_iostats_fini(void) {}
++static inline void sd_iostats_start_req(struct scsi_cmnd *SCpnt) {}
++static inline void sd_iostats_finish_req(struct scsi_cmnd *SCpnt) {}
++#endif
++
+ static const char *sd_cache_types[] = {
+ 	"write through", "none", "write back",
+ 	"write back, no read (daft)"
+@@ -578,6 +596,8 @@
+ 
+ 	sdev = sdkp->device;
+ 
++	sd_iostats_start_req(SCpnt);
++
+ 	/*
+ 	 * If the device is in error recovery, wait until it is done.
+ 	 * If the device is offline, then disallow any access to it.
+@@ -1023,6 +1043,7 @@
+ 		break;
+ 	}
+  out:
++ 	sd_iostats_finish_req(SCpnt);
+ 	return good_bytes;
+ }
+ 
+@@ -1712,6 +1733,36 @@
+ 	if (sdp->removable)
+ 		gd->flags |= GENHD_FL_REMOVABLE;
+ 
++#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
++	sdkp->stats = kzalloc(sizeof(iostat_stats_t), GFP_KERNEL);
++	if (!sdkp->stats) {
++		printk(KERN_WARNING "cannot allocate iostat structure for"
++				    "%s\n", gd->disk_name);
++	} else {
++		do_gettimeofday(&sdkp->stats->iostat_timeval);
++		sdkp->stats->iostat_queue_stamp = jiffies;
++		spin_lock_init(&sdkp->stats->iostat_lock);
++		if (sd_iostats_procdir) {
++			struct proc_dir_entry *pde;
++			pde = create_proc_entry(gd->disk_name, S_IRUGO | S_IWUSR,
++					        sd_iostats_procdir);
++			if (!pde) {
++				printk(KERN_WARNING "Can't create /proc/scsi/"
++						    "%s/%s\n",
++						    sd_iostats_procdir_name,
++						    gd->disk_name);
++				kfree(sdkp->stats);
++				sdkp->stats = NULL;
++			} else {
++				pde->proc_fops = &sd_iostats_proc_fops;
++				pde->data = gd;
++			}
++		} else {
++			kfree(sdkp->stats);
++			sdkp->stats = NULL;
++		}
++	}
++#endif
+ 	dev_set_drvdata(dev, sdkp);
+ 	add_disk(gd);
+ 
+@@ -1755,6 +1806,366 @@
+ 	return 0;
+ }
+ 
++#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
++static int
++sd_iostats_seq_show(struct seq_file *seq, void *v)
++{
++	struct timeval     now;
++	struct gendisk *disk = seq->private;
++	iostat_stats_t    *stats;
++	unsigned long long read_len;
++	unsigned long long read_len_tot;
++	unsigned long      read_num;
++	unsigned long      read_num_tot;
++	unsigned long long write_len;
++	unsigned long long write_len_tot;
++	unsigned long      write_num;
++	unsigned long      write_num_tot;
++	int                i;
++	int                maxi;
++
++	stats = scsi_disk(disk)->stats;
++	if (stats == NULL) {
++		printk(KERN_ERR "sd_iostats_seq_show: NULL stats entry\n");
++		BUG();
++	}
++
++	do_gettimeofday(&now);
++	now.tv_sec -= stats->iostat_timeval.tv_sec;
++	now.tv_usec -= stats->iostat_timeval.tv_usec;
++	if (now.tv_usec < 0) {
++		now.tv_usec += 1000000;
++		now.tv_sec--;
++	}
++
++	/* this sampling races with updates */
++	seq_printf(seq, "index:        %lu   snapshot_time:         %lu.%06lu\n",
++			(unsigned long) scsi_disk(disk)->index,
++			now.tv_sec, now.tv_usec);
++
++	for (i = IOSTAT_NCOUNTERS - 1; i > 0; i--)
++		if (stats->iostat_read_histogram[i].iostat_count != 0 ||
++				stats->iostat_write_histogram[i].iostat_count != 0)
++			break;
++	maxi = i;
++
++	seq_printf(seq, "%8s %8s %12s %8s %12s\n", "size", 
++			"reads", "total", "writes", "total");
++
++	read_len_tot = write_len_tot = 0;
++	read_num_tot = write_num_tot = 0;
++	for (i = 0; i <= maxi; i++) {
++		read_len = stats->iostat_read_histogram[i].iostat_size;
++		read_len_tot += read_len;
++		read_num = stats->iostat_read_histogram[i].iostat_count;
++		read_num_tot += read_num;
++
++		write_len = stats->iostat_write_histogram[i].iostat_size;
++		write_len_tot += write_len;
++		write_num = stats->iostat_write_histogram[i].iostat_count;
++		write_num_tot += write_num;
++
++		seq_printf (seq, "%8d %8lu %12llu %8lu %12llu\n", 
++				512<<i, read_num, read_len, write_num, write_len);
++	}
++
++	seq_printf(seq, "%8s %8lu %12llu %8lu %12llu\n\n", "total",
++			read_num_tot, read_len_tot, 
++			write_num_tot, write_len_tot);
++
++	seq_printf(seq, "%8s %8s %8s\n", "qdepth", "ticks", "%");
++	for (i = 0; i < IOSTAT_NCOUNTERS; i++) {
++		unsigned long long ticks, percent;
++		ticks = stats->iostat_queue_ticks[i];
++		if (ticks == 0)
++			continue;
++		percent = stats->iostat_queue_ticks[i] * 100;
++		do_div(percent, stats->iostat_queue_ticks_sum);
++		seq_printf(seq, "%8d %8llu %8llu\n", i, ticks, percent);
++	}
++
++	if (stats->iostat_reqs != 0) {
++		unsigned long long aveseek = 0, percent = 0;
++
++		if (stats->iostat_seeks) {
++			aveseek = stats->iostat_seek_sectors;
++			do_div(aveseek, stats->iostat_seeks);
++			percent = stats->iostat_seeks * 100;
++			do_div(percent, stats->iostat_reqs);
++		}
++
++		seq_printf(seq, "\n%llu sectors in %llu reqs: %llu seek(s) over "
++				"%llu sectors in ave, %llu%% of all reqs\n",
++				stats->iostat_sectors, stats->iostat_reqs,
++				stats->iostat_seeks, aveseek, percent);
++	}
++
++	seq_printf(seq, "\n%16s %8s %8s %8s %8s\n", "process time", "reads",
++			"%%", "writes", "%%");
++	for (i = 0; i < IOSTAT_NCOUNTERS; i++) {
++		unsigned long read_percent = 0, write_percent = 0;
++		if (stats->iostat_wtime[i] == 0 &&
++				stats->iostat_rtime[i] == 0)
++			continue;
++		if (stats->iostat_read_reqs)
++			read_percent = stats->iostat_rtime[i] * 100 / 
++				stats->iostat_read_reqs;
++		if (stats->iostat_write_reqs)
++			write_percent = stats->iostat_wtime[i] * 100 / 
++				stats->iostat_write_reqs;
++		seq_printf(seq, "%16u %8lu %8lu %8lu %8lu\n",
++				jiffies_to_msecs(((1UL << i) >> 1) << 1),
++				stats->iostat_rtime[i], read_percent,
++				stats->iostat_wtime[i], write_percent);
++	}
++
++	seq_printf(seq, "\n%16s %8s %8s %8s %8s\n", "time in queue", "reads",
++			"%%", "writes", "%%");
++	for (i = 0; i < IOSTAT_NCOUNTERS; i++) {
++		unsigned long read_percent = 0, write_percent = 0;
++		if (stats->iostat_wtime_in_queue[i] == 0 &&
++				stats->iostat_rtime_in_queue[i] == 0)
++			continue;
++		if (stats->iostat_read_reqs)
++			read_percent = stats->iostat_rtime_in_queue[i] * 100 / 
++				stats->iostat_read_reqs;
++		if (stats->iostat_write_reqs)
++			write_percent = stats->iostat_wtime_in_queue[i] * 100 / 
++				stats->iostat_write_reqs;
++		seq_printf(seq, "%16u %8lu %8lu %8lu %8lu\n",
++				jiffies_to_msecs(((1UL << i) >> 1) << 1),
++				stats->iostat_rtime_in_queue[i],
++				read_percent,
++				stats->iostat_wtime_in_queue[i],
++				write_percent);
++	}
++
++	return 0;
++}
++
++static void *
++sd_iostats_seq_start(struct seq_file *p, loff_t *pos)
++{
++	return (*pos == 0) ? (void *)1 : NULL;
++}
++
++static void *
++sd_iostats_seq_next(struct seq_file *p, void *v, loff_t *pos)
++{
++	++*pos;
++	return NULL;
++}
++
++static void
++sd_iostats_seq_stop(struct seq_file *p, void *v)
++{
++}
++
++static struct seq_operations sd_iostats_seqops = {
++	.start = sd_iostats_seq_start,
++	.stop  = sd_iostats_seq_stop,
++	.next  = sd_iostats_seq_next,
++	.show  = sd_iostats_seq_show,
++};
++
++static int
++sd_iostats_seq_open (struct inode *inode, struct file *file)
++{
++	int rc;
++
++	rc = seq_open(file, &sd_iostats_seqops);
++	if (rc != 0)
++		return rc;
++
++	((struct seq_file *)file->private_data)->private = PDE(inode)->data;
++	return 0;
++}
++
++static ssize_t
++sd_iostats_seq_write(struct file *file, const char *buffer,
++		     size_t len, loff_t *off)
++{
++	struct seq_file   *seq = file->private_data;
++	struct gendisk *disk = seq->private;
++	iostat_stats_t    *stats = scsi_disk(disk)->stats;
++	unsigned long      flags;
++	unsigned long      qdepth;
++
++
++	spin_lock_irqsave (&stats->iostat_lock, flags);
++	qdepth = stats->iostat_queue_depth;
++	memset (stats, 0, offsetof(iostat_stats_t, iostat_lock));
++	do_gettimeofday(&stats->iostat_timeval);
++	stats->iostat_queue_stamp = jiffies;
++	stats->iostat_queue_depth = qdepth;
++	spin_unlock_irqrestore (&stats->iostat_lock, flags);
++
++	return len;
++}
++
++static struct file_operations sd_iostats_proc_fops = {
++	.owner   = THIS_MODULE,
++	.open    = sd_iostats_seq_open,
++	.read    = seq_read,
++	.write   = sd_iostats_seq_write,
++	.llseek  = seq_lseek,
++	.release = seq_release,
++};
++
++extern struct proc_dir_entry *proc_scsi;
++
++void
++sd_iostats_init(void)
++{
++	if (proc_scsi == NULL) {
++		printk(KERN_WARNING "No access to sd iostats: "
++			"proc_scsi is NULL\n");
++		return;
++	}
++
++	sd_iostats_procdir = create_proc_entry(sd_iostats_procdir_name,
++					       S_IFDIR | S_IRUGO | S_IXUGO,
++					        proc_scsi);
++	if (sd_iostats_procdir == NULL) {
++		printk(KERN_WARNING "No access to sd iostats: "
++			"can't create /proc/scsi/%s\n", sd_iostats_procdir_name);
++		return;
++	}
++}
++
++void sd_iostats_fini(void)
++{
++	if (proc_scsi != NULL && sd_iostats_procdir != NULL)
++		remove_proc_entry(sd_iostats_procdir_name, proc_scsi);
++
++	sd_iostats_procdir = NULL;
++}
++
++void sd_iostats_finish_req(struct scsi_cmnd *SCpnt)
++{
++	struct request		*rq = SCpnt->request;
++	iostat_stats_t		*stats;
++	unsigned long		*tcounter;
++	int			tbucket;
++	int			tmp;
++	unsigned long		irqflags;
++	unsigned long		i;
++
++	stats = scsi_disk(rq->rq_disk)->stats;
++	if (stats == NULL)
++		return;
++
++	tmp = jiffies - rq->start_time;
++	for (tbucket = 0; tmp > 1; tbucket++)
++		tmp >>= 1;
++	if (tbucket >= IOSTAT_NCOUNTERS)
++		tbucket = IOSTAT_NCOUNTERS - 1;
++	//printk("%u ticks in D to %u\n", jiffies - rq->start_time, tbucket);
++
++	tcounter = rq_data_dir(rq) == WRITE ?
++		&stats->iostat_wtime[tbucket] : &stats->iostat_rtime[tbucket];
++
++	spin_lock_irqsave(&stats->iostat_lock, irqflags);
++
++	/* update delay stats */
++	(*tcounter)++;
++
++	/* update queue depth stats */
++	i = stats->iostat_queue_depth;
++	if (i >= IOSTAT_NCOUNTERS)
++		i = IOSTAT_NCOUNTERS - 1;
++	stats->iostat_queue_ticks[i] += jiffies - stats->iostat_queue_stamp;
++	stats->iostat_queue_ticks_sum += jiffies - stats->iostat_queue_stamp;
++	BUG_ON(stats->iostat_queue_depth == 0);
++	stats->iostat_queue_depth--;
++
++	/* update seek stats. XXX: not sure about nr_sectors */
++	stats->iostat_sectors += rq->nr_sectors;
++	stats->iostat_reqs++;
++	if (rq->sector != stats->iostat_next_sector) {
++		stats->iostat_seek_sectors +=
++			rq->sector > stats->iostat_next_sector ?
++			rq->sector - stats->iostat_next_sector :
++			stats->iostat_next_sector - rq->sector;
++		stats->iostat_seeks++;
++	}
++	stats->iostat_next_sector = rq->sector + rq->nr_sectors;
++
++	stats->iostat_queue_stamp = jiffies;
++
++	spin_unlock_irqrestore(&stats->iostat_lock, irqflags);
++}
++
++void sd_iostats_start_req(struct scsi_cmnd *SCpnt)
++{
++	struct request		*rq = SCpnt->request;
++	iostat_stats_t		*stats;
++	iostat_counter_t	*counter;
++	int			bucket;
++	int			tbucket;
++	int			tmp;
++	unsigned long		irqflags;
++	unsigned long		i;
++	int			nsect;
++
++	stats = scsi_disk(rq->rq_disk)->stats;
++	if (stats == NULL)
++		return;
++
++	nsect = scsi_bufflen(SCpnt) >> 9;
++	for (bucket = 0, tmp = nsect; tmp > 1; bucket++)
++		tmp >>= 1;
++
++	if (bucket >= IOSTAT_NCOUNTERS) {
++		printk (KERN_ERR "sd_iostats_bump: nsect %d too big\n", nsect);
++		BUG();
++	}
++
++	counter = rq_data_dir(rq) == WRITE ?
++		&stats->iostat_write_histogram[bucket] :
++		&stats->iostat_read_histogram[bucket];
++
++	tmp = jiffies - rq->start_time;
++	for (tbucket = 0; tmp > 1; tbucket++)
++		tmp >>= 1;
++	if (tbucket >= IOSTAT_NCOUNTERS)
++		tbucket = IOSTAT_NCOUNTERS - 1;
++	//printk("%u ticks in Q to %u\n", jiffies - rq->start_time, tbucket);
++
++	/* an ugly hack to know exact processing time. the right
++	 * solution is to add one more field to struct request
++	 * hopefully it will break nothing ... */
++	rq->start_time = jiffies;
++
++	spin_lock_irqsave(&stats->iostat_lock, irqflags);
++
++	/* update queue depth stats */
++	i = stats->iostat_queue_depth;
++	if (i >= IOSTAT_NCOUNTERS)
++		i = IOSTAT_NCOUNTERS - 1;
++	stats->iostat_queue_ticks[i] += jiffies - stats->iostat_queue_stamp;
++	stats->iostat_queue_ticks_sum += jiffies - stats->iostat_queue_stamp;
++	stats->iostat_queue_depth++;
++
++	/* update delay stats */
++	if (rq_data_dir(rq) == WRITE) {
++		stats->iostat_wtime_in_queue[tbucket]++;
++		stats->iostat_write_reqs++;
++	} else {
++		stats->iostat_rtime_in_queue[tbucket]++;
++		stats->iostat_read_reqs++;
++	}
++
++	/* update size stats */
++	counter->iostat_size += nsect;
++	counter->iostat_count++;
++
++	stats->iostat_queue_stamp = jiffies;
++
++	spin_unlock_irqrestore(&stats->iostat_lock, irqflags);
++}
++#endif
++
+ /**
+  *	scsi_disk_release - Called to free the scsi_disk structure
+  *	@dev: pointer to embedded class device
+@@ -1773,10 +2184,16 @@
+ 	idr_remove(&sd_index_idr, sdkp->index);
+ 	spin_unlock(&sd_index_lock);
+ 
++#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
++	if (sdkp->stats) {
++		remove_proc_entry(disk->disk_name, sd_iostats_procdir);
++		kfree(sdkp->stats);
++		sdkp->stats = NULL;
++	}
++#endif
+ 	disk->private_data = NULL;
+ 	put_disk(disk);
+ 	put_device(&sdkp->device->sdev_gendev);
+-
+ 	kfree(sdkp);
+ }
+ 
+@@ -1890,6 +2307,8 @@
+ 	if (!majors)
+ 		return -ENODEV;
+ 
++	sd_iostats_init();
++
+ 	err = class_register(&sd_disk_class);
+ 	if (err)
+ 		goto err_out;
+@@ -1905,6 +2324,7 @@
+ err_out:
+ 	for (i = 0; i < SD_MAJORS; i++)
+ 		unregister_blkdev(sd_major(i), "sd");
++	sd_iostats_fini();
+ 	return err;
+ }
+ 
+Index: linux-source-2.6.26/include/scsi/sd.h
+===================================================================
+--- linux-source-2.6.26.orig/include/scsi/sd.h	2009-10-09 13:33:25.000000000 +0200
++++ linux-source-2.6.26/include/scsi/sd.h	2009-10-09 13:39:06.000000000 +0200
+@@ -31,6 +31,46 @@
+  */
+ #define SD_BUF_SIZE		512
+ 
++#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
++typedef struct {
++	unsigned long long iostat_size;
++	unsigned long long iostat_count;
++} iostat_counter_t;
++
++#define IOSTAT_NCOUNTERS 16
++typedef struct {
++	iostat_counter_t	iostat_read_histogram[IOSTAT_NCOUNTERS];
++	iostat_counter_t	iostat_write_histogram[IOSTAT_NCOUNTERS];
++	struct timeval		iostat_timeval;
++
++	/* queue depth: how well the pipe is filled up */
++	unsigned long long	iostat_queue_ticks[IOSTAT_NCOUNTERS];
++	unsigned long long	iostat_queue_ticks_sum;
++	unsigned long		iostat_queue_depth;
++	unsigned long		iostat_queue_stamp;
++
++	/* seeks: how linear the traffic is */
++	unsigned long long	iostat_next_sector;
++	unsigned long long	iostat_seek_sectors;
++	unsigned long long	iostat_seeks;
++	unsigned long long	iostat_sectors;
++	unsigned long long	iostat_reqs;
++	unsigned long		iostat_read_reqs;
++	unsigned long		iostat_write_reqs;
++
++	/* process time: how long it takes to process requests */
++	unsigned long		iostat_rtime[IOSTAT_NCOUNTERS];
++	unsigned long		iostat_wtime[IOSTAT_NCOUNTERS];
++
++	/* queue time: how long process spent in elevator's queue */
++	unsigned long		iostat_rtime_in_queue[IOSTAT_NCOUNTERS];
++	unsigned long		iostat_wtime_in_queue[IOSTAT_NCOUNTERS];
++
++	/* must be the last field, as it's used to know size to be memset'ed */
++	spinlock_t		iostat_lock;
++} ____cacheline_aligned_in_smp iostat_stats_t;
++#endif
++
+ struct scsi_disk {
+ 	struct scsi_driver *driver;	/* always &sd_template */
+ 	struct scsi_device *device;
+@@ -45,6 +85,9 @@
+ 	unsigned	WCE : 1;	/* state of disk WCE bit */
+ 	unsigned	RCD : 1;	/* state of disk RCD bit, unused */
+ 	unsigned	DPOFUA : 1;	/* state of disk DPOFUA bit */
++#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
++	iostat_stats_t	*stats;		/* scsi disk statistics */
++#endif
+ };
+ #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev)
+ 
--- lustre-1.8.3.orig/lustre/kernel_patches/patches/md-mmp-unplug-dev-2.6.27-vanilla.patch
+++ lustre-1.8.3/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;
+ }
+ 
--- lustre-1.8.3.orig/lustre/kernel_patches/patches/debian-2.6.26.diff
+++ lustre-1.8.3/lustre/kernel_patches/patches/debian-2.6.26.diff
@@ -0,0 +1,1210 @@
+diff -u -r debian-2.6.26/Documentation/filesystems/ext2.txt debian-2.6.26_lustre.1.8.2/Documentation/filesystems/ext2.txt
+--- debian-2.6.26/Documentation/filesystems/ext2.txt	2008-07-13 23:51:29.000000000 +0200
++++ debian-2.6.26_lustre.1.8.2/Documentation/filesystems/ext2.txt	2010-02-12 15:11:19.000000000 +0100
+@@ -58,6 +58,22 @@
+ 
+ xip				Use execute in place (no caching) if possible
+ 
++iopen                          Makes an invisible pseudo-directory called 
++                               __iopen__ available in the root directory
++                               of the filesystem.  Allows open-by-inode-
++                               number.  i.e., inode 3145 can be accessed
++                               via /mntpt/__iopen__/3145
++
++iopen_nopriv                   This option makes the iopen directory be
++                               world-readable.  This may be safer since it
++                               allows daemons to run as an unprivileged user,
++                               however it significantly changes the security
++                               model of a Unix filesystem, since previously
++                               all files under a mode 700 directory were not
++                               generally avilable even if the
++                               permissions on the file itself is
++                               world-readable.
++
+ grpquota,noquota,quota,usrquota	Quota options are silently ignored by ext2.
+ 
+ 
+diff -u -r debian-2.6.26/block/blk-core.c debian-2.6.26_lustre.1.8.2/block/blk-core.c
+--- debian-2.6.26/block/blk-core.c	2008-07-13 23:51:29.000000000 +0200
++++ debian-2.6.26_lustre.1.8.2/block/blk-core.c	2010-02-12 15:14:32.000000000 +0100
+@@ -1270,6 +1270,8 @@
+ 
+ #endif /* CONFIG_FAIL_MAKE_REQUEST */
+ 
++int dev_check_rdonly(struct block_device *bdev);
++
+ /*
+  * Check whether this bio extends beyond the end of the device.
+  */
+@@ -1371,6 +1373,12 @@
+ 
+ 		if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags)))
+ 			goto end_io;
++                /* this is cfs's dev_rdonly check */
++                if (bio->bi_rw == WRITE &&
++                                dev_check_rdonly(bio->bi_bdev)) {
++                        bio_endio(bio, 0);
++                        break;
++                }
+ 
+ 		if (should_fail_request(bio))
+ 			goto end_io;
+@@ -2028,6 +2036,91 @@
+ }
+ EXPORT_SYMBOL(kblockd_flush_work);
+ 
++ /*
++ * Debug code for turning block devices "read-only" (will discard writes
++ * silently).  This is for filesystem crash/recovery testing.
++ */
++struct deventry {
++       dev_t dev;
++       struct deventry *next;
++};
++
++static struct deventry *devlist = NULL;
++static spinlock_t devlock = SPIN_LOCK_UNLOCKED;
++
++int dev_check_rdonly(struct block_device *bdev)
++{
++       struct deventry *cur;
++       if (!bdev) return 0;
++       spin_lock(&devlock);
++       cur = devlist;
++       while(cur) {
++               if (bdev->bd_dev == cur->dev) {
++                       spin_unlock(&devlock);
++                       return 1;
++       }
++               cur = cur->next;
++       }
++       spin_unlock(&devlock);
++       return 0;
++}
++
++void dev_set_rdonly(struct block_device *bdev)
++{
++       struct deventry *newdev, *cur;
++
++       if (!bdev)
++               return;
++       newdev = kmalloc(sizeof(struct deventry), GFP_KERNEL);
++       if (!newdev)
++               return;
++
++       spin_lock(&devlock);
++       cur = devlist;
++       while(cur) {
++               if (bdev->bd_dev == cur->dev) {
++                       spin_unlock(&devlock);
++                       kfree(newdev);
++                       return;
++               }
++               cur = cur->next;
++       }
++       newdev->dev = bdev->bd_dev;
++       newdev->next = devlist;
++       devlist = newdev;
++       spin_unlock(&devlock);
++       printk(KERN_WARNING "Turning device %s (%#x) read-only\n",
++              bdev->bd_disk ? bdev->bd_disk->disk_name : "", bdev->bd_dev);
++}
++
++void dev_clear_rdonly(struct block_device *bdev)
++{
++       struct deventry *cur, *last = NULL;
++       if (!bdev) return;
++       spin_lock(&devlock);
++       cur = devlist;
++       while(cur) {
++               if (bdev->bd_dev == cur->dev) {
++                       if (last)
++                               last->next = cur->next;
++                       else
++                               devlist = cur->next;
++                       spin_unlock(&devlock);
++                       kfree(cur);
++                       printk(KERN_WARNING "Removing read-only on %s (%#x)\n",
++                              bdev->bd_disk ? bdev->bd_disk->disk_name :
++                                              "unknown block", bdev->bd_dev);
++                       return;
++               }
++               last = cur;
++               cur = cur->next;
++       }
++       spin_unlock(&devlock);
++}
++
++EXPORT_SYMBOL(dev_set_rdonly);
++EXPORT_SYMBOL(dev_clear_rdonly);
++
+ int __init blk_dev_init(void)
+ {
+ 	int i;
+diff -u -r debian-2.6.26/drivers/md/raid5.c debian-2.6.26_lustre.1.8.2/drivers/md/raid5.c
+--- debian-2.6.26/drivers/md/raid5.c	2008-07-13 23:51:29.000000000 +0200
++++ debian-2.6.26_lustre.1.8.2/drivers/md/raid5.c	2010-02-12 15:19:25.000000000 +0100
+@@ -1817,6 +1817,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);
+ 
+@@ -3699,6 +3701,8 @@
+ 			      test_bit(BIO_UPTODATE, &bi->bi_flags)
+ 			        ? 0 : -EIO);
+ 	}
++	if (bio_sync(bi))
++		raid5_unplug_device(q);
+ 	return 0;
+ }
+ 
+diff -u -r debian-2.6.26/drivers/scsi/Kconfig debian-2.6.26_lustre.1.8.2/drivers/scsi/Kconfig
+--- debian-2.6.26/drivers/scsi/Kconfig	2009-12-26 09:14:53.000000000 +0100
++++ debian-2.6.26_lustre.1.8.2/drivers/scsi/Kconfig	2010-02-12 15:20:02.000000000 +0100
+@@ -81,6 +81,14 @@
+ 	  In this case, do not compile the driver for your SCSI host adapter
+ 	  (below) as a module either.
+ 
++config SD_IOSTATS
++   bool "Enable SCSI disk I/O stats"
++   depends on BLK_DEV_SD
++   default y
++   ---help---
++     This enables SCSI disk I/O stats collection.  You must also enable
++     /proc file system support if you want this feature.
++
+ config CHR_DEV_ST
+ 	tristate "SCSI tape support"
+ 	depends on SCSI
+diff -u -r debian-2.6.26/drivers/scsi/scsi_proc.c debian-2.6.26_lustre.1.8.2/drivers/scsi/scsi_proc.c
+--- debian-2.6.26/drivers/scsi/scsi_proc.c	2008-07-13 23:51:29.000000000 +0200
++++ debian-2.6.26_lustre.1.8.2/drivers/scsi/scsi_proc.c	2010-02-12 15:22:05.000000000 +0100
+@@ -40,7 +40,8 @@
+ /* 4K page size, but our output routines, use some slack for overruns */
+ #define PROC_BLOCK_SIZE (3*1024)
+ 
+-static struct proc_dir_entry *proc_scsi;
++struct proc_dir_entry *proc_scsi;
++EXPORT_SYMBOL(proc_scsi);
+ 
+ /* Protect sht->present and sht->proc_dir */
+ static DEFINE_MUTEX(global_host_template_mutex);
+diff -u -r debian-2.6.26/drivers/scsi/sd.c debian-2.6.26_lustre.1.8.2/drivers/scsi/sd.c
+--- debian-2.6.26/drivers/scsi/sd.c	2008-07-13 23:51:29.000000000 +0200
++++ debian-2.6.26_lustre.1.8.2/drivers/scsi/sd.c	2010-02-17 14:13:32.000000000 +0100
+@@ -107,6 +107,24 @@
+  * object after last put) */
+ static DEFINE_MUTEX(sd_ref_mutex);
+ 
++#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
++# include <linux/proc_fs.h>
++# include <linux/seq_file.h>
++struct proc_dir_entry *sd_iostats_procdir = NULL;
++char sd_iostats_procdir_name[] = "sd_iostats";
++static struct file_operations sd_iostats_proc_fops;
++
++extern void sd_iostats_init(void);
++extern void sd_iostats_fini(void);
++void sd_iostats_start_req(struct scsi_cmnd *SCpnt);
++void sd_iostats_finish_req(struct scsi_cmnd *SCpnt);
++#else
++static inline void sd_iostats_init(void) {}
++static inline void sd_iostats_fini(void) {}
++static inline void sd_iostats_start_req(struct scsi_cmnd *SCpnt) {}
++static inline void sd_iostats_finish_req(struct scsi_cmnd *SCpnt) {}
++#endif
++
+ static const char *sd_cache_types[] = {
+ 	"write through", "none", "write back",
+ 	"write back, no read (daft)"
+@@ -531,6 +549,8 @@
+ 	}
+ 	SCpnt->sdb.length = this_count * sdp->sector_size;
+ 
++	sd_iostats_start_req(SCpnt);
++
+ 	/*
+ 	 * We shouldn't disconnect in the middle of a sector, so with a dumb
+ 	 * host adapter, it's safe to assume that we can at least transfer
+@@ -667,7 +687,7 @@
+ 	int diskinfo[4];
+ 
+ 	/* default to most commonly used values */
+-        diskinfo[0] = 0x40;	/* 1 << 6 */
++	diskinfo[0] = 0x40;	/* 1 << 6 */
+        	diskinfo[1] = 0x20;	/* 1 << 5 */
+        	diskinfo[2] = sdkp->capacity >> 11;
+ 	
+@@ -1023,6 +1043,7 @@
+ 		break;
+ 	}
+  out:
++	sd_iostats_finish_req(SCpnt);
+ 	return good_bytes;
+ }
+ 
+@@ -1711,6 +1732,36 @@
+ 	gd->flags = GENHD_FL_DRIVERFS;
+ 	if (sdp->removable)
+ 		gd->flags |= GENHD_FL_REMOVABLE;
++#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
++       sdkp->stats = kzalloc(sizeof(iostat_stats_t), GFP_KERNEL);
++       if (!sdkp->stats) {
++	       printk(KERN_WARNING "cannot allocate iostat structure for"
++	                           "%s\n", gd->disk_name);
++       } else {
++	       do_gettimeofday(&sdkp->stats->iostat_timeval);
++	       sdkp->stats->iostat_queue_stamp = jiffies;
++	       spin_lock_init(&sdkp->stats->iostat_lock);
++	       if (sd_iostats_procdir) {
++	               struct proc_dir_entry *pde;
++	               pde = create_proc_entry(gd->disk_name, S_IRUGO | S_IWUSR,
++	                                       sd_iostats_procdir);
++	               if (!pde) {
++	                       printk(KERN_WARNING "Can't create /proc/scsi/"
++	                                           "%s/%s\n",
++	                                           sd_iostats_procdir_name,
++	                                           gd->disk_name);
++	                       kfree(sdkp->stats);
++	                       sdkp->stats = NULL;
++	               } else {
++	                       pde->proc_fops = &sd_iostats_proc_fops;
++	                       pde->data = gd;
++	               }
++	       } else {
++	               kfree(sdkp->stats);
++	               sdkp->stats = NULL;
++	       }
++       }
++#endif
+ 
+ 	dev_set_drvdata(dev, sdkp);
+ 	add_disk(gd);
+@@ -1755,6 +1806,366 @@
+ 	return 0;
+ }
+ 
++#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
++static int
++ sd_iostats_seq_show(struct seq_file *seq, void *v)
++ {
++	struct timeval     now;
++	struct gendisk *disk = seq->private;
++	iostat_stats_t    *stats;
++	unsigned long long read_len;
++	unsigned long long read_len_tot;
++	unsigned long      read_num;
++	unsigned long      read_num_tot;
++	unsigned long long write_len;
++	unsigned long long write_len_tot;
++	unsigned long      write_num;
++	unsigned long      write_num_tot;
++	int                i;
++	int                maxi;
++ 
++	stats = scsi_disk(disk)->stats;
++	if (stats == NULL) {
++	        printk(KERN_ERR "sd_iostats_seq_show: NULL stats entry\n");
++	        BUG();
++	}
++ 
++	do_gettimeofday(&now);
++	now.tv_sec -= stats->iostat_timeval.tv_sec;
++	now.tv_usec -= stats->iostat_timeval.tv_usec;
++	if (now.tv_usec < 0) {
++	        now.tv_usec += 1000000;
++	        now.tv_sec--;
++	}
++ 
++	/* this sampling races with updates */
++	seq_printf(seq, "index:        %lu   snapshot_time:         %lu.%06lu\n",
++	                (unsigned long) scsi_disk(disk)->index,
++	                now.tv_sec, now.tv_usec);
++ 
++	for (i = IOSTAT_NCOUNTERS - 1; i > 0; i--)
++	        if (stats->iostat_read_histogram[i].iostat_count != 0 ||
++	                        stats->iostat_write_histogram[i].iostat_count != 0)
++	                break;
++	maxi = i;
++ 
++	seq_printf(seq, "%8s %8s %12s %8s %12s\n", "size", 
++	                "reads", "total", "writes", "total");
++ 
++	read_len_tot = write_len_tot = 0;
++	read_num_tot = write_num_tot = 0;
++	for (i = 0; i <= maxi; i++) {
++	        read_len = stats->iostat_read_histogram[i].iostat_size;
++	        read_len_tot += read_len;
++	        read_num = stats->iostat_read_histogram[i].iostat_count;
++	        read_num_tot += read_num;
++ 
++	        write_len = stats->iostat_write_histogram[i].iostat_size;
++	        write_len_tot += write_len;
++	        write_num = stats->iostat_write_histogram[i].iostat_count;
++	        write_num_tot += write_num;
++ 
++	        seq_printf (seq, "%8d %8lu %12llu %8lu %12llu\n", 
++	                        512<<i, read_num, read_len, write_num, write_len);
++	}
++ 
++	seq_printf(seq, "%8s %8lu %12llu %8lu %12llu\n\n", "total",
++	                read_num_tot, read_len_tot, 
++	                write_num_tot, write_len_tot);
++ 
++	seq_printf(seq, "%8s %8s %8s\n", "qdepth", "ticks", "%");
++	for (i = 0; i < IOSTAT_NCOUNTERS; i++) {
++	        unsigned long long ticks, percent;
++	        ticks = stats->iostat_queue_ticks[i];
++	        if (ticks == 0)
++	                continue;
++	        percent = stats->iostat_queue_ticks[i] * 100;
++	        do_div(percent, stats->iostat_queue_ticks_sum);
++	        seq_printf(seq, "%8d %8llu %8llu\n", i, ticks, percent);
++	}
++ 
++	if (stats->iostat_reqs != 0) {
++	        unsigned long long aveseek = 0, percent = 0;
++ 
++	        if (stats->iostat_seeks) {
++	                aveseek = stats->iostat_seek_sectors;
++	                do_div(aveseek, stats->iostat_seeks);
++	                percent = stats->iostat_seeks * 100;
++	                do_div(percent, stats->iostat_reqs);
++	        }
++ 
++	        seq_printf(seq, "\n%llu sectors in %llu reqs: %llu seek(s) over "
++	                        "%llu sectors in ave, %llu%% of all reqs\n",
++	                        stats->iostat_sectors, stats->iostat_reqs,
++	                        stats->iostat_seeks, aveseek, percent);
++	}
++ 
++	seq_printf(seq, "\n%16s %8s %8s %8s %8s\n", "process time", "reads",
++	                "%%", "writes", "%%");
++	for (i = 0; i < IOSTAT_NCOUNTERS; i++) {
++	        unsigned long read_percent = 0, write_percent = 0;
++	        if (stats->iostat_wtime[i] == 0 &&
++	                        stats->iostat_rtime[i] == 0)
++	                continue;
++	        if (stats->iostat_read_reqs)
++	                read_percent = stats->iostat_rtime[i] * 100 / 
++	                        stats->iostat_read_reqs;
++	        if (stats->iostat_write_reqs)
++	                write_percent = stats->iostat_wtime[i] * 100 / 
++	                        stats->iostat_write_reqs;
++	        seq_printf(seq, "%16u %8lu %8lu %8lu %8lu\n",
++	                        jiffies_to_msecs(((1UL << i) >> 1) << 1),
++	                        stats->iostat_rtime[i], read_percent,
++	                        stats->iostat_wtime[i], write_percent);
++	}
++ 
++	seq_printf(seq, "\n%16s %8s %8s %8s %8s\n", "time in queue", "reads",
++	                "%%", "writes", "%%");
++	for (i = 0; i < IOSTAT_NCOUNTERS; i++) {
++	        unsigned long read_percent = 0, write_percent = 0;
++	        if (stats->iostat_wtime_in_queue[i] == 0 &&
++	                        stats->iostat_rtime_in_queue[i] == 0)
++	                continue;
++	        if (stats->iostat_read_reqs)
++	                read_percent = stats->iostat_rtime_in_queue[i] * 100 / 
++	                        stats->iostat_read_reqs;
++	        if (stats->iostat_write_reqs)
++	                write_percent = stats->iostat_wtime_in_queue[i] * 100 / 
++	                        stats->iostat_write_reqs;
++	        seq_printf(seq, "%16u %8lu %8lu %8lu %8lu\n",
++	                        jiffies_to_msecs(((1UL << i) >> 1) << 1),
++	                        stats->iostat_rtime_in_queue[i],
++	                        read_percent,
++	                        stats->iostat_wtime_in_queue[i],
++	                        write_percent);
++	}
++ 
++	return 0;
++ }
++ 
++ static void *
++ sd_iostats_seq_start(struct seq_file *p, loff_t *pos)
++ {
++	return (*pos == 0) ? (void *)1 : NULL;
++ }
++ 
++ static void *
++ sd_iostats_seq_next(struct seq_file *p, void *v, loff_t *pos)
++ {
++	++*pos;
++	return NULL;
++ }
++ 
++ static void
++ sd_iostats_seq_stop(struct seq_file *p, void *v)
++ {
++ }
++ 
++ static struct seq_operations sd_iostats_seqops = {
++	.start = sd_iostats_seq_start,
++	.stop  = sd_iostats_seq_stop,
++	.next  = sd_iostats_seq_next,
++	.show  = sd_iostats_seq_show,
++ };
++ 
++ static int
++ sd_iostats_seq_open (struct inode *inode, struct file *file)
++ {
++	int rc;
++ 
++	rc = seq_open(file, &sd_iostats_seqops);
++	if (rc != 0)
++	        return rc;
++ 
++	((struct seq_file *)file->private_data)->private = PDE(inode)->data;
++	return 0;
++ }
++ 
++ static ssize_t
++ sd_iostats_seq_write(struct file *file, const char *buffer,
++	             size_t len, loff_t *off)
++ {
++	struct seq_file   *seq = file->private_data;
++	struct gendisk *disk = seq->private;
++	iostat_stats_t    *stats = scsi_disk(disk)->stats;
++	unsigned long      flags;
++	unsigned long      qdepth;
++ 
++ 
++	spin_lock_irqsave (&stats->iostat_lock, flags);
++	qdepth = stats->iostat_queue_depth;
++	memset (stats, 0, offsetof(iostat_stats_t, iostat_lock));
++	do_gettimeofday(&stats->iostat_timeval);
++	stats->iostat_queue_stamp = jiffies;
++	stats->iostat_queue_depth = qdepth;
++	spin_unlock_irqrestore (&stats->iostat_lock, flags);
++ 
++	return len;
++ }
++ 
++ static struct file_operations sd_iostats_proc_fops = {
++	.owner   = THIS_MODULE,
++	.open    = sd_iostats_seq_open,
++	.read    = seq_read,
++	.write   = sd_iostats_seq_write,
++	.llseek  = seq_lseek,
++	.release = seq_release,
++ };
++ 
++ extern struct proc_dir_entry *proc_scsi;
++ 
++ void
++ sd_iostats_init(void)
++ {
++	if (proc_scsi == NULL) {
++	        printk(KERN_WARNING "No access to sd iostats: "
++	                "proc_scsi is NULL\n");
++	        return;
++	}
++ 
++	sd_iostats_procdir = create_proc_entry(sd_iostats_procdir_name,
++	                                       S_IFDIR | S_IRUGO | S_IXUGO,
++	                                        proc_scsi);
++	if (sd_iostats_procdir == NULL) {
++	        printk(KERN_WARNING "No access to sd iostats: "
++	                "can't create /proc/scsi/%s\n", sd_iostats_procdir_name);
++	        return;
++	}
++ }
++ 
++ void sd_iostats_fini(void)
++ {
++	if (proc_scsi != NULL && sd_iostats_procdir != NULL)
++	        remove_proc_entry(sd_iostats_procdir_name, proc_scsi);
++ 
++	sd_iostats_procdir = NULL;
++ }
++ 
++ void sd_iostats_finish_req(struct scsi_cmnd *SCpnt)
++ {
++	struct request          *rq = SCpnt->request;
++	iostat_stats_t          *stats;
++	unsigned long           *tcounter;
++	int                     tbucket;
++	int                     tmp;
++	unsigned long           irqflags;
++	unsigned long           i;
++ 
++	stats = scsi_disk(rq->rq_disk)->stats;
++	if (stats == NULL)
++	        return;
++ 
++	tmp = jiffies - rq->start_time;
++	for (tbucket = 0; tmp > 1; tbucket++)
++	        tmp >>= 1;
++	if (tbucket >= IOSTAT_NCOUNTERS)
++	        tbucket = IOSTAT_NCOUNTERS - 1;
++	//printk("%u ticks in D to %u\n", jiffies - rq->start_time, tbucket);
++ 
++	tcounter = rq_data_dir(rq) == WRITE ?
++	        &stats->iostat_wtime[tbucket] : &stats->iostat_rtime[tbucket];
++ 
++	spin_lock_irqsave(&stats->iostat_lock, irqflags);
++ 
++	/* update delay stats */
++	(*tcounter)++;
++ 
++	/* update queue depth stats */
++	i = stats->iostat_queue_depth;
++	if (i >= IOSTAT_NCOUNTERS)
++	        i = IOSTAT_NCOUNTERS - 1;
++	stats->iostat_queue_ticks[i] += jiffies - stats->iostat_queue_stamp;
++	stats->iostat_queue_ticks_sum += jiffies - stats->iostat_queue_stamp;
++	BUG_ON(stats->iostat_queue_depth == 0);
++	stats->iostat_queue_depth--;
++ 
++	/* update seek stats. XXX: not sure about nr_sectors */
++	stats->iostat_sectors += rq->nr_sectors;
++	stats->iostat_reqs++;
++	if (rq->sector != stats->iostat_next_sector) {
++	        stats->iostat_seek_sectors +=
++	                rq->sector > stats->iostat_next_sector ?
++	                rq->sector - stats->iostat_next_sector :
++	                stats->iostat_next_sector - rq->sector;
++	        stats->iostat_seeks++;
++	}
++	stats->iostat_next_sector = rq->sector + rq->nr_sectors;
++ 
++	stats->iostat_queue_stamp = jiffies;
++ 
++	spin_unlock_irqrestore(&stats->iostat_lock, irqflags);
++ }
++ 
++ void sd_iostats_start_req(struct scsi_cmnd *SCpnt)
++ {
++	struct request          *rq = SCpnt->request;
++	iostat_stats_t          *stats;
++	iostat_counter_t        *counter;
++	int                     bucket;
++	int                     tbucket;
++	int                     tmp;
++	unsigned long           irqflags;
++	unsigned long           i;
++	int                     nsect;
++ 
++	stats = scsi_disk(rq->rq_disk)->stats;
++	if (stats == NULL)
++	        return;
++ 
++	nsect = scsi_bufflen(SCpnt) >> 9;
++	for (bucket = 0, tmp = nsect; tmp > 1; bucket++)
++	        tmp >>= 1;
++ 
++	if (bucket >= IOSTAT_NCOUNTERS) {
++	        printk (KERN_ERR "sd_iostats_bump: nsect %d too big\n", nsect);
++	        BUG();
++	}
++ 
++	counter = rq_data_dir(rq) == WRITE ?
++	        &stats->iostat_write_histogram[bucket] :
++	        &stats->iostat_read_histogram[bucket];
++ 
++	tmp = jiffies - rq->start_time;
++	for (tbucket = 0; tmp > 1; tbucket++)
++	        tmp >>= 1;
++	if (tbucket >= IOSTAT_NCOUNTERS)
++	        tbucket = IOSTAT_NCOUNTERS - 1;
++	//printk("%u ticks in Q to %u\n", jiffies - rq->start_time, tbucket);
++ 
++	/* an ugly hack to know exact processing time. the right
++	 * solution is to add one more field to struct request
++	 * hopefully it will break nothing ... */
++	rq->start_time = jiffies;
++ 
++	spin_lock_irqsave(&stats->iostat_lock, irqflags);
++ 
++	/* update queue depth stats */
++	i = stats->iostat_queue_depth;
++	if (i >= IOSTAT_NCOUNTERS)
++	        i = IOSTAT_NCOUNTERS - 1;
++	stats->iostat_queue_ticks[i] += jiffies - stats->iostat_queue_stamp;
++	stats->iostat_queue_ticks_sum += jiffies - stats->iostat_queue_stamp;
++	stats->iostat_queue_depth++;
++ 
++	/* update delay stats */
++	if (rq_data_dir(rq) == WRITE) {
++	        stats->iostat_wtime_in_queue[tbucket]++;
++	        stats->iostat_write_reqs++;
++	} else {
++	        stats->iostat_rtime_in_queue[tbucket]++;
++	        stats->iostat_read_reqs++;
++	}
++ 
++	/* update size stats */
++	counter->iostat_size += nsect;
++	counter->iostat_count++;
++ 
++	stats->iostat_queue_stamp = jiffies;
++ 
++	spin_unlock_irqrestore(&stats->iostat_lock, irqflags);
++}
++#endif
++
+ /**
+  *	scsi_disk_release - Called to free the scsi_disk structure
+  *	@dev: pointer to embedded class device
+@@ -1773,6 +2184,13 @@
+ 	idr_remove(&sd_index_idr, sdkp->index);
+ 	spin_unlock(&sd_index_lock);
+ 
++#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
++        if (sdkp->stats) {
++                remove_proc_entry(disk->disk_name, sd_iostats_procdir);
++                kfree(sdkp->stats);
++                sdkp->stats = NULL;
++        }
++#endif
+ 	disk->private_data = NULL;
+ 	put_disk(disk);
+ 	put_device(&sdkp->device->sdev_gendev);
+@@ -1890,6 +2308,8 @@
+ 	if (!majors)
+ 		return -ENODEV;
+ 
++	sd_iostats_init();
++
+ 	err = class_register(&sd_disk_class);
+ 	if (err)
+ 		goto err_out;
+@@ -1905,6 +2325,7 @@
+ err_out:
+ 	for (i = 0; i < SD_MAJORS; i++)
+ 		unregister_blkdev(sd_major(i), "sd");
++	sd_iostats_fini();
+ 	return err;
+ }
+ 
+diff -u -r debian-2.6.26/fs/block_dev.c debian-2.6.26_lustre.1.8.2/fs/block_dev.c
+--- debian-2.6.26/fs/block_dev.c	2008-07-13 23:51:29.000000000 +0200
++++ debian-2.6.26_lustre.1.8.2/fs/block_dev.c	2010-02-17 14:19:50.000000000 +0100
+@@ -1125,6 +1125,7 @@
+ 		if (bdev != bdev->bd_contains)
+ 			victim = bdev->bd_contains;
+ 		bdev->bd_contains = NULL;
++		dev_clear_rdonly(bdev);
+ 	}
+ 	unlock_kernel();
+ 	mutex_unlock(&bdev->bd_mutex);
+diff -u -r debian-2.6.26/fs/dcache.c debian-2.6.26_lustre.1.8.2/fs/dcache.c
+--- debian-2.6.26/fs/dcache.c	2009-12-26 09:14:56.000000000 +0100
++++ debian-2.6.26_lustre.1.8.2/fs/dcache.c	2010-02-17 14:24:24.000000000 +0100
+@@ -250,6 +250,13 @@
+ 		spin_unlock(&dcache_lock);
+ 		return 0;
+ 	}
++
++        /* network invalidation by Lustre */
++        if (dentry->d_flags & DCACHE_LUSTRE_INVALID) {
++                spin_unlock(&dcache_lock);
++                return 0;
++        }
++
+ 	/*
+ 	 * Check whether to do a partial shrink_dcache
+ 	 * to get rid of unused child entries.
+@@ -1427,14 +1434,23 @@
+  *
+  * Adds a dentry to the hash according to its name.
+  */
+- 
++
++void d_rehash_cond(struct dentry * entry, int lock)
++{
++        if (lock)
++                spin_lock(&dcache_lock);
++        spin_lock(&entry->d_lock);
++        _d_rehash(entry);
++        spin_unlock(&entry->d_lock);
++        if (lock)
++                spin_unlock(&dcache_lock);
++}
++
++EXPORT_SYMBOL(d_rehash_cond);
++
+ void d_rehash(struct dentry * entry)
+ {
+-	spin_lock(&dcache_lock);
+-	spin_lock(&entry->d_lock);
+-	_d_rehash(entry);
+-	spin_unlock(&entry->d_lock);
+-	spin_unlock(&dcache_lock);
++	d_rehash_cond(entry, 1);
+ }
+ 
+ #define do_switch(x,y) do { \
+@@ -1510,7 +1526,7 @@
+  * Update the dcache to reflect the move of a file name. Negative
+  * dcache entries should not be moved in this way.
+  */
+-static void d_move_locked(struct dentry * dentry, struct dentry * target)
++void d_move_locked(struct dentry * dentry, struct dentry * target)
+ {
+ 	struct hlist_head *list;
+ 
+@@ -1568,6 +1584,7 @@
+ 	spin_unlock(&dentry->d_lock);
+ 	write_sequnlock(&rename_lock);
+ }
++EXPORT_SYMBOL(d_move_locked);
+ 
+ /**
+  * d_move - move a dentry
+@@ -2051,6 +2068,7 @@
+ 
+ 	return result;
+ }
++EXPORT_SYMBOL(is_subdir);
+ 
+ void d_genocide(struct dentry *root)
+ {
+diff -u -r debian-2.6.26/fs/filesystems.c debian-2.6.26_lustre.1.8.2/fs/filesystems.c
+--- debian-2.6.26/fs/filesystems.c	2009-12-26 09:14:56.000000000 +0100
++++ debian-2.6.26_lustre.1.8.2/fs/filesystems.c	2010-02-17 14:26:59.000000000 +0100
+@@ -28,7 +28,9 @@
+  */
+ 
+ static struct file_system_type *file_systems;
+-static DEFINE_RWLOCK(file_systems_lock);
++DEFINE_RWLOCK(file_systems_lock);
++
++EXPORT_SYMBOL(file_systems_lock);
+ 
+ /* WARNING: This can be used only if we _already_ own a reference */
+ void get_filesystem(struct file_system_type *fs)
+diff -u -r debian-2.6.26/fs/inode.c debian-2.6.26_lustre.1.8.2/fs/inode.c
+--- debian-2.6.26/fs/inode.c	2008-07-13 23:51:29.000000000 +0200
++++ debian-2.6.26_lustre.1.8.2/fs/inode.c	2010-02-17 14:27:51.000000000 +0100
+@@ -409,7 +409,9 @@
+ 	int nr_scanned;
+ 	unsigned long reap = 0;
+ 
+-	mutex_lock(&iprune_mutex);
++	if (!mutex_trylock(&iprune_mutex))
++		return;
++
+ 	spin_lock(&inode_lock);
+ 	for (nr_scanned = 0; nr_scanned < nr_to_scan; nr_scanned++) {
+ 		struct inode *inode;
+diff -u -r debian-2.6.26/fs/jbd2/checkpoint.c debian-2.6.26_lustre.1.8.2/fs/jbd2/checkpoint.c
+--- debian-2.6.26/fs/jbd2/checkpoint.c	2008-07-13 23:51:29.000000000 +0200
++++ debian-2.6.26_lustre.1.8.2/fs/jbd2/checkpoint.c	2010-02-17 14:28:49.000000000 +0100
+@@ -696,6 +696,7 @@
+ 	J_ASSERT(transaction->t_checkpoint_list == NULL);
+ 	J_ASSERT(transaction->t_checkpoint_io_list == NULL);
+ 	J_ASSERT(transaction->t_updates == 0);
++	J_ASSERT(list_empty(&transaction->t_jcb));
+ 	J_ASSERT(journal->j_committing_transaction != transaction);
+ 	J_ASSERT(journal->j_running_transaction != transaction);
+ 
+diff -u -r debian-2.6.26/fs/jbd2/commit.c debian-2.6.26_lustre.1.8.2/fs/jbd2/commit.c
+--- debian-2.6.26/fs/jbd2/commit.c	2008-07-13 23:51:29.000000000 +0200
++++ debian-2.6.26_lustre.1.8.2/fs/jbd2/commit.c	2010-02-17 14:29:44.000000000 +0100
+@@ -874,6 +874,30 @@
+            transaction can be removed from any checkpoint list it was on
+            before. */
+ 
++        /*
++         * Call any callbacks that had been registered for handles in this
++         * transaction.  It is up to the callback to free any allocated
++         * memory.
++         *
++         * The spinlocking (t_jcb_lock) here is surely unnecessary...
++         */
++        spin_lock(&commit_transaction->t_jcb_lock);
++        if (!list_empty(&commit_transaction->t_jcb)) {
++                struct list_head *p, *n;
++                int error = is_journal_aborted(journal);
++
++                list_for_each_safe(p, n, &commit_transaction->t_jcb) {
++                        struct journal_callback *jcb;
++
++                        jcb = list_entry(p, struct journal_callback, jcb_list);
++                        list_del(p);
++                        spin_unlock(&commit_transaction->t_jcb_lock);
++                        jcb->jcb_func(jcb, error);
++                        spin_lock(&commit_transaction->t_jcb_lock);
++                }
++        }
++        spin_unlock(&commit_transaction->t_jcb_lock);
++
+ 	jbd_debug(3, "JBD: commit phase 7\n");
+ 
+ 	J_ASSERT(commit_transaction->t_sync_datalist == NULL);
+diff -u -r debian-2.6.26/fs/jbd2/journal.c debian-2.6.26_lustre.1.8.2/fs/jbd2/journal.c
+--- debian-2.6.26/fs/jbd2/journal.c	2008-07-13 23:51:29.000000000 +0200
++++ debian-2.6.26_lustre.1.8.2/fs/jbd2/journal.c	2010-02-17 14:38:15.000000000 +0100
+@@ -82,6 +82,8 @@
+ EXPORT_SYMBOL(jbd2_journal_invalidatepage);
+ EXPORT_SYMBOL(jbd2_journal_try_to_free_buffers);
+ EXPORT_SYMBOL(jbd2_journal_force_commit);
++EXPORT_SYMBOL(jbd2_journal_callback_set);
++EXPORT_SYMBOL(jbd2_journal_bmap);
+ 
+ static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *);
+ static void __journal_abort_soft (journal_t *journal, int errno);
+@@ -460,6 +462,7 @@
+ 	spin_unlock(&journal->j_state_lock);
+ 	return ret;
+ }
++EXPORT_SYMBOL(jbd2_log_start_commit);
+ 
+ /*
+  * Force and wait upon a commit if the calling process is not within
+diff -u -r debian-2.6.26/fs/jbd2/transaction.c debian-2.6.26_lustre.1.8.2/fs/jbd2/transaction.c
+--- debian-2.6.26/fs/jbd2/transaction.c	2008-07-13 23:51:29.000000000 +0200
++++ debian-2.6.26_lustre.1.8.2/fs/jbd2/transaction.c	2010-02-17 14:42:20.000000000 +0100
+@@ -51,10 +51,12 @@
+ 	transaction->t_state = T_RUNNING;
+ 	transaction->t_tid = journal->j_transaction_sequence++;
+ 	transaction->t_expires = jiffies + journal->j_commit_interval;
++	INIT_LIST_HEAD(&transaction->t_jcb);
+ 	spin_lock_init(&transaction->t_handle_lock);
++	spin_lock_init(&transaction->t_jcb_lock);
+ 
+ 	/* Set up the commit timer for the new transaction. */
+-	journal->j_commit_timer.expires = round_jiffies(transaction->t_expires);
++	journal->j_commit_timer.expires = transaction->t_expires;
+ 	add_timer(&journal->j_commit_timer);
+ 
+ 	J_ASSERT(journal->j_running_transaction == NULL);
+@@ -252,6 +254,7 @@
+ 	memset(handle, 0, sizeof(*handle));
+ 	handle->h_buffer_credits = nblocks;
+ 	handle->h_ref = 1;
++	INIT_LIST_HEAD(&handle->h_jcb);
+ 
+ 	lockdep_init_map(&handle->h_lockdep_map, "jbd2_handle",
+ 						&jbd2_handle_key, 0);
+@@ -1350,6 +1353,36 @@
+ }
+ 
+ /**
++ * void jbd2_journal_callback_set() -  Register a callback function for this handle.
++ * @handle: handle to attach the callback to.
++ * @func: function to callback.
++ * @jcb:  structure with additional information required by func() , and
++ *      some space for jbd2 internal information.
++ *
++ * The function will be
++ * called when the transaction that this handle is part of has been
++ * committed to disk with the original callback data struct and the
++ * error status of the journal as parameters.  There is no guarantee of
++ * ordering between handles within a single transaction, nor between
++ * callbacks registered on the same handle.
++ *
++ * The caller is responsible for allocating the journal_callback struct.
++ * This is to allow the caller to add as much extra data to the callback
++ * as needed, but reduce the overhead of multiple allocations.  The caller
++ * allocated struct must start with a struct journal_callback at offset 0,
++ * and has the caller-specific data afterwards.
++ */
++void jbd2_journal_callback_set(handle_t *handle,
++                      void (*func)(struct journal_callback *jcb, int error),
++                      struct journal_callback *jcb)
++{
++        spin_lock(&handle->h_transaction->t_jcb_lock);
++        list_add_tail(&jcb->jcb_list, &handle->h_jcb);
++        spin_unlock(&handle->h_transaction->t_jcb_lock);
++        jcb->jcb_func = func;
++}
++
++/**
+  * int jbd2_journal_stop() - complete a transaction
+  * @handle: tranaction to complete.
+  *
+@@ -1423,6 +1456,11 @@
+ 			wake_up(&journal->j_wait_transaction_locked);
+ 	}
+ 
++        /* Move callbacks from the handle to the transaction. */
++        spin_lock(&transaction->t_jcb_lock);
++        list_splice(&handle->h_jcb, &transaction->t_jcb);
++        spin_unlock(&transaction->t_jcb_lock);
++
+ 	/*
+ 	 * If the handle is marked SYNC, we need to set another commit
+ 	 * going!  We also want to force a commit if the current
+diff -u -r debian-2.6.26/fs/namespace.c debian-2.6.26_lustre.1.8.2/fs/namespace.c
+--- debian-2.6.26/fs/namespace.c	2009-12-26 09:14:56.000000000 +0100
++++ debian-2.6.26_lustre.1.8.2/fs/namespace.c	2010-02-17 14:43:07.000000000 +0100
+@@ -1660,6 +1660,7 @@
+ 
+ 	return do_add_mount(mnt, nd, mnt_flags, NULL);
+ }
++EXPORT_SYMBOL(set_fs_pwd);
+ 
+ /*
+  * add a mount into a namespace's mount tree
+diff -u -r debian-2.6.26/include/linux/blkdev.h debian-2.6.26_lustre.1.8.2/include/linux/blkdev.h
+--- debian-2.6.26/include/linux/blkdev.h	2009-12-26 09:14:55.000000000 +0100
++++ debian-2.6.26_lustre.1.8.2/include/linux/blkdev.h	2010-02-18 07:44:31.000000000 +0100
+@@ -806,7 +806,7 @@
+ #define MAX_PHYS_SEGMENTS 128
+ #define MAX_HW_SEGMENTS 128
+ #define SAFE_MAX_SECTORS 255
+-#define BLK_DEF_MAX_SECTORS 1024
++#define BLK_DEF_MAX_SECTORS 2048
+ 
+ #define MAX_SEGMENT_SIZE	65536
+ 
+diff -u -r debian-2.6.26/include/linux/dcache.h debian-2.6.26_lustre.1.8.2/include/linux/dcache.h
+--- debian-2.6.26/include/linux/dcache.h	2008-07-13 23:51:29.000000000 +0200
++++ debian-2.6.26_lustre.1.8.2/include/linux/dcache.h	2010-02-18 07:46:08.000000000 +0100
+@@ -173,6 +173,7 @@
+ 
+ #define DCACHE_REFERENCED	0x0008  /* Recently used, don't discard. */
+ #define DCACHE_UNHASHED		0x0010	
++#define DCACHE_LUSTRE_INVALID   0x0040  /* Lustre invalidated */
+ 
+ #define DCACHE_INOTIFY_PARENT_WATCHED	0x0020 /* Parent inode is watched */
+ 
+@@ -250,6 +251,7 @@
+  * This adds the entry to the hash queues.
+  */
+ extern void d_rehash(struct dentry *);
++extern void d_rehash_cond(struct dentry *, int lock);
+ 
+ /**
+  * d_add - add dentry to hash queues
+@@ -285,6 +287,7 @@
+ 
+ /* used for rename() and baskets */
+ extern void d_move(struct dentry *, struct dentry *);
++extern void d_move_locked(struct dentry *, struct dentry *);
+ 
+ /* appendix may either be NULL or be used for transname suffixes */
+ extern struct dentry * d_lookup(struct dentry *, struct qstr *);
+diff -u -r debian-2.6.26/include/linux/fs.h debian-2.6.26_lustre.1.8.2/include/linux/fs.h
+--- debian-2.6.26/include/linux/fs.h	2008-07-13 23:51:29.000000000 +0200
++++ debian-2.6.26_lustre.1.8.2/include/linux/fs.h	2010-02-18 07:57:56.000000000 +0100
+@@ -1832,6 +1832,10 @@
+ extern void submit_bio(int, struct bio *);
+ extern int bdev_read_only(struct block_device *);
+ #endif
++#define HAVE_CLEAR_RDONLY_ON_PUT
++extern void dev_set_rdonly(struct block_device *bdev);
++extern int dev_check_rdonly(struct block_device *bdev);
++extern void dev_clear_rdonly(struct block_device *bdev);
+ extern int set_blocksize(struct block_device *, int);
+ extern int sb_set_blocksize(struct super_block *, int);
+ extern int sb_min_blocksize(struct super_block *, int);
+@@ -1930,6 +1934,7 @@
+ 
+ extern const struct file_operations generic_ro_fops;
+ 
++extern rwlock_t file_systems_lock;
+ #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m))
+ 
+ extern int vfs_readlink(struct dentry *, char __user *, int, const char *);
+diff -u -r debian-2.6.26/include/linux/jbd2.h debian-2.6.26_lustre.1.8.2/include/linux/jbd2.h
+--- debian-2.6.26/include/linux/jbd2.h	2008-07-13 23:51:29.000000000 +0200
++++ debian-2.6.26_lustre.1.8.2/include/linux/jbd2.h	2010-02-18 08:08:30.000000000 +0100
+@@ -379,6 +379,27 @@
+ 	bit_spin_unlock(BH_JournalHead, &bh->b_state);
+ }
+ 
++#define HAVE_JOURNAL_CALLBACK_STATUS
++/**
++ *   struct journal_callback - Base structure for callback information.
++ *   @jcb_list: list information for other callbacks attached to the same handle.
++ *   @jcb_func: Function to call with this callback structure.
++ *
++ *   This struct is a 'seed' structure for a using with your own callback
++ *   structs. If you are using callbacks you must allocate one of these
++ *   or another struct of your own definition which has this struct
++ *   as it's first element and pass it to journal_callback_set().
++ *
++ *   This is used internally by jbd2 to maintain callback information.
++ *
++ *   See journal_callback_set for more information.
++ **/
++struct journal_callback {
++        struct list_head jcb_list;              /* t_jcb_lock */
++        void (*jcb_func)(struct journal_callback *jcb, int error);
++        /* user data goes here */
++};
++
+ struct jbd2_revoke_table_s;
+ 
+ /**
+@@ -387,6 +408,7 @@
+  * @h_transaction: Which compound transaction is this update a part of?
+  * @h_buffer_credits: Number of remaining buffers we are allowed to dirty.
+  * @h_ref: Reference count on this handle
++ * @h_jcb: List of application registered callbacks for this handle.
+  * @h_err: Field for caller's use to track errors through large fs operations
+  * @h_sync: flag for sync-on-close
+  * @h_jdata: flag to force data journaling
+@@ -412,6 +434,13 @@
+ 	/* operations */
+ 	int			h_err;
+ 
++        /*
++         * List of application registered callbacks for this handle. The
++         * function(s) will be called after the transaction that this handle is
++         * part of has been committed to disk. [t_jcb_lock]
++         */
++        struct list_head        h_jcb;
++
+ 	/* Flags [no locking] */
+ 	unsigned int	h_sync:		1;	/* sync-on-close */
+ 	unsigned int	h_jdata:	1;	/* force data journaling */
+@@ -467,6 +496,9 @@
+  *    j_state_lock
+  *    ->j_list_lock			(journal_unmap_buffer)
+  *
++ *    t_handle_lock
++ *    ->t_jcb_lock
++ *
+  */
+ 
+ struct transaction_s
+@@ -613,6 +645,15 @@
+ 	 */
+ 	int t_handle_count;
+ 
++        /*
++         * Protects the callback list
++         */
++        spinlock_t              t_jcb_lock;
++        /*
++         * List of registered callback functions for this transaction.
++         * Called when the transaction is committed. [t_jcb_lock]
++         */
++        struct list_head        t_jcb;
+ };
+ 
+ struct transaction_run_stats_s {
+@@ -1016,6 +1057,9 @@
+ extern int	 jbd2_journal_flush (journal_t *);
+ extern void	 jbd2_journal_lock_updates (journal_t *);
+ extern void	 jbd2_journal_unlock_updates (journal_t *);
++extern void      jbd2_journal_callback_set(handle_t *handle,
++                                      void (*fn)(struct journal_callback *,int),
++                                      struct journal_callback *jcb);
+ 
+ extern journal_t * jbd2_journal_init_dev(struct block_device *bdev,
+ 				struct block_device *fs_dev,
+diff -u -r debian-2.6.26/include/linux/mm.h debian-2.6.26_lustre.1.8.2/include/linux/mm.h
+--- debian-2.6.26/include/linux/mm.h	2009-12-26 09:14:57.000000000 +0100
++++ debian-2.6.26_lustre.1.8.2/include/linux/mm.h	2010-02-18 08:10:11.000000000 +0100
+@@ -564,6 +564,8 @@
+ {
+ 	return __va(page_to_pfn(page) << PAGE_SHIFT);
+ }
++/* truncate.c */
++extern void truncate_complete_page(struct address_space *mapping,struct page *);
+ 
+ #if defined(CONFIG_HIGHMEM) && !defined(WANT_PAGE_VIRTUAL)
+ #define HASHED_PAGE_VIRTUAL
+diff -u -r debian-2.6.26/include/scsi/sd.h debian-2.6.26_lustre.1.8.2/include/scsi/sd.h
+--- debian-2.6.26/include/scsi/sd.h	2008-07-13 23:51:29.000000000 +0200
++++ debian-2.6.26_lustre.1.8.2/include/scsi/sd.h	2010-02-17 14:18:52.000000000 +0100
+@@ -31,6 +31,47 @@
+  */
+ #define SD_BUF_SIZE		512
+ 
++#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
++typedef struct {
++        unsigned long long iostat_size;
++        unsigned long long iostat_count;
++} iostat_counter_t;
++
++#define IOSTAT_NCOUNTERS 16
++typedef struct {
++        iostat_counter_t        iostat_read_histogram[IOSTAT_NCOUNTERS];
++        iostat_counter_t        iostat_write_histogram[IOSTAT_NCOUNTERS];
++        struct timeval          iostat_timeval;
++
++        /* queue depth: how well the pipe is filled up */
++        unsigned long long      iostat_queue_ticks[IOSTAT_NCOUNTERS];
++        unsigned long long      iostat_queue_ticks_sum;
++        unsigned long           iostat_queue_depth;
++        unsigned long           iostat_queue_stamp;
++
++        /* seeks: how linear the traffic is */
++        unsigned long long      iostat_next_sector;
++        unsigned long long      iostat_seek_sectors;
++        unsigned long long      iostat_seeks;
++        unsigned long long      iostat_sectors;
++        unsigned long long      iostat_reqs;
++        unsigned long           iostat_read_reqs;
++        unsigned long           iostat_write_reqs;
++
++        /* process time: how long it takes to process requests */
++        unsigned long           iostat_rtime[IOSTAT_NCOUNTERS];
++        unsigned long           iostat_wtime[IOSTAT_NCOUNTERS];
++
++        /* queue time: how long process spent in elevator's queue */
++        unsigned long           iostat_rtime_in_queue[IOSTAT_NCOUNTERS];
++        unsigned long           iostat_wtime_in_queue[IOSTAT_NCOUNTERS];
++
++        /* must be the last field, as it's used to know size to be memset'ed */
++        spinlock_t              iostat_lock;
++} ____cacheline_aligned_in_smp iostat_stats_t;
++#endif
++
++
+ struct scsi_disk {
+ 	struct scsi_driver *driver;	/* always &sd_template */
+ 	struct scsi_device *device;
+@@ -45,6 +86,9 @@
+ 	unsigned	WCE : 1;	/* state of disk WCE bit */
+ 	unsigned	RCD : 1;	/* state of disk RCD bit, unused */
+ 	unsigned	DPOFUA : 1;	/* state of disk DPOFUA bit */
++#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
++        iostat_stats_t  *stats;         /* scsi disk statistics */
++#endif
+ };
+ #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev)
+ 
+diff -u -r debian-2.6.26/kernel/sched.c debian-2.6.26_lustre.1.8.2/kernel/sched.c
+--- debian-2.6.26/kernel/sched.c	2009-12-26 09:14:56.000000000 +0100
++++ debian-2.6.26_lustre.1.8.2/kernel/sched.c	2010-02-18 08:11:02.000000000 +0100
+@@ -5477,6 +5477,7 @@
+ 
+ 	show_stack(p, NULL);
+ }
++EXPORT_SYMBOL(sched_show_task);
+ 
+ void show_state_filter(unsigned long state_filter)
+ {
+diff -u -r debian-2.6.26/mm/truncate.c debian-2.6.26_lustre.1.8.2/mm/truncate.c
+--- debian-2.6.26/mm/truncate.c	2008-07-13 23:51:29.000000000 +0200
++++ debian-2.6.26_lustre.1.8.2/mm/truncate.c	2010-02-18 08:12:58.000000000 +0100
+@@ -92,7 +92,7 @@
+  * its lock, b) when a concurrent invalidate_mapping_pages got there first and
+  * c) when tmpfs swizzles a page between a tmpfs inode and swapper_space.
+  */
+-static void
++void
+ truncate_complete_page(struct address_space *mapping, struct page *page)
+ {
+ 	if (page->mapping != mapping)
+@@ -108,6 +108,7 @@
+ 	ClearPageMappedToDisk(page);
+ 	page_cache_release(page);	/* pagecache ref */
+ }
++EXPORT_SYMBOL_GPL(truncate_complete_page);
+ 
+ /*
+  * This is for invalidate_mapping_pages().  That function can be called at
+diff -u -r debian-2.6.26/security/security.c debian-2.6.26_lustre.1.8.2/security/security.c
+--- debian-2.6.26/security/security.c	2009-12-26 09:14:57.000000000 +0100
++++ debian-2.6.26_lustre.1.8.2/security/security.c	2010-02-18 08:13:38.000000000 +0100
+@@ -406,6 +406,7 @@
+ 		return 0;
+ 	return security_ops->inode_unlink(dir, dentry);
+ }
++EXPORT_SYMBOL(security_inode_unlink);
+ 
+ int security_inode_symlink(struct inode *dir, struct dentry *dentry,
+ 			    const char *old_name)
--- lustre-1.8.3.orig/lustre/kernel_patches/patches/quota-Increase-size-of-variables-for-limits-and-ino.patch
+++ lustre-1.8.3/lustre/kernel_patches/patches/quota-Increase-size-of-variables-for-limits-and-ino.patch
@@ -0,0 +1,359 @@
+From: Jan Kara <jack@suse.cz>
+References: fate#302681
+Subject: [PATCH 02/28] quota: Increase size of variables for limits and inode usage
+Patch-mainline: 2.6.29?
+
+So far quota was fine with quota block limits and inode limits/numbers in
+a 32-bit type. Now with rapid increase in storage sizes there are coming
+requests to be able to handle quota limits above 4TB / more that 2^32 inodes.
+So bump up sizes of types in mem_dqblk structure to 64-bits to be able to
+handle this. Also update inode allocation / checking functions to use qsize_t
+and make global structure keep quota limits in bytes so that things are
+consistent.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+---
+ fs/dquot.c               |   50 ++++++++++++++++++++++++++-------------------
+ fs/quota_v1.c            |   25 +++++++++++++++++-----
+ fs/quota_v2.c            |   21 +++++++++++++++---
+ include/linux/quota.h    |   28 +++++++++++--------------
+ include/linux/quotaops.h |    4 +-
+ 5 files changed, 79 insertions(+), 49 deletions(-)
+
+diff --git a/fs/dquot.c b/fs/dquot.c
+index e1dac3e..758bf4a 100644
+--- a/fs/dquot.c
++++ b/fs/dquot.c
+@@ -833,7 +833,7 @@ static void drop_dquot_ref(struct super_block *sb, int type)
+ 	}
+ }
+ 
+-static inline void dquot_incr_inodes(struct dquot *dquot, unsigned long number)
++static inline void dquot_incr_inodes(struct dquot *dquot, qsize_t number)
+ {
+ 	dquot->dq_dqb.dqb_curinodes += number;
+ }
+@@ -843,7 +843,7 @@ static inline void dquot_incr_space(struct dquot *dquot, qsize_t number)
+ 	dquot->dq_dqb.dqb_curspace += number;
+ }
+ 
+-static inline void dquot_decr_inodes(struct dquot *dquot, unsigned long number)
++static inline void dquot_decr_inodes(struct dquot *dquot, qsize_t number)
+ {
+ 	if (dquot->dq_dqb.dqb_curinodes > number)
+ 		dquot->dq_dqb.dqb_curinodes -= number;
+@@ -860,7 +860,7 @@ static inline void dquot_decr_space(struct dquot *dquot, qsize_t number)
+ 		dquot->dq_dqb.dqb_curspace -= number;
+ 	else
+ 		dquot->dq_dqb.dqb_curspace = 0;
+-	if (toqb(dquot->dq_dqb.dqb_curspace) <= dquot->dq_dqb.dqb_bsoftlimit)
++	if (dquot->dq_dqb.dqb_curspace <= dquot->dq_dqb.dqb_bsoftlimit)
+ 		dquot->dq_dqb.dqb_btime = (time_t) 0;
+ 	clear_bit(DQ_BLKS_B, &dquot->dq_flags);
+ }
+@@ -1038,7 +1038,7 @@ static inline char ignore_hardlimit(struct dquot *dquot)
+ }
+ 
+ /* needs dq_data_lock */
+-static int check_idq(struct dquot *dquot, ulong inodes, char *warntype)
++static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype)
+ {
+ 	*warntype = QUOTA_NL_NOWARN;
+ 	if (inodes <= 0 || test_bit(DQ_FAKE_B, &dquot->dq_flags))
+@@ -1077,7 +1077,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war
+ 		return QUOTA_OK;
+ 
+ 	if (dquot->dq_dqb.dqb_bhardlimit &&
+-	   toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bhardlimit &&
++	    dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bhardlimit &&
+             !ignore_hardlimit(dquot)) {
+ 		if (!prealloc)
+ 			*warntype = QUOTA_NL_BHARDWARN;
+@@ -1085,7 +1085,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war
+ 	}
+ 
+ 	if (dquot->dq_dqb.dqb_bsoftlimit &&
+-	   toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bsoftlimit &&
++	    dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bsoftlimit &&
+ 	    dquot->dq_dqb.dqb_btime && get_seconds() >= dquot->dq_dqb.dqb_btime &&
+             !ignore_hardlimit(dquot)) {
+ 		if (!prealloc)
+@@ -1094,7 +1094,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war
+ 	}
+ 
+ 	if (dquot->dq_dqb.dqb_bsoftlimit &&
+-	   toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bsoftlimit &&
++	    dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bsoftlimit &&
+ 	    dquot->dq_dqb.dqb_btime == 0) {
+ 		if (!prealloc) {
+ 			*warntype = QUOTA_NL_BSOFTWARN;
+@@ -1111,7 +1111,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war
+ 	return QUOTA_OK;
+ }
+ 
+-static int info_idq_free(struct dquot *dquot, ulong inodes)
++static int info_idq_free(struct dquot *dquot, qsize_t inodes)
+ {
+ 	if (test_bit(DQ_FAKE_B, &dquot->dq_flags) ||
+ 	    dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit)
+@@ -1128,15 +1128,13 @@ static int info_idq_free(struct dquot *dquot, ulong inodes)
+ static int info_bdq_free(struct dquot *dquot, qsize_t space)
+ {
+ 	if (test_bit(DQ_FAKE_B, &dquot->dq_flags) ||
+-	    toqb(dquot->dq_dqb.dqb_curspace) <= dquot->dq_dqb.dqb_bsoftlimit)
++	    dquot->dq_dqb.dqb_curspace <= dquot->dq_dqb.dqb_bsoftlimit)
+ 		return QUOTA_NL_NOWARN;
+ 
+-	if (toqb(dquot->dq_dqb.dqb_curspace - space) <=
+-	    dquot->dq_dqb.dqb_bsoftlimit)
++	if (dquot->dq_dqb.dqb_curspace - space <= dquot->dq_dqb.dqb_bsoftlimit)
+ 		return QUOTA_NL_BSOFTBELOW;
+-	if (toqb(dquot->dq_dqb.dqb_curspace) >= dquot->dq_dqb.dqb_bhardlimit &&
+-	    toqb(dquot->dq_dqb.dqb_curspace - space) <
+-						dquot->dq_dqb.dqb_bhardlimit)
++	if (dquot->dq_dqb.dqb_curspace >= dquot->dq_dqb.dqb_bhardlimit &&
++	    dquot->dq_dqb.dqb_curspace - space < dquot->dq_dqb.dqb_bhardlimit)
+ 		return QUOTA_NL_BHARDBELOW;
+ 	return QUOTA_NL_NOWARN;
+ }
+@@ -1279,7 +1277,7 @@ warn_put_all:
+ /*
+  * This operation can block, but only after everything is updated
+  */
+-int dquot_alloc_inode(const struct inode *inode, unsigned long number)
++int dquot_alloc_inode(const struct inode *inode, qsize_t number)
+ {
+ 	int cnt, ret = NO_QUOTA;
+ 	char warntype[MAXQUOTAS];
+@@ -1364,7 +1362,7 @@ out_sub:
+ /*
+  * This operation can block, but only after everything is updated
+  */
+-int dquot_free_inode(const struct inode *inode, unsigned long number)
++int dquot_free_inode(const struct inode *inode, qsize_t number)
+ {
+ 	unsigned int cnt;
+ 	char warntype[MAXQUOTAS];
+@@ -1881,14 +1879,24 @@ int vfs_dq_quota_on_remount(struct super_block *sb)
+ 	return ret;
+ }
+ 
++static inline qsize_t qbtos(qsize_t blocks)
++{
++	return blocks << QIF_DQBLKSIZE_BITS;
++}
++
++static inline qsize_t stoqb(qsize_t space)
++{
++	return (space + QIF_DQBLKSIZE - 1) >> QIF_DQBLKSIZE_BITS;
++}
++
+ /* Generic routine for getting common part of quota structure */
+ static void do_get_dqblk(struct dquot *dquot, struct if_dqblk *di)
+ {
+ 	struct mem_dqblk *dm = &dquot->dq_dqb;
+ 
+ 	spin_lock(&dq_data_lock);
+-	di->dqb_bhardlimit = dm->dqb_bhardlimit;
+-	di->dqb_bsoftlimit = dm->dqb_bsoftlimit;
++	di->dqb_bhardlimit = stoqb(dm->dqb_bhardlimit);
++	di->dqb_bsoftlimit = stoqb(dm->dqb_bsoftlimit);
+ 	di->dqb_curspace = dm->dqb_curspace;
+ 	di->dqb_ihardlimit = dm->dqb_ihardlimit;
+ 	di->dqb_isoftlimit = dm->dqb_isoftlimit;
+@@ -1935,8 +1943,8 @@ static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
+ 		check_blim = 1;
+ 	}
+ 	if (di->dqb_valid & QIF_BLIMITS) {
+-		dm->dqb_bsoftlimit = di->dqb_bsoftlimit;
+-		dm->dqb_bhardlimit = di->dqb_bhardlimit;
++		dm->dqb_bsoftlimit = qbtos(di->dqb_bsoftlimit);
++		dm->dqb_bhardlimit = qbtos(di->dqb_bhardlimit);
+ 		check_blim = 1;
+ 	}
+ 	if (di->dqb_valid & QIF_INODES) {
+@@ -1954,7 +1962,7 @@ static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
+ 		dm->dqb_itime = di->dqb_itime;
+ 
+ 	if (check_blim) {
+-		if (!dm->dqb_bsoftlimit || toqb(dm->dqb_curspace) < dm->dqb_bsoftlimit) {
++		if (!dm->dqb_bsoftlimit || dm->dqb_curspace < dm->dqb_bsoftlimit) {
+ 			dm->dqb_btime = 0;
+ 			clear_bit(DQ_BLKS_B, &dquot->dq_flags);
+ 		}
+diff --git a/fs/quota_v1.c b/fs/quota_v1.c
+index 5ae15b1..3e078ee 100644
+--- a/fs/quota_v1.c
++++ b/fs/quota_v1.c
+@@ -14,14 +14,27 @@ MODULE_AUTHOR("Jan Kara");
+ MODULE_DESCRIPTION("Old quota format support");
+ MODULE_LICENSE("GPL");
+ 
++#define QUOTABLOCK_BITS 10
++#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS)
++
++static inline qsize_t v1_stoqb(qsize_t space)
++{
++	return (space + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS;
++}
++
++static inline qsize_t v1_qbtos(qsize_t blocks)
++{
++	return blocks << QUOTABLOCK_BITS;
++}
++
+ static void v1_disk2mem_dqblk(struct mem_dqblk *m, struct v1_disk_dqblk *d)
+ {
+ 	m->dqb_ihardlimit = d->dqb_ihardlimit;
+ 	m->dqb_isoftlimit = d->dqb_isoftlimit;
+ 	m->dqb_curinodes = d->dqb_curinodes;
+-	m->dqb_bhardlimit = d->dqb_bhardlimit;
+-	m->dqb_bsoftlimit = d->dqb_bsoftlimit;
+-	m->dqb_curspace = ((qsize_t)d->dqb_curblocks) << QUOTABLOCK_BITS;
++	m->dqb_bhardlimit = v1_qbtos(d->dqb_bhardlimit);
++	m->dqb_bsoftlimit = v1_qbtos(d->dqb_bsoftlimit);
++	m->dqb_curspace = v1_qbtos(d->dqb_curblocks);
+ 	m->dqb_itime = d->dqb_itime;
+ 	m->dqb_btime = d->dqb_btime;
+ }
+@@ -31,9 +44,9 @@ static void v1_mem2disk_dqblk(struct v1_disk_dqblk *d, struct mem_dqblk *m)
+ 	d->dqb_ihardlimit = m->dqb_ihardlimit;
+ 	d->dqb_isoftlimit = m->dqb_isoftlimit;
+ 	d->dqb_curinodes = m->dqb_curinodes;
+-	d->dqb_bhardlimit = m->dqb_bhardlimit;
+-	d->dqb_bsoftlimit = m->dqb_bsoftlimit;
+-	d->dqb_curblocks = toqb(m->dqb_curspace);
++	d->dqb_bhardlimit = v1_stoqb(m->dqb_bhardlimit);
++	d->dqb_bsoftlimit = v1_stoqb(m->dqb_bsoftlimit);
++	d->dqb_curblocks = v1_stoqb(m->dqb_curspace);
+ 	d->dqb_itime = m->dqb_itime;
+ 	d->dqb_btime = m->dqb_btime;
+ }
+diff --git a/fs/quota_v2.c b/fs/quota_v2.c
+index b53827d..51c4717 100644
+--- a/fs/quota_v2.c
++++ b/fs/quota_v2.c
+@@ -26,6 +26,19 @@ 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)))
+ 
++#define QUOTABLOCK_BITS 10
++#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS)
++
++static inline qsize_t v2_stoqb(qsize_t space)
++{
++	return (space + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS;
++}
++
++static inline qsize_t v2_qbtos(qsize_t blocks)
++{
++	return blocks << QUOTABLOCK_BITS;
++}
++
+ /* Check whether given file is really vfsv0 quotafile */
+ static int v2_check_quota_file(struct super_block *sb, int type)
+ {
+@@ -104,8 +117,8 @@ static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d)
+ 	m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit);
+ 	m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes);
+ 	m->dqb_itime = le64_to_cpu(d->dqb_itime);
+-	m->dqb_bhardlimit = le32_to_cpu(d->dqb_bhardlimit);
+-	m->dqb_bsoftlimit = le32_to_cpu(d->dqb_bsoftlimit);
++	m->dqb_bhardlimit = v2_qbtos(le32_to_cpu(d->dqb_bhardlimit));
++	m->dqb_bsoftlimit = v2_qbtos(le32_to_cpu(d->dqb_bsoftlimit));
+ 	m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
+ 	m->dqb_btime = le64_to_cpu(d->dqb_btime);
+ }
+@@ -116,8 +129,8 @@ static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id)
+ 	d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
+ 	d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes);
+ 	d->dqb_itime = cpu_to_le64(m->dqb_itime);
+-	d->dqb_bhardlimit = cpu_to_le32(m->dqb_bhardlimit);
+-	d->dqb_bsoftlimit = cpu_to_le32(m->dqb_bsoftlimit);
++	d->dqb_bhardlimit = cpu_to_le32(v2_qbtos(m->dqb_bhardlimit));
++	d->dqb_bsoftlimit = cpu_to_le32(v2_qbtos(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);
+diff --git a/include/linux/quota.h b/include/linux/quota.h
+index eeae7a9..5167786 100644
+--- a/include/linux/quota.h
++++ b/include/linux/quota.h
+@@ -41,15 +41,6 @@
+ #define __DQUOT_VERSION__	"dquot_6.5.1"
+ #define __DQUOT_NUM_VERSION__	6*10000+5*100+1
+ 
+-/* Size of blocks in which are counted size limits */
+-#define QUOTABLOCK_BITS 10
+-#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS)
+-
+-/* Conversion routines from and to quota blocks */
+-#define qb2kb(x) ((x) << (QUOTABLOCK_BITS-10))
+-#define kb2qb(x) ((x) >> (QUOTABLOCK_BITS-10))
+-#define toqb(x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS)
+-
+ #define MAXQUOTAS 2
+ #define USRQUOTA  0		/* element used for user quotas */
+ #define GRPQUOTA  1		/* element used for group quotas */
+@@ -82,6 +73,11 @@
+ #define Q_GETQUOTA 0x800007	/* get user quota structure */
+ #define Q_SETQUOTA 0x800008	/* set user quota structure */
+ 
++/* Size of block in which space limits are passed through the quota
++ * interface */
++#define QIF_DQBLKSIZE_BITS 10
++#define QIF_DQBLKSIZE (1 << QIF_DQBLKSIZE_BITS)
++
+ /*
+  * Quota structure used for communication with userspace via quotactl
+  * Following flags are used to specify which fields are valid
+@@ -189,12 +185,12 @@ extern spinlock_t dq_data_lock;
+  * Data for one user/group kept in memory
+  */
+ struct mem_dqblk {
+-	__u32 dqb_bhardlimit;	/* absolute limit on disk blks alloc */
+-	__u32 dqb_bsoftlimit;	/* preferred limit on disk blks */
++	qsize_t dqb_bhardlimit;	/* absolute limit on disk blks alloc */
++	qsize_t dqb_bsoftlimit;	/* preferred limit on disk blks */
+ 	qsize_t dqb_curspace;	/* current used space */
+-	__u32 dqb_ihardlimit;	/* absolute limit on allocated inodes */
+-	__u32 dqb_isoftlimit;	/* preferred inode limit */
+-	__u32 dqb_curinodes;	/* current # allocated inodes */
++	qsize_t dqb_ihardlimit;	/* absolute limit on allocated inodes */
++	qsize_t dqb_isoftlimit;	/* preferred inode limit */
++	qsize_t dqb_curinodes;	/* current # allocated inodes */
+ 	time_t dqb_btime;	/* time limit for excessive disk use */
+ 	time_t dqb_itime;	/* time limit for excessive inode use */
+ };
+@@ -289,9 +285,9 @@ struct dquot_operations {
+ 	int (*initialize) (struct inode *, int);
+ 	int (*drop) (struct inode *);
+ 	int (*alloc_space) (struct inode *, qsize_t, int);
+-	int (*alloc_inode) (const struct inode *, unsigned long);
++	int (*alloc_inode) (const struct inode *, qsize_t);
+ 	int (*free_space) (struct inode *, qsize_t);
+-	int (*free_inode) (const struct inode *, unsigned long);
++	int (*free_inode) (const struct inode *, qsize_t);
+ 	int (*transfer) (struct inode *, struct iattr *);
+ 	int (*write_dquot) (struct dquot *);		/* Ordinary dquot write */
+ 	struct dquot *(*alloc_dquot)(struct super_block *, int);	/* Allocate memory for new dquot (can be NULL if no special entries dquot are needed) */
+diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
+index ca6b9b5..9e7bc4b 100644
+--- a/include/linux/quotaops.h
++++ b/include/linux/quotaops.h
+@@ -29,10 +29,10 @@ int dquot_initialize(struct inode *inode, int type);
+ int dquot_drop(struct inode *inode);
+ 
+ int dquot_alloc_space(struct inode *inode, qsize_t number, int prealloc);
+-int dquot_alloc_inode(const struct inode *inode, unsigned long number);
++int dquot_alloc_inode(const struct inode *inode, qsize_t number);
+ 
+ int dquot_free_space(struct inode *inode, qsize_t number);
+-int dquot_free_inode(const struct inode *inode, unsigned long number);
++int dquot_free_inode(const struct inode *inode, qsize_t number);
+ 
+ int dquot_transfer(struct inode *inode, struct iattr *iattr);
+ int dquot_commit(struct dquot *dquot);
+-- 
+1.5.2.4
+
--- lustre-1.8.3.orig/lustre/kernel_patches/patches/jbd2-jcberr-2.6.26-vanilla.patch
+++ lustre-1.8.3/lustre/kernel_patches/patches/jbd2-jcberr-2.6.26-vanilla.patch
@@ -0,0 +1,211 @@
+Index: linux-source-2.6.26/include/linux/jbd2.h
+===================================================================
+--- linux-source-2.6.26.orig/include/linux/jbd2.h	2008-07-13 23:51:29.000000000 +0200
++++ linux-source-2.6.26/include/linux/jbd2.h	2009-10-09 13:42:21.000000000 +0200
+@@ -379,6 +379,27 @@
+ 	bit_spin_unlock(BH_JournalHead, &bh->b_state);
+ }
+ 
++#define HAVE_JOURNAL_CALLBACK_STATUS
++/**
++ *   struct journal_callback - Base structure for callback information.
++ *   @jcb_list: list information for other callbacks attached to the same handle.
++ *   @jcb_func: Function to call with this callback structure.
++ *
++ *   This struct is a 'seed' structure for a using with your own callback
++ *   structs. If you are using callbacks you must allocate one of these
++ *   or another struct of your own definition which has this struct
++ *   as it's first element and pass it to journal_callback_set().
++ *
++ *   This is used internally by jbd2 to maintain callback information.
++ *
++ *   See journal_callback_set for more information.
++ **/
++struct journal_callback {
++	struct list_head jcb_list;		/* t_jcb_lock */
++	void (*jcb_func)(struct journal_callback *jcb, int error);
++	/* user data goes here */
++};
++
+ struct jbd2_revoke_table_s;
+ 
+ /**
+@@ -387,6 +408,7 @@
+  * @h_transaction: Which compound transaction is this update a part of?
+  * @h_buffer_credits: Number of remaining buffers we are allowed to dirty.
+  * @h_ref: Reference count on this handle
++ * @h_jcb: List of application registered callbacks for this handle.
+  * @h_err: Field for caller's use to track errors through large fs operations
+  * @h_sync: flag for sync-on-close
+  * @h_jdata: flag to force data journaling
+@@ -412,6 +434,13 @@
+ 	/* operations */
+ 	int			h_err;
+ 
++	/*
++	 * List of application registered callbacks for this handle. The
++	 * function(s) will be called after the transaction that this handle is
++	 * part of has been committed to disk. [t_jcb_lock]
++	 */
++	struct list_head	h_jcb;
++
+ 	/* Flags [no locking] */
+ 	unsigned int	h_sync:		1;	/* sync-on-close */
+ 	unsigned int	h_jdata:	1;	/* force data journaling */
+@@ -467,6 +496,8 @@
+  *    j_state_lock
+  *    ->j_list_lock			(journal_unmap_buffer)
+  *
++ *    t_handle_lock
++ *    ->t_jcb_lock
+  */
+ 
+ struct transaction_s
+@@ -613,6 +644,15 @@
+ 	 */
+ 	int t_handle_count;
+ 
++	/*
++	 * Protects the callback list
++	 */
++	spinlock_t		t_jcb_lock;
++	/*
++	 * List of registered callback functions for this transaction.
++	 * Called when the transaction is committed. [t_jcb_lock]
++	 */
++	struct list_head	t_jcb;
+ };
+ 
+ struct transaction_run_stats_s {
+@@ -1016,6 +1056,9 @@
+ extern int	 jbd2_journal_flush (journal_t *);
+ extern void	 jbd2_journal_lock_updates (journal_t *);
+ extern void	 jbd2_journal_unlock_updates (journal_t *);
++extern void	 jbd2_journal_callback_set(handle_t *handle,
++                                      void (*fn)(struct journal_callback *,int),
++                                      struct journal_callback *jcb);
+ 
+ extern journal_t * jbd2_journal_init_dev(struct block_device *bdev,
+ 				struct block_device *fs_dev,
+Index: linux-source-2.6.26/fs/jbd2/checkpoint.c
+===================================================================
+--- linux-source-2.6.26.orig/fs/jbd2/checkpoint.c	2008-07-13 23:51:29.000000000 +0200
++++ linux-source-2.6.26/fs/jbd2/checkpoint.c	2009-10-09 13:42:21.000000000 +0200
+@@ -696,6 +696,7 @@
+ 	J_ASSERT(transaction->t_checkpoint_list == NULL);
+ 	J_ASSERT(transaction->t_checkpoint_io_list == NULL);
+ 	J_ASSERT(transaction->t_updates == 0);
++	J_ASSERT(list_empty(&transaction->t_jcb));
+ 	J_ASSERT(journal->j_committing_transaction != transaction);
+ 	J_ASSERT(journal->j_running_transaction != transaction);
+ 
+Index: linux-source-2.6.26/fs/jbd2/commit.c
+===================================================================
+--- linux-source-2.6.26.orig/fs/jbd2/commit.c	2008-07-13 23:51:29.000000000 +0200
++++ linux-source-2.6.26/fs/jbd2/commit.c	2009-10-09 13:42:21.000000000 +0200
+@@ -854,6 +854,30 @@
+ 		/* AKPM: bforget here */
+ 	}
+ 
++	/*
++	 * Call any callbacks that had been registered for handles in this
++	 * transaction.  It is up to the callback to free any allocated
++	 * memory.
++	 *
++	 * The spinlocking (t_jcb_lock) here is surely unnecessary...
++	 */
++	spin_lock(&commit_transaction->t_jcb_lock);
++	if (!list_empty(&commit_transaction->t_jcb)) {
++		struct list_head *p, *n;
++		int error = is_journal_aborted(journal);
++
++		list_for_each_safe(p, n, &commit_transaction->t_jcb) {
++			struct journal_callback *jcb;
++
++			jcb = list_entry(p, struct journal_callback, jcb_list);
++			list_del(p);
++			spin_unlock(&commit_transaction->t_jcb_lock);
++			jcb->jcb_func(jcb, error);
++			spin_lock(&commit_transaction->t_jcb_lock);
++		}
++	}
++	spin_unlock(&commit_transaction->t_jcb_lock);
++
+ 	jbd_debug(3, "JBD: commit phase 6\n");
+ 
+ 	if (!JBD2_HAS_INCOMPAT_FEATURE(journal,
+Index: linux-source-2.6.26/fs/jbd2/journal.c
+===================================================================
+--- linux-source-2.6.26.orig/fs/jbd2/journal.c	2009-10-09 13:39:04.000000000 +0200
++++ linux-source-2.6.26/fs/jbd2/journal.c	2009-10-09 13:43:03.000000000 +0200
+@@ -82,6 +82,9 @@
+ EXPORT_SYMBOL(jbd2_journal_invalidatepage);
+ EXPORT_SYMBOL(jbd2_journal_try_to_free_buffers);
+ EXPORT_SYMBOL(jbd2_journal_force_commit);
++EXPORT_SYMBOL(jbd2_journal_callback_set);
++EXPORT_SYMBOL(jbd2_journal_bmap);
++
+ 
+ static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *);
+ static void __journal_abort_soft (journal_t *journal, int errno);
+Index: linux-source-2.6.26/fs/jbd2/transaction.c
+===================================================================
+--- linux-source-2.6.26.orig/fs/jbd2/transaction.c	2008-07-13 23:51:29.000000000 +0200
++++ linux-source-2.6.26/fs/jbd2/transaction.c	2009-10-09 13:42:21.000000000 +0200
+@@ -252,6 +252,7 @@
+ 	memset(handle, 0, sizeof(*handle));
+ 	handle->h_buffer_credits = nblocks;
+ 	handle->h_ref = 1;
++	INIT_LIST_HEAD(&handle->h_jcb);
+ 
+ 	lockdep_init_map(&handle->h_lockdep_map, "jbd2_handle",
+ 						&jbd2_handle_key, 0);
+@@ -1350,6 +1351,36 @@
+ }
+ 
+ /**
++ * void jbd2_journal_callback_set() -  Register a callback function for this handle.
++ * @handle: handle to attach the callback to.
++ * @func: function to callback.
++ * @jcb:  structure with additional information required by func() , and
++ *	some space for jbd2 internal information.
++ *
++ * The function will be
++ * called when the transaction that this handle is part of has been
++ * committed to disk with the original callback data struct and the
++ * error status of the journal as parameters.  There is no guarantee of
++ * ordering between handles within a single transaction, nor between
++ * callbacks registered on the same handle.
++ *
++ * The caller is responsible for allocating the journal_callback struct.
++ * This is to allow the caller to add as much extra data to the callback
++ * as needed, but reduce the overhead of multiple allocations.  The caller
++ * allocated struct must start with a struct journal_callback at offset 0,
++ * and has the caller-specific data afterwards.
++ */
++void jbd2_journal_callback_set(handle_t *handle,
++		      void (*func)(struct journal_callback *jcb, int error),
++		      struct journal_callback *jcb)
++{
++	spin_lock(&handle->h_transaction->t_jcb_lock);
++	list_add_tail(&jcb->jcb_list, &handle->h_jcb);
++	spin_unlock(&handle->h_transaction->t_jcb_lock);
++	jcb->jcb_func = func;
++}
++
++/**
+  * int jbd2_journal_stop() - complete a transaction
+  * @handle: tranaction to complete.
+  *
+@@ -1423,6 +1454,11 @@
+ 			wake_up(&journal->j_wait_transaction_locked);
+ 	}
+ 
++	/* Move callbacks from the handle to the transaction. */
++	spin_lock(&transaction->t_jcb_lock);
++	list_splice(&handle->h_jcb, &transaction->t_jcb);
++	spin_unlock(&transaction->t_jcb_lock);
++
+ 	/*
+ 	 * If the handle is marked SYNC, we need to set another commit
+ 	 * going!  We also want to force a commit if the current
--- lustre-1.8.3.orig/lustre/kernel_patches/series/2.6.26-vanilla.series
+++ lustre-1.8.3/lustre/kernel_patches/series/2.6.26-vanilla.series
@@ -0,0 +1,2 @@
+lustre_version.patch
+debian-2.6.26.diff 
--- lustre-1.8.3.orig/lustre/kernel_patches/series/2.6.27-vanilla.series
+++ lustre-1.8.3/lustre/kernel_patches/series/2.6.27-vanilla.series
@@ -0,0 +1,15 @@
+lustre_version.patch
+vfs_races-2.6.22-vanilla.patch
+iopen-misc-2.6.22-vanilla.patch
+export-truncate-2.6.18-vanilla.patch 
+export_symbols-2.6.22-vanilla.patch 
+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-2.6.27-vanilla.patch
+quota-Split-off-quota-tree-handling-into-a-separate.patch
+quota-Increase-size-of-variables-for-limits-and-ino.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
