Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 956

kernel-2.6.18-194.11.1.el5.src.rpm

From: Eric Sandeen <sandeen@redhat.com>
Date: Wed, 25 Mar 2009 15:54:52 -0500
Subject: [fs] xfs: backport to rhel5.4 kernel
Message-id: 49CA9A1C.5010907@redhat.com
O-Subject: [PATCH 7/10] backport xfs to rhel5.4 kernel
Bugzilla: 470845
RH-Acked-by: Josef Bacik <josef@redhat.com>

Majority of the backporting bits to make the previous patch
build & run (modulo aops update patch, next).

I can point reviewers to a much more finegrained quilt series
that this patch came from, if need be.

diff --git a/fs/xfs/Kconfig b/fs/xfs/Kconfig
index 3f53dd1..cbe1af0 100644
--- a/fs/xfs/Kconfig
+++ b/fs/xfs/Kconfig
@@ -1,6 +1,5 @@
 config XFS_FS
 	tristate "XFS filesystem support"
-	depends on BLOCK
 	help
 	  XFS is a high performance journaling filesystem which originated
 	  on the SGI IRIX platform.  It is completely multi-threaded, can
diff --git a/fs/xfs/linux-2.6/kmem.c b/fs/xfs/linux-2.6/kmem.c
index 1cd3b55..9afb573 100644
--- a/fs/xfs/linux-2.6/kmem.c
+++ b/fs/xfs/linux-2.6/kmem.c
@@ -53,7 +53,7 @@ kmem_alloc(size_t size, unsigned int __nocast flags)
 			printk(KERN_ERR "XFS: possible memory allocation "
 					"deadlock in %s (mode:0x%x)\n",
 					__func__, lflags);
-		congestion_wait(WRITE, HZ/50);
+		blk_congestion_wait(WRITE, HZ/50);
 	} while (1);
 }
 
@@ -95,7 +95,7 @@ kmem_free(const void *ptr)
 	if (!is_vmalloc_addr(ptr)) {
 		kfree(ptr);
 	} else {
-		vfree(ptr);
+		vfree((void *)ptr);
 	}
 }
 
@@ -130,7 +130,7 @@ kmem_zone_alloc(kmem_zone_t *zone, unsigned int __nocast flags)
 			printk(KERN_ERR "XFS: possible memory allocation "
 					"deadlock in %s (mode:0x%x)\n",
 					__func__, lflags);
-		congestion_wait(WRITE, HZ/50);
+		blk_congestion_wait(WRITE, HZ/50);
 	} while (1);
 }
 
diff --git a/fs/xfs/linux-2.6/kmem.h b/fs/xfs/linux-2.6/kmem.h
index af6843c..3ccf8e3 100644
--- a/fs/xfs/linux-2.6/kmem.h
+++ b/fs/xfs/linux-2.6/kmem.h
@@ -74,14 +74,14 @@ extern void  kmem_free(const void *);
 static inline kmem_zone_t *
 kmem_zone_init(int size, char *zone_name)
 {
-	return kmem_cache_create(zone_name, size, 0, 0, NULL);
+	return kmem_cache_create(zone_name, size, 0, 0, NULL, NULL);
 }
 
 static inline kmem_zone_t *
 kmem_zone_init_flags(int size, char *zone_name, unsigned long flags,
-		     void (*construct)(void *))
+		     void (*construct)(void *, kmem_zone_t *, unsigned long))
 {
-	return kmem_cache_create(zone_name, size, 0, flags, construct);
+	return kmem_cache_create(zone_name, size, 0, flags, construct, NULL);
 }
 
 static inline void
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index a44d68e..e79d83c 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -202,10 +202,9 @@ xfs_setfilesize(
  */
 STATIC void
 xfs_end_bio_delalloc(
-	struct work_struct	*work)
+	void			*data)
 {
-	xfs_ioend_t		*ioend =
-		container_of(work, xfs_ioend_t, io_work);
+	xfs_ioend_t		*ioend = data;
 
 	xfs_setfilesize(ioend);
 	xfs_destroy_ioend(ioend);
@@ -216,10 +215,9 @@ xfs_end_bio_delalloc(
  */
 STATIC void
 xfs_end_bio_written(
-	struct work_struct	*work)
+	void			*data)
 {
-	xfs_ioend_t		*ioend =
-		container_of(work, xfs_ioend_t, io_work);
+	xfs_ioend_t		*ioend = data;
 
 	xfs_setfilesize(ioend);
 	xfs_destroy_ioend(ioend);
@@ -233,10 +231,9 @@ xfs_end_bio_written(
  */
 STATIC void
 xfs_end_bio_unwritten(
-	struct work_struct	*work)
+	void			*data)
 {
-	xfs_ioend_t		*ioend =
-		container_of(work, xfs_ioend_t, io_work);
+	xfs_ioend_t		*ioend = data;
 	struct xfs_inode	*ip = XFS_I(ioend->io_inode);
 	xfs_off_t		offset = ioend->io_offset;
 	size_t			size = ioend->io_size;
@@ -258,10 +255,9 @@ xfs_end_bio_unwritten(
  */
 STATIC void
 xfs_end_bio_read(
-	struct work_struct	*work)
+	void			*data)
 {
-	xfs_ioend_t		*ioend =
-		container_of(work, xfs_ioend_t, io_work);
+	xfs_ioend_t		*ioend = data;
 
 	xfs_destroy_ioend(ioend);
 }
@@ -298,13 +294,13 @@ xfs_alloc_ioend(
 	ioend->io_size = 0;
 
 	if (type == IOMAP_UNWRITTEN)
-		INIT_WORK(&ioend->io_work, xfs_end_bio_unwritten);
+		INIT_WORK(&ioend->io_work, xfs_end_bio_unwritten, ioend);
 	else if (type == IOMAP_DELAY)
-		INIT_WORK(&ioend->io_work, xfs_end_bio_delalloc);
+		INIT_WORK(&ioend->io_work, xfs_end_bio_delalloc, ioend);
 	else if (type == IOMAP_READ)
-		INIT_WORK(&ioend->io_work, xfs_end_bio_read);
+		INIT_WORK(&ioend->io_work, xfs_end_bio_read, ioend);
 	else
-		INIT_WORK(&ioend->io_work, xfs_end_bio_written);
+		INIT_WORK(&ioend->io_work, xfs_end_bio_written, ioend);
 
 	return ioend;
 }
@@ -339,13 +335,17 @@ xfs_iomap_valid(
 /*
  * BIO completion handler for buffered IO.
  */
-STATIC void
+STATIC int
 xfs_end_bio(
 	struct bio		*bio,
+	unsigned int		bytes_done,
 	int			error)
 {
 	xfs_ioend_t		*ioend = bio->bi_private;
 
+	if (bio->bi_size)
+		return 1;
+
 	ASSERT(atomic_read(&bio->bi_cnt) >= 1);
 	ioend->io_error = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : error;
 
@@ -355,6 +355,7 @@ xfs_end_bio(
 	bio_put(bio);
 
 	xfs_finish_ioend(ioend, 0);
+	return 0;
 }
 
 STATIC void
@@ -674,7 +675,7 @@ xfs_probe_cluster(
 			} else
 				pg_offset = PAGE_CACHE_SIZE;
 
-			if (page->index == tindex && trylock_page(page)) {
+			if (page->index == tindex && !TestSetPageLocked(page)) {
 				pg_len = xfs_probe_page(page, pg_offset, mapped);
 				unlock_page(page);
 			}
@@ -758,7 +759,7 @@ xfs_convert_page(
 
 	if (page->index != tindex)
 		goto fail;
-	if (!trylock_page(page))
+	if (TestSetPageLocked(page))
 		goto fail;
 	if (PageWriteback(page))
 		goto fail_unlock_page;
@@ -1103,7 +1104,7 @@ xfs_page_state_convert(
 			 * that we are writing into for the first time.
 			 */
 			type = IOMAP_NEW;
-			if (trylock_buffer(bh)) {
+			if (!test_and_set_bit(BH_Lock, &bh->b_state)) {
 				ASSERT(buffer_mapped(bh));
 				if (iomap_valid)
 					all_bh = 1;
@@ -1468,7 +1469,7 @@ xfs_end_io_direct(
 		 * didn't map an unwritten extent so switch it's completion
 		 * handler.
 		 */
-		INIT_WORK(&ioend->io_work, xfs_end_bio_written);
+		INIT_WORK(&ioend->io_work, xfs_end_bio_written, ioend);
 		xfs_finish_ioend(ioend, 0);
 	}
 
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c
index 8454dee..f0e7ab4 100644
--- a/fs/xfs/linux-2.6/xfs_buf.c
+++ b/fs/xfs/linux-2.6/xfs_buf.c
@@ -32,16 +32,12 @@
 #include <linux/kthread.h>
 #include <linux/migrate.h>
 #include <linux/backing-dev.h>
-#include <linux/freezer.h>
 
 static kmem_zone_t *xfs_buf_zone;
 STATIC int xfsbufd(void *);
 STATIC int xfsbufd_wakeup(int, gfp_t);
 STATIC void xfs_buf_delwri_queue(xfs_buf_t *, int);
-static struct shrinker xfs_buf_shake = {
-	.shrink = xfsbufd_wakeup,
-	.seeks = DEFAULT_SEEKS,
-};
+static struct shrinker *xfs_buf_shake;
 
 static struct workqueue_struct *xfslogd_workqueue;
 struct workqueue_struct *xfsdatad_workqueue;
@@ -58,7 +54,7 @@ xfs_buf_trace(
 		bp, id,
 		(void *)(unsigned long)bp->b_flags,
 		(void *)(unsigned long)bp->b_hold.counter,
-		(void *)(unsigned long)bp->b_sema.count,
+		(void *)(unsigned long)bp->b_sema.count.counter,
 		(void *)current,
 		data, ra,
 		(void *)(unsigned long)((bp->b_file_offset>>32) & 0xffffffff),
@@ -405,7 +401,7 @@ _xfs_buf_lookup_pages(
 
 			XFS_STATS_INC(xb_page_retries);
 			xfsbufd_wakeup(0, gfp_mask);
-			congestion_wait(WRITE, HZ/50);
+			blk_congestion_wait(WRITE, HZ/50);
 			goto retry;
 		}
 
@@ -891,7 +887,7 @@ int
 xfs_buf_lock_value(
 	xfs_buf_t		*bp)
 {
-	return bp->b_sema.count;
+	return atomic_read(&bp->b_sema.count);
 }
 #endif
 
@@ -992,10 +988,9 @@ xfs_buf_wait_unpin(
 
 STATIC void
 xfs_buf_iodone_work(
-	struct work_struct	*work)
+	void			*data)
 {
-	xfs_buf_t		*bp =
-		container_of(work, xfs_buf_t, b_iodone_work);
+	xfs_buf_t		*bp = data;
 
 	/*
 	 * We can get an EOPNOTSUPP to ordered writes.  Here we clear the
@@ -1028,10 +1023,10 @@ xfs_buf_ioend(
 
 	if ((bp->b_iodone) || (bp->b_flags & XBF_ASYNC)) {
 		if (schedule) {
-			INIT_WORK(&bp->b_iodone_work, xfs_buf_iodone_work);
+			INIT_WORK(&bp->b_iodone_work, xfs_buf_iodone_work, bp);
 			queue_work(xfslogd_workqueue, &bp->b_iodone_work);
 		} else {
-			xfs_buf_iodone_work(&bp->b_iodone_work);
+			xfs_buf_iodone_work(bp);
 		}
 	} else {
 		complete(&bp->b_iowait);
@@ -1105,15 +1100,19 @@ _xfs_buf_ioend(
 	}
 }
 
-STATIC void
+STATIC int
 xfs_buf_bio_end_io(
 	struct bio		*bio,
+	unsigned int		bytes_done,
 	int			error)
 {
 	xfs_buf_t		*bp = (xfs_buf_t *)bio->bi_private;
 	unsigned int		blocksize = bp->b_target->bt_bsize;
 	struct bio_vec		*bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
 
+	if (bio->bi_size)
+		return 1;
+
 	xfs_buf_ioerror(bp, -error);
 
 	do {
@@ -1139,6 +1138,7 @@ xfs_buf_bio_end_io(
 
 	_xfs_buf_ioend(bp, 1);
 	bio_put(bio);
+	return 0;
 }
 
 STATIC void
@@ -1705,8 +1705,6 @@ xfsbufd(
 
 	current->flags |= PF_MEMALLOC;
 
-	set_freezable();
-
 	do {
 		if (unlikely(freezing(current))) {
 			set_bit(XBT_FORCE_SLEEP, &target->bt_flags);
@@ -1811,9 +1809,14 @@ xfs_buf_init(void)
 	if (!xfsdatad_workqueue)
 		goto out_destroy_xfslogd_workqueue;
 
-	register_shrinker(&xfs_buf_shake);
+	xfs_buf_shake = set_shrinker(DEFAULT_SEEKS, xfsbufd_wakeup);
+	if (!xfs_buf_shake)
+		goto out_destroy_xfsdatad_workqueue;
+
 	return 0;
 
+ out_destroy_xfsdatad_workqueue:
+	destroy_workqueue(xfsdatad_workqueue);
  out_destroy_xfslogd_workqueue:
 	destroy_workqueue(xfslogd_workqueue);
  out_free_buf_zone:
@@ -1828,7 +1831,7 @@ xfs_buf_init(void)
 void
 xfs_buf_terminate(void)
 {
-	unregister_shrinker(&xfs_buf_shake);
+	remove_shrinker(xfs_buf_shake);
 	destroy_workqueue(xfsdatad_workqueue);
 	destroy_workqueue(xfslogd_workqueue);
 	kmem_zone_destroy(xfs_buf_zone);
diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c
index 7f7abec..c46e1df 100644
--- a/fs/xfs/linux-2.6/xfs_export.c
+++ b/fs/xfs/linux-2.6/xfs_export.c
@@ -22,7 +22,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_export.h"
@@ -31,26 +30,65 @@
 #include "xfs_inode.h"
 #include "xfs_vfsops.h"
 
+static struct xfs_name xfs_name_dotdot = {"..", 2};
+
 /*
- * Note that we only accept fileids which are long enough rather than allow
- * the parent generation number to default to zero.  XFS considers zero a
- * valid generation number not an invalid/wildcard value.
+ * XFS encodes and decodes the fileid portion of NFS filehandles
+ * itself instead of letting the generic NFS code do it.  This
+ * allows filesystems with 64 bit inode numbers to be exported.
+ *
+ * Note that a side effect is that xfs_vget() won't be passed a
+ * zero inode/generation pair under normal circumstances.  As
+ * however a malicious client could send us such data, the check
+ * remains in that code.
  */
-static int xfs_fileid_length(int fileid_type)
+
+STATIC struct dentry *
+xfs_fs_decode_fh(
+	struct super_block	*sb,
+	__u32			*fh,
+	int			fh_len,
+	int			fileid_type,
+	int (*acceptable)(
+		void		*context,
+		struct dentry	*de),
+	void			*context)
 {
-	switch (fileid_type) {
-	case FILEID_INO32_GEN:
-		return 2;
-	case FILEID_INO32_GEN_PARENT:
-		return 4;
-	case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
-		return 3;
-	case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
-		return 6;
+	xfs_fid_t		ifid;
+	xfs_fid_t		pfid;
+	void			*parent = NULL;
+	int			is64 = 0;
+	__u32			*p = fh;
+
+#if XFS_BIG_INUMS
+	is64 = (fileid_type & XFS_FILEID_TYPE_64FLAG);
+	fileid_type &= ~XFS_FILEID_TYPE_64FLAG;
+#endif
+
+	/*
+	 * Note that we only accept fileids which are long enough
+	 * rather than allow the parent generation number to default
+	 * to zero.  XFS considers zero a valid generation number not
+	 * an invalid/wildcard value.  There's little point printk'ing
+	 * a warning here as we don't have the client information
+	 * which would make such a warning useful.
+	 */
+	if (fileid_type > 2 ||
+	    fh_len < xfs_fileid_length((fileid_type == 2), is64))
+		return NULL;
+
+	p = xfs_fileid_decode_fid2(p, &ifid, is64);
+
+	if (fileid_type == 2) {
+		p = xfs_fileid_decode_fid2(p, &pfid, is64);
+		parent = &pfid;
 	}
-	return 255; /* invalid */
+
+	fh = (__u32 *)&ifid;
+	return sb->s_export_op->find_exported_dentry(sb, fh, parent, acceptable, context);
 }
 
+
 STATIC int
 xfs_fs_encode_fh(
 	struct dentry		*dentry,
@@ -58,21 +96,20 @@ xfs_fs_encode_fh(
 	int			*max_len,
 	int			connectable)
 {
-	struct fid		*fid = (struct fid *)fh;
-	struct xfs_fid64	*fid64 = (struct xfs_fid64 *)fh;
 	struct inode		*inode = dentry->d_inode;
-	int			fileid_type;
+	int			type = 1;
+	__u32			*p = fh;
 	int			len;
-
+	int			is64 = 0;
+#if XFS_BIG_INUMS
+	if (!(XFS_M(inode->i_sb)->m_flags & XFS_MOUNT_SMALL_INUMS)) {
+		/* filesystem may contain 64bit inode numbers */
+		is64 = XFS_FILEID_TYPE_64FLAG;
+	}
+#endif
 	/* Directories don't need their parent encoded, they have ".." */
-	if (S_ISDIR(inode->i_mode) || !connectable)
-		fileid_type = FILEID_INO32_GEN;
-	else
-		fileid_type = FILEID_INO32_GEN_PARENT;
-
-	/* filesystem may contain 64bit inode numbers */
-	if (!(XFS_M(inode->i_sb)->m_flags & XFS_MOUNT_SMALL_INUMS))
-		fileid_type |= XFS_FILEID_TYPE_64FLAG;
+	if (S_ISDIR(inode->i_mode))
+	    connectable = 0;
 
 	/*
 	 * Only encode if there is enough space given.  In practice
@@ -80,110 +117,52 @@ xfs_fs_encode_fh(
 	 * over NFSv2 with the subtree_check export option; the other
 	 * seven combinations work.  The real answer is "don't use v2".
 	 */
-	len = xfs_fileid_length(fileid_type);
+	len = xfs_fileid_length(connectable, is64);
 	if (*max_len < len)
 		return 255;
 	*max_len = len;
 
-	switch (fileid_type) {
-	case FILEID_INO32_GEN_PARENT:
-		spin_lock(&dentry->d_lock);
-		fid->i32.parent_ino = dentry->d_parent->d_inode->i_ino;
-		fid->i32.parent_gen = dentry->d_parent->d_inode->i_generation;
-		spin_unlock(&dentry->d_lock);
-		/*FALLTHRU*/
-	case FILEID_INO32_GEN:
-		fid->i32.ino = inode->i_ino;
-		fid->i32.gen = inode->i_generation;
-		break;
-	case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
+	p = xfs_fileid_encode_inode(p, inode, is64);
+	if (connectable) {
 		spin_lock(&dentry->d_lock);
-		fid64->parent_ino = dentry->d_parent->d_inode->i_ino;
-		fid64->parent_gen = dentry->d_parent->d_inode->i_generation;
+		p = xfs_fileid_encode_inode(p, dentry->d_parent->d_inode, is64);
 		spin_unlock(&dentry->d_lock);
-		/*FALLTHRU*/
-	case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
-		fid64->ino = inode->i_ino;
-		fid64->gen = inode->i_generation;
-		break;
+		type = 2;
 	}
-
-	return fileid_type;
+	BUG_ON((p - fh) != len);
+	return type | is64;
 }
 
-STATIC struct inode *
-xfs_nfs_get_inode(
+STATIC struct dentry *
+xfs_fs_get_dentry(
 	struct super_block	*sb,
-	u64			ino,
-	u32			generation)
- {
- 	xfs_mount_t		*mp = XFS_M(sb);
-	xfs_inode_t		*ip;
+	void			*data)
+{
+	struct xfs_inode	*ip;
+	struct inode		*inode;
+	xfs_fid_t       	*xfid = (struct xfs_fid *)data;
+	xfs_mount_t		*mp = XFS_M(sb);
 	int			error;
 
 	/*
 	 * NFS can sometimes send requests for ino 0.  Fail them gracefully.
 	 */
-	if (ino == 0)
+	if (xfid->fid_ino == 0)
 		return ERR_PTR(-ESTALE);
 
-	error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0);
+	error = xfs_iget(mp, NULL, xfid->fid_ino, 0, XFS_ILOCK_SHARED, &ip, 0);
 	if (error)
 		return ERR_PTR(-error);
 	if (!ip)
-		return ERR_PTR(-EIO);
+		return ERR_PTR(-EIO) ;
 
-	if (ip->i_d.di_gen != generation) {
+	if (!ip->i_d.di_mode || ip->i_d.di_gen != xfid->fid_gen) {
 		xfs_iput_new(ip, XFS_ILOCK_SHARED);
 		return ERR_PTR(-ENOENT);
 	}
 
 	xfs_iunlock(ip, XFS_ILOCK_SHARED);
-	return VFS_I(ip);
-}
-
-STATIC struct dentry *
-xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid,
-		 int fh_len, int fileid_type)
-{
-	struct xfs_fid64	*fid64 = (struct xfs_fid64 *)fid;
-	struct inode		*inode = NULL;
-
-	if (fh_len < xfs_fileid_length(fileid_type))
-		return NULL;
-
-	switch (fileid_type) {
-	case FILEID_INO32_GEN_PARENT:
-	case FILEID_INO32_GEN:
-		inode = xfs_nfs_get_inode(sb, fid->i32.ino, fid->i32.gen);
-		break;
-	case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
-	case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
-		inode = xfs_nfs_get_inode(sb, fid64->ino, fid64->gen);
-		break;
-	}
-
-	return d_obtain_alias(inode);
-}
-
-STATIC struct dentry *
-xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid,
-		 int fh_len, int fileid_type)
-{
-	struct xfs_fid64	*fid64 = (struct xfs_fid64 *)fid;
-	struct inode		*inode = NULL;
-
-	switch (fileid_type) {
-	case FILEID_INO32_GEN_PARENT:
-		inode = xfs_nfs_get_inode(sb, fid->i32.parent_ino,
-					      fid->i32.parent_gen);
-		break;
-	case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
-		inode = xfs_nfs_get_inode(sb, fid64->parent_ino,
-					      fid64->parent_gen);
-		break;
-	}
-
+	inode = VFS_I(ip);
 	return d_obtain_alias(inode);
 }
 
@@ -194,6 +173,7 @@ xfs_fs_get_parent(
 	int			error;
 	struct xfs_inode	*cip;
 
+	cip = NULL;
 	error = xfs_lookup(XFS_I(child->d_inode), &xfs_name_dotdot, &cip, NULL);
 	if (unlikely(error))
 		return ERR_PTR(-error);
@@ -201,9 +181,10 @@ xfs_fs_get_parent(
 	return d_obtain_alias(VFS_I(cip));
 }
 
-const struct export_operations xfs_export_operations = {
+struct export_operations xfs_export_operations = {
+	.decode_fh		= xfs_fs_decode_fh,
 	.encode_fh		= xfs_fs_encode_fh,
-	.fh_to_dentry		= xfs_fs_fh_to_dentry,
-	.fh_to_parent		= xfs_fs_fh_to_parent,
 	.get_parent		= xfs_fs_get_parent,
+	.get_dentry		= xfs_fs_get_dentry,
 };
+
diff --git a/fs/xfs/linux-2.6/xfs_export.h b/fs/xfs/linux-2.6/xfs_export.h
index 3272b6a..675bc63 100644
--- a/fs/xfs/linux-2.6/xfs_export.h
+++ b/fs/xfs/linux-2.6/xfs_export.h
@@ -59,14 +59,51 @@
  * a subdirectory) or use the "fsid" export option.
  */
 
-struct xfs_fid64 {
-	u64 ino;
-	u32 gen;
-	u64 parent_ino;
-	u32 parent_gen;
-} __attribute__((packed));
-
 /* This flag goes on the wire.  Don't play with it. */
 #define XFS_FILEID_TYPE_64FLAG	0x80	/* NFS fileid has 64bit inodes */
 
+/* Calculate the length in u32 units of the fileid data */
+static inline int
+xfs_fileid_length(int hasparent, int is64)
+{
+	return hasparent ? (is64 ? 6 : 4) : (is64 ? 3 : 2);
+}
+
+/*
+ * Decode encoded inode information (either for the inode itself
+ * or the parent) into an xfs_fid_t structure.  Advances and
+ * returns the new data pointer
+ */
+static inline __u32 *
+xfs_fileid_decode_fid2(__u32 *p, xfs_fid_t *fid, int is64)
+{
+	fid->fid_len = sizeof(xfs_fid_t) - sizeof(fid->fid_len);
+	fid->fid_pad = 0;
+	fid->fid_ino = *p++;
+#if XFS_BIG_INUMS
+	if (is64)
+		fid->fid_ino |= (((__u64)(*p++)) << 32);
+#endif
+	fid->fid_gen = *p++;
+	return p;
+}
+
+/*
+ * Encode inode information (either for the inode itself or the
+ * parent) into a fileid buffer.  Advances and returns the new
+ * data pointer.
+ */
+static inline __u32 *
+xfs_fileid_encode_inode(__u32 *p, struct inode *inode, int is64)
+{
+	*p++ = (__u32)inode->i_ino;
+#if XFS_BIG_INUMS
+	if (is64)
+		*p++ = (__u32)(inode->i_ino >> 32);
+#endif
+	*p++ = inode->i_generation;
+	return p;
+}
+
 #endif	/* __XFS_EXPORT_H__ */
+
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c
index 3fee790..dc28fd4 100644
--- a/fs/xfs/linux-2.6/xfs_file.c
+++ b/fs/xfs/linux-2.6/xfs_file.c
@@ -47,75 +47,209 @@ static struct vm_operations_struct xfs_file_vm_ops;
 STATIC_INLINE ssize_t
 __xfs_file_read(
 	struct kiocb		*iocb,
-	const struct iovec	*iov,
-	unsigned long		nr_segs,
+	char			__user *buf,
 	int			ioflags,
+	size_t			count,
 	loff_t			pos)
 {
+	struct iovec		iov = {buf, count};
 	struct file		*file = iocb->ki_filp;
 
 	BUG_ON(iocb->ki_pos != pos);
 	if (unlikely(file->f_flags & O_DIRECT))
 		ioflags |= IO_ISDIRECT;
-	return xfs_read(XFS_I(file->f_path.dentry->d_inode), iocb, iov,
-				nr_segs, &iocb->ki_pos, ioflags);
+	return xfs_read(XFS_I(file->f_dentry->d_inode), iocb, &iov, 1, &iocb->ki_pos, ioflags);
 }
 
 STATIC ssize_t
 xfs_file_aio_read(
 	struct kiocb		*iocb,
-	const struct iovec	*iov,
-	unsigned long		nr_segs,
+	char			__user *buf,
+	size_t			count,
 	loff_t			pos)
 {
-	return __xfs_file_read(iocb, iov, nr_segs, IO_ISAIO, pos);
+	return __xfs_file_read(iocb, buf, IO_ISAIO, count, pos);
 }
 
 STATIC ssize_t
 xfs_file_aio_read_invis(
 	struct kiocb		*iocb,
-	const struct iovec	*iov,
-	unsigned long		nr_segs,
+	char			__user *buf,
+	size_t			count,
 	loff_t			pos)
 {
-	return __xfs_file_read(iocb, iov, nr_segs, IO_ISAIO|IO_INVIS, pos);
+	return __xfs_file_read(iocb, buf, IO_ISAIO|IO_INVIS, count, pos);
 }
 
 STATIC_INLINE ssize_t
 __xfs_file_write(
 	struct kiocb		*iocb,
-	const struct iovec	*iov,
-	unsigned long		nr_segs,
+	const char		__user *buf,
 	int			ioflags,
+	size_t			count,
 	loff_t			pos)
 {
+	struct iovec	iov = {(void __user *)buf, count};
 	struct file	*file = iocb->ki_filp;
 
 	BUG_ON(iocb->ki_pos != pos);
 	if (unlikely(file->f_flags & O_DIRECT))
 		ioflags |= IO_ISDIRECT;
-	return xfs_write(XFS_I(file->f_mapping->host), iocb, iov, nr_segs,
+	return xfs_write(XFS_I(file->f_mapping->host), iocb, &iov, 1,
 				&iocb->ki_pos, ioflags);
 }
 
 STATIC ssize_t
 xfs_file_aio_write(
 	struct kiocb		*iocb,
-	const struct iovec	*iov,
-	unsigned long		nr_segs,
+	const char		__user *buf,
+	size_t			count,
 	loff_t			pos)
 {
-	return __xfs_file_write(iocb, iov, nr_segs, IO_ISAIO, pos);
+	return __xfs_file_write(iocb, buf, IO_ISAIO, count, pos);
 }
 
 STATIC ssize_t
 xfs_file_aio_write_invis(
 	struct kiocb		*iocb,
+	const char		__user *buf,
+	size_t			count,
+	loff_t			pos)
+{
+	return __xfs_file_write(iocb, buf, IO_ISAIO|IO_INVIS, count, pos);
+}
+
+STATIC_INLINE ssize_t
+__xfs_file_readv(
+	struct file		*file,
 	const struct iovec	*iov,
+	int			ioflags,
 	unsigned long		nr_segs,
-	loff_t			pos)
+	loff_t			*ppos)
+{
+	struct kiocb	kiocb;
+	ssize_t		rval;
+
+	init_sync_kiocb(&kiocb, file);
+	kiocb.ki_pos = *ppos;
+
+	if (unlikely(file->f_flags & O_DIRECT))
+		ioflags |= IO_ISDIRECT;
+	rval = xfs_read(XFS_I(file->f_dentry->d_inode), &kiocb, iov,
+			nr_segs, &kiocb.ki_pos, ioflags);
+
+	*ppos = kiocb.ki_pos;
+	return rval;
+}
+
+STATIC ssize_t
+xfs_file_readv(
+	struct file		*file,
+	const struct iovec	*iov,
+	unsigned long		nr_segs,
+	loff_t			*ppos)
+{
+	return __xfs_file_readv(file, iov, 0, nr_segs, ppos);
+}
+
+STATIC_INLINE ssize_t
+__xfs_file_writev(
+	struct file		*file,
+	const struct iovec	*iov,
+	int			ioflags,
+	unsigned long		nr_segs,
+	loff_t			*ppos)
+{
+	struct kiocb	kiocb;
+	ssize_t		rval;
+
+	init_sync_kiocb(&kiocb, file);
+	kiocb.ki_pos = *ppos;
+	if (unlikely(file->f_flags & O_DIRECT))
+		ioflags |= IO_ISDIRECT;
+
+	rval = xfs_write(XFS_I(file->f_mapping->host), &kiocb, iov, nr_segs,
+			 &kiocb.ki_pos, ioflags);
+
+	*ppos = kiocb.ki_pos;
+	return rval;
+}
+
+STATIC ssize_t
+xfs_file_writev(
+	struct file		*file,
+	const struct iovec	*iov,
+	unsigned long		nr_segs,
+	loff_t			*ppos)
 {
-	return __xfs_file_write(iocb, iov, nr_segs, IO_ISAIO|IO_INVIS, pos);
+	return __xfs_file_writev(file, iov, 0, nr_segs, ppos);
+}
+
+ssize_t
+xfs_sendfile(
+	struct xfs_inode	*xip,
+	struct file		*filp,
+	loff_t			*offset,
+	int			ioflags,
+	size_t			count,
+	read_actor_t		actor,
+	void			*target,
+	cred_t			*credp)
+{
+	xfs_mount_t		*mp = xip->i_mount;
+	ssize_t			ret;
+
+	XFS_STATS_INC(xs_read_calls);
+	if (XFS_FORCED_SHUTDOWN(mp))
+		return -EIO;
+
+	xfs_ilock(xip, XFS_IOLOCK_SHARED);
+
+	if (DM_EVENT_ENABLED(xip, DM_EVENT_READ) &&
+	    (!(ioflags & IO_INVIS))) {
+		int locktype = XFS_IOLOCK_SHARED;
+		int error;
+
+		error = XFS_SEND_DATA(mp, DM_EVENT_READ, xip,
+				      *offset, count,
+				      FILP_DELAY_FLAG(filp), &locktype);
+		if (error) {
+			xfs_iunlock(xip, XFS_IOLOCK_SHARED);
+			return -error;
+		}
+	}
+	xfs_rw_enter_trace(XFS_SENDFILE_ENTER, xip,
+		   (void *)(unsigned long)target, count, *offset, ioflags);
+	ret = generic_file_sendfile(filp, offset, count, actor, target);
+	if (ret > 0)
+		XFS_STATS_ADD(xs_read_bytes, ret);
+
+	xfs_iunlock(xip, XFS_IOLOCK_SHARED);
+	return ret;
+}
+
+STATIC ssize_t
+xfs_file_sendfile(
+	struct file		*filp,
+	loff_t			*pos,
+	size_t			count,
+	read_actor_t		actor,
+	void			*target)
+{
+	return xfs_sendfile(XFS_I(filp->f_dentry->d_inode), filp, pos, 0,
+			    count, actor, target, NULL);
+}
+
+STATIC ssize_t
+xfs_file_sendfile_invis(
+	struct file		*filp,
+	loff_t			*pos,
+	size_t			count,
+	read_actor_t		actor,
+	void			*target)
+{
+	return xfs_sendfile(XFS_I(filp->f_dentry->d_inode), filp, pos, IO_INVIS,
+			    count, actor, target, NULL);
 }
 
 STATIC ssize_t
@@ -126,7 +260,7 @@ xfs_file_splice_read(
 	size_t			len,
 	unsigned int		flags)
 {
-	return xfs_splice_read(XFS_I(infilp->f_path.dentry->d_inode),
+	return xfs_splice_read(XFS_I(infilp->f_dentry->d_inode),
 				   infilp, ppos, pipe, len, flags, 0);
 }
 
@@ -138,7 +272,7 @@ xfs_file_splice_read_invis(
 	size_t			len,
 	unsigned int		flags)
 {
-	return xfs_splice_read(XFS_I(infilp->f_path.dentry->d_inode),
+	return xfs_splice_read(XFS_I(infilp->f_dentry->d_inode),
 				   infilp, ppos, pipe, len, flags, IO_INVIS);
 }
 
@@ -150,7 +284,7 @@ xfs_file_splice_write(
 	size_t			len,
 	unsigned int		flags)
 {
-	return xfs_splice_write(XFS_I(outfilp->f_path.dentry->d_inode),
+	return xfs_splice_write(XFS_I(outfilp->f_dentry->d_inode),
 				    pipe, outfilp, ppos, len, flags, 0);
 }
 
@@ -162,7 +296,7 @@ xfs_file_splice_write_invis(
 	size_t			len,
 	unsigned int		flags)
 {
-	return xfs_splice_write(XFS_I(outfilp->f_path.dentry->d_inode),
+	return xfs_splice_write(XFS_I(outfilp->f_dentry->d_inode),
 				    pipe, outfilp, ppos, len, flags, IO_INVIS);
 }
 
@@ -204,13 +338,22 @@ xfs_file_fsync(
 	return -xfs_fsync(XFS_I(dentry->d_inode));
 }
 
+/*
+ * Unfortunately we can't just use the clean and simple readdir implementation
+ * below, because nfs might call back into ->lookup from the filldir callback
+ * and that will deadlock the low-level btree code.
+ *
+ * Hopefully we'll find a better workaround that allows to use the optimal
+ * version at least for local readdirs for 2.6.25.
+ */
+#if 0
 STATIC int
 xfs_file_readdir(
 	struct file	*filp,
 	void		*dirent,
 	filldir_t	filldir)
 {
-	struct inode	*inode = filp->f_path.dentry->d_inode;
+	struct inode	*inode = filp->f_dentry->d_inode;
 	xfs_inode_t	*ip = XFS_I(inode);
 	int		error;
 	size_t		bufsize;
@@ -235,6 +378,125 @@ xfs_file_readdir(
 		return -error;
 	return 0;
 }
+#else
+
+struct hack_dirent {
+	u64		ino;
+	loff_t		offset;
+	int		namlen;
+	unsigned int	d_type;
+	char		name[];
+};
+
+struct hack_callback {
+	char		*dirent;
+	size_t		len;
+	size_t		used;
+};
+
+STATIC int
+xfs_hack_filldir(
+	void		*__buf,
+	const char	*name,
+	int		namlen,
+	loff_t		offset,
+	u64		ino,
+	unsigned int	d_type)
+{
+	struct hack_callback *buf = __buf;
+	struct hack_dirent *de = (struct hack_dirent *)(buf->dirent + buf->used);
+	unsigned int reclen;
+
+	reclen = ALIGN(sizeof(struct hack_dirent) + namlen, sizeof(u64));
+	if (buf->used + reclen > buf->len)
+		return -EINVAL;
+
+	de->namlen = namlen;
+	de->offset = offset;
+	de->ino = ino;
+	de->d_type = d_type;
+	memcpy(de->name, name, namlen);
+	buf->used += reclen;
+	return 0;
+}
+
+STATIC int
+xfs_file_readdir(
+	struct file	*filp,
+	void		*dirent,
+	filldir_t	filldir)
+{
+	struct inode	*inode = filp->f_dentry->d_inode;
+	xfs_inode_t	*ip = XFS_I(inode);
+	struct hack_callback buf;
+	struct hack_dirent *de;
+	int		error;
+	loff_t		size;
+	int		eof = 0;
+	xfs_off_t       start_offset, curr_offset, offset;
+
+	/*
+	 * Try fairly hard to get memory
+	 */
+	buf.len = PAGE_CACHE_SIZE;
+	do {
+		buf.dirent = kmalloc(buf.len, GFP_KERNEL);
+		if (buf.dirent)
+			break;
+		buf.len >>= 1;
+	} while (buf.len >= 1024);
+
+	if (!buf.dirent)
+		return -ENOMEM;
+
+	curr_offset = filp->f_pos;
+	if (curr_offset == 0x7fffffff)
+		offset = 0xffffffff;
+	else
+		offset = filp->f_pos;
+
+	while (!eof) {
+		unsigned int reclen;
+
+		start_offset = offset;
+
+		buf.used = 0;
+		error = -xfs_readdir(ip, &buf, buf.len, &offset,
+				     xfs_hack_filldir);
+		if (error || offset == start_offset) {
+			size = 0;
+			break;
+		}
+
+		size = buf.used;
+		de = (struct hack_dirent *)buf.dirent;
+		while (size > 0) {
+			curr_offset = de->offset /* & 0x7fffffff */;
+			if (filldir(dirent, de->name, de->namlen,
+					curr_offset & 0x7fffffff,
+					de->ino, de->d_type)) {
+				goto done;
+			}
+
+			reclen = ALIGN(sizeof(struct hack_dirent) + de->namlen,
+				       sizeof(u64));
+			size -= reclen;
+			de = (struct hack_dirent *)((char *)de + reclen);
+		}
+	}
+
+ done:
+	if (!error) {
+		if (size == 0)
+			filp->f_pos = offset & 0x7fffffff;
+		else if (de)
+			filp->f_pos = curr_offset;
+	}
+
+	kfree(buf.dirent);
+	return error;
+}
+#endif
 
 STATIC int
 xfs_file_mmap(
@@ -242,7 +504,6 @@ xfs_file_mmap(
 	struct vm_area_struct *vma)
 {
 	vma->vm_ops = &xfs_file_vm_ops;
-	vma->vm_flags |= VM_CAN_NONLINEAR;
 
 	file_accessed(filp);
 	return 0;
@@ -255,7 +516,7 @@ xfs_file_ioctl(
 	unsigned long	p)
 {
 	int		error;
-	struct inode	*inode = filp->f_path.dentry->d_inode;
+	struct inode	*inode = filp->f_dentry->d_inode;
 
 	error = xfs_ioctl(XFS_I(inode), filp, 0, cmd, (void __user *)p);
 	xfs_iflags_set(XFS_I(inode), XFS_IMODIFIED);
@@ -276,7 +537,7 @@ xfs_file_ioctl_invis(
 	unsigned long	p)
 {
 	int		error;
-	struct inode	*inode = filp->f_path.dentry->d_inode;
+	struct inode	*inode = filp->f_dentry->d_inode;
 
 	error = xfs_ioctl(XFS_I(inode), filp, IO_INVIS, cmd, (void __user *)p);
 	xfs_iflags_set(XFS_I(inode), XFS_IMODIFIED);
@@ -308,10 +569,13 @@ const struct file_operations xfs_file_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= do_sync_read,
 	.write		= do_sync_write,
+	.readv		= xfs_file_readv,
+	.writev		= xfs_file_writev,
 	.aio_read	= xfs_file_aio_read,
 	.aio_write	= xfs_file_aio_write,
 	.splice_read	= xfs_file_splice_read,
 	.splice_write	= xfs_file_splice_write,
+	.sendfile	= xfs_file_sendfile,
 	.unlocked_ioctl	= xfs_file_ioctl,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= xfs_file_compat_ioctl,
@@ -333,6 +597,7 @@ const struct file_operations xfs_invis_file_operations = {
 	.aio_write	= xfs_file_aio_write_invis,
 	.splice_read	= xfs_file_splice_read_invis,
 	.splice_write	= xfs_file_splice_write_invis,
+	.sendfile	= xfs_file_sendfile_invis,
 	.unlocked_ioctl	= xfs_file_ioctl_invis,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= xfs_file_compat_invis_ioctl,
@@ -356,6 +621,7 @@ const struct file_operations xfs_dir_file_operations = {
 };
 
 static struct vm_operations_struct xfs_file_vm_ops = {
-	.fault		= filemap_fault,
+	.nopage		= filemap_nopage,
+	.populate	= filemap_populate,
 	.page_mkwrite	= xfs_vm_page_mkwrite,
 };
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c
index d3438c7..7f433cf 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl.c
@@ -86,15 +86,17 @@ xfs_find_handle(
 	switch (cmd) {
 	case XFS_IOC_PATH_TO_FSHANDLE:
 	case XFS_IOC_PATH_TO_HANDLE: {
-		struct path path;
-		int error = user_lpath((const char __user *)hreq.path, &path);
+		struct nameidata	nd;
+		int			error;
+
+		error = user_path_walk_link((const char __user *)hreq.path, &nd);
 		if (error)
 			return error;
 
-		ASSERT(path.dentry);
-		ASSERT(path.dentry->d_inode);
-		inode = igrab(path.dentry->d_inode);
-		path_put(&path);
+		ASSERT(nd.dentry);
+		ASSERT(nd.dentry->d_inode);
+		inode = igrab(nd.dentry->d_inode);
+		path_release(&nd);
 		break;
 	}
 
@@ -105,9 +107,9 @@ xfs_find_handle(
 		if (!file)
 		    return -EBADF;
 
-		ASSERT(file->f_path.dentry);
-		ASSERT(file->f_path.dentry->d_inode);
-		inode = igrab(file->f_path.dentry->d_inode);
+		ASSERT(file->f_dentry);
+		ASSERT(file->f_dentry->d_inode);
+		inode = igrab(file->f_dentry->d_inode);
 		fput(file);
 		break;
 	}
@@ -318,10 +320,10 @@ xfs_open_by_handle(
 	}
 
 	/* Ensure umount returns EBUSY on umounts while this file is open. */
-	mntget(parfilp->f_path.mnt);
+	mntget(parfilp->f_vfsmnt);
 
 	/* Create file pointer. */
-	filp = dentry_open(dentry, parfilp->f_path.mnt, hreq.oflags);
+	filp = dentry_open(dentry, parfilp->f_vfsmnt, hreq.oflags);
 	if (IS_ERR(filp)) {
 		put_unused_fd(new_fd);
 		return -XFS_ERROR(-PTR_ERR(filp));
@@ -540,6 +542,8 @@ xfs_attrmulti_attr_set(
 	char			*kbuf;
 	int			error = EFAULT;
 
+	if (IS_RDONLY(inode))
+		return -EROFS;
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 		return EPERM;
 	if (len > XATTR_SIZE_MAX)
@@ -565,6 +569,8 @@ xfs_attrmulti_attr_remove(
 	char			*name,
 	__uint32_t		flags)
 {
+	if (IS_RDONLY(inode))
+		return -EROFS;
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 		return EPERM;
 	return xfs_attr_remove(XFS_I(inode), name, flags);
@@ -574,7 +580,6 @@ STATIC int
 xfs_attrmulti_by_handle(
 	xfs_mount_t		*mp,
 	void			__user *arg,
-	struct file		*parfilp,
 	struct inode		*parinode)
 {
 	int			error;
@@ -628,21 +633,13 @@ xfs_attrmulti_by_handle(
 					&ops[i].am_length, ops[i].am_flags);
 			break;
 		case ATTR_OP_SET:
-			ops[i].am_error = mnt_want_write(parfilp->f_path.mnt);
-			if (ops[i].am_error)
-				break;
 			ops[i].am_error = xfs_attrmulti_attr_set(inode,
 					attr_name, ops[i].am_attrvalue,
 					ops[i].am_length, ops[i].am_flags);
-			mnt_drop_write(parfilp->f_path.mnt);
 			break;
 		case ATTR_OP_REMOVE:
-			ops[i].am_error = mnt_want_write(parfilp->f_path.mnt);
-			if (ops[i].am_error)
-				break;
 			ops[i].am_error = xfs_attrmulti_attr_remove(inode,
 					attr_name, ops[i].am_flags);
-			mnt_drop_write(parfilp->f_path.mnt);
 			break;
 		default:
 			ops[i].am_error = EINVAL;
@@ -1333,7 +1330,7 @@ xfs_ioctl(
 	unsigned int		cmd,
 	void			__user *arg)
 {
-	struct inode		*inode = filp->f_path.dentry->d_inode;
+	struct inode		*inode = filp->f_dentry->d_inode;
 	xfs_mount_t		*mp = ip->i_mount;
 	int			error;
 
@@ -1433,7 +1430,7 @@ xfs_ioctl(
 		return xfs_attrlist_by_handle(mp, arg, inode);
 
 	case XFS_IOC_ATTRMULTI_BY_HANDLE:
-		return xfs_attrmulti_by_handle(mp, arg, filp, inode);
+		return xfs_attrmulti_by_handle(mp, arg, inode);
 
 	case XFS_IOC_SWAPEXT: {
 		error = xfs_swapext((struct xfs_swapext __user *)arg);
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c
index a4b254e..d5b5023 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl32.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl32.c
@@ -374,7 +374,7 @@ xfs_compat_ioctl(
 	unsigned	cmd,
 	unsigned long	arg)
 {
-	struct inode	*inode = file->f_path.dentry->d_inode;
+	struct inode	*inode = file->f_dentry->d_inode;
 	int		error;
 
 	switch (cmd) {
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c
index 095d271..c2233ec 100644
--- a/fs/xfs/linux-2.6/xfs_iops.c
+++ b/fs/xfs/linux-2.6/xfs_iops.c
@@ -101,6 +101,13 @@ xfs_ichgtime(
 
 	tv = current_fs_time(inode->i_sb);
 
+	/*
+	 * We're not supposed to change timestamps in readonly-mounted
+	 * filesystems.  Throw it away if anyone asks us.
+	 */
+	 if (unlikely(IS_RDONLY(inode)))
+		return;
+
 	if ((flags & XFS_ICHGTIME_MOD) &&
 	    !timespec_equal(&inode->i_mtime, &tv)) {
 		inode->i_mtime = tv;
@@ -529,7 +536,8 @@ xfs_check_acl(
 STATIC int
 xfs_vn_permission(
 	struct inode		*inode,
-	int			mask)
+	int			mask,
+	struct nameidata	*nd)
 {
 	return generic_permission(inode, mask, xfs_check_acl);
 }
@@ -661,7 +669,7 @@ out_error:
 	return error;
 }
 
-static const struct inode_operations xfs_inode_operations = {
+static struct inode_operations xfs_inode_operations = {
 	.permission		= xfs_vn_permission,
 	.truncate		= xfs_vn_truncate,
 	.getattr		= xfs_vn_getattr,
@@ -673,7 +681,7 @@ static const struct inode_operations xfs_inode_operations = {
 	.fallocate		= xfs_vn_fallocate,
 };
 
-static const struct inode_operations xfs_dir_inode_operations = {
+static struct inode_operations xfs_dir_inode_operations = {
 	.create			= xfs_vn_create,
 	.lookup			= xfs_vn_lookup,
 	.link			= xfs_vn_link,
@@ -698,7 +706,7 @@ static const struct inode_operations xfs_dir_inode_operations = {
 	.listxattr		= xfs_vn_listxattr,
 };
 
-static const struct inode_operations xfs_dir_ci_inode_operations = {
+static struct inode_operations xfs_dir_ci_inode_operations = {
 	.create			= xfs_vn_create,
 	.lookup			= xfs_vn_ci_lookup,
 	.link			= xfs_vn_link,
@@ -723,7 +731,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = {
 	.listxattr		= xfs_vn_listxattr,
 };
 
-static const struct inode_operations xfs_symlink_inode_operations = {
+static struct inode_operations xfs_symlink_inode_operations = {
 	.readlink		= generic_readlink,
 	.follow_link		= xfs_vn_follow_link,
 	.put_link		= xfs_vn_put_link,
diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h
index cc0f7b3..bbb83d7 100644
--- a/fs/xfs/linux-2.6/xfs_linux.h
+++ b/fs/xfs/linux-2.6/xfs_linux.h
@@ -51,7 +51,6 @@
 #include <support/debug.h>
 #include <support/uuid.h>
 
-#include <linux/semaphore.h>
 #include <linux/mm.h>
 #include <linux/kernel.h>
 #include <linux/blkdev.h>
@@ -180,6 +179,8 @@
 #define xfs_itruncate_data(ip, off)	\
 	(-vmtruncate(VFS_I(ip), (off)))
 
+#include <linux/net.h>
+#define random32() net_random()
 
 /* Move the kernel do_div definition off to one side */
 
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c
index 1957e53..617788f 100644
--- a/fs/xfs/linux-2.6/xfs_lrw.c
+++ b/fs/xfs/linux-2.6/xfs_lrw.c
@@ -256,7 +256,7 @@ xfs_read(
 				(void *)iovp, segs, *offset, ioflags);
 
 	iocb->ki_pos = *offset;
-	ret = generic_file_aio_read(iocb, iovp, segs, *offset);
+	ret = __generic_file_aio_read(iocb, iovp, segs, offset);
 	if (ret == -EIOCBQUEUED && !(ioflags & IO_ISAIO))
 		ret = wait_on_sync_kiocb(iocb);
 	if (ret > 0)
@@ -668,14 +668,8 @@ start:
 	if (new_size > xip->i_size)
 		xip->i_new_size = new_size;
 
-	/*
-	 * We're not supposed to change timestamps in readonly-mounted
-	 * filesystems.  Throw it away if anyone asks us.
-	 */
-	if (likely(!(ioflags & IO_INVIS) &&
-		   !mnt_want_write(file->f_path.mnt))) {
+	if (likely(!(ioflags & IO_INVIS))) {
 		xfs_ichgtime(xip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-		mnt_drop_write(file->f_path.mnt);
 	}
 
 	/*
@@ -709,7 +703,7 @@ start:
 	     !capable(CAP_FSETID)) {
 		error = xfs_write_clear_setuid(xip);
 		if (likely(!error))
-			error = -file_remove_suid(file);
+			error = -remove_suid(file->f_dentry);
 		if (unlikely(error)) {
 			goto out_unlock_internal;
 		}
diff --git a/fs/xfs/linux-2.6/xfs_lrw.h b/fs/xfs/linux-2.6/xfs_lrw.h
index e6be37d..4ae0a55 100644
--- a/fs/xfs/linux-2.6/xfs_lrw.h
+++ b/fs/xfs/linux-2.6/xfs_lrw.h
@@ -50,6 +50,7 @@ struct xfs_iomap;
 #define	XFS_INVAL_CACHED	18
 #define	XFS_DIORD_ENTER		19
 #define	XFS_DIOWR_ENTER		20
+#define XFS_SENDFILE_ENTER	21
 #define	XFS_WRITEPAGE_ENTER	22
 #define	XFS_RELEASEPAGE_ENTER	23
 #define	XFS_INVALIDPAGE_ENTER	24
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index 37ebe36..ab10491 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -65,7 +65,6 @@
 #include <linux/mempool.h>
 #include <linux/writeback.h>
 #include <linux/kthread.h>
-#include <linux/freezer.h>
 #include <linux/parser.h>
 
 static struct quotactl_ops xfs_quotactl_operations;
@@ -158,7 +157,7 @@ enum {
 	Opt_barrier, Opt_nobarrier, Opt_err
 };
 
-static const match_table_t tokens = {
+static match_table_t tokens = {
 	{Opt_barrier, "barrier"},
 	{Opt_nobarrier, "nobarrier"},
 	{Opt_err, NULL}
@@ -589,7 +588,7 @@ xfs_blkdev_get(
 {
 	int			error = 0;
 
-	*bdevp = open_bdev_exclusive(name, FMODE_READ|FMODE_WRITE, mp);
+	*bdevp = open_bdev_excl(name, 0, mp);
 	if (IS_ERR(*bdevp)) {
 		error = PTR_ERR(*bdevp);
 		printk("XFS: Invalid device [%s], error=%d\n", name, error);
@@ -603,7 +602,7 @@ xfs_blkdev_put(
 	struct block_device	*bdev)
 {
 	if (bdev)
-		close_bdev_exclusive(bdev, FMODE_READ|FMODE_WRITE);
+		close_bdev_excl(bdev);
 }
 
 /*
@@ -882,9 +881,13 @@ xfs_fs_destroy_inode(
 
 STATIC void
 xfs_fs_inode_init_once(
-	void			*vnode)
+	void			*vnode,
+	kmem_zone_t		*zonep,
+	unsigned long		flags)
 {
-	inode_init_once((struct inode *)vnode);
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+		      SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once((struct inode *)vnode);
 }
 
 /*
@@ -1044,7 +1047,6 @@ xfssyncd(
 	bhv_vfs_sync_work_t	*work, *n;
 	LIST_HEAD		(tmp);
 
-	set_freezable();
 	timeleft = xfs_syncd_centisecs * msecs_to_jiffies(10);
 	for (;;) {
 		timeleft = schedule_timeout_interruptible(timeleft);
@@ -1866,7 +1868,7 @@ static struct file_system_type xfs_fs_type = {
 	.name			= "xfs",
 	.get_sb			= xfs_fs_get_sb,
 	.kill_sb		= kill_block_super,
-	.fs_flags		= FS_REQUIRES_DEV,
+	.fs_flags		= FS_REQUIRES_DEV|FS_HAS_FALLOCATE,
 };
 
 STATIC int __init
diff --git a/fs/xfs/linux-2.6/xfs_super.h b/fs/xfs/linux-2.6/xfs_super.h
index fe2ef4e..2de6c31 100644
--- a/fs/xfs/linux-2.6/xfs_super.h
+++ b/fs/xfs/linux-2.6/xfs_super.h
@@ -18,8 +18,6 @@
 #ifndef __XFS_SUPER_H__
 #define __XFS_SUPER_H__
 
-#include <linux/exportfs.h>
-
 #ifdef CONFIG_XFS_DMAPI
 # define vfs_insertdmapi(vfs)	vfs_insertops(vfsp, &xfs_dmops)
 # define vfs_initdmapi()	dmapi_init()
@@ -106,7 +104,7 @@ extern void xfs_flush_device(struct xfs_inode *);
 
 extern void xfs_blkdev_issue_flush(struct xfs_buftarg *);
 
-extern const struct export_operations xfs_export_operations;
+extern struct export_operations xfs_export_operations;
 extern struct xattr_handler *xfs_xattr_handlers[];
 
 #define XFS_M(sb)		((struct xfs_mount *)((sb)->s_fs_info))
diff --git a/fs/xfs/linux-2.6/xfs_sysctl.c b/fs/xfs/linux-2.6/xfs_sysctl.c
index 7dacb5b..6e76594 100644
--- a/fs/xfs/linux-2.6/xfs_sysctl.c
+++ b/fs/xfs/linux-2.6/xfs_sysctl.c
@@ -262,7 +262,7 @@ static ctl_table xfs_root_table[] = {
 int
 xfs_sysctl_register(void)
 {
-	xfs_table_header = register_sysctl_table(xfs_root_table);
+	xfs_table_header = register_sysctl_table(xfs_root_table, 1);
 	if (!xfs_table_header)
 		return -ENOMEM;
 	return 0;
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
index df0ffef..e9b1f6a 100644
--- a/fs/xfs/quota/xfs_qm.c
+++ b/fs/xfs/quota/xfs_qm.c
@@ -62,6 +62,7 @@ uint		ndquot;
 
 kmem_zone_t	*qm_dqzone;
 kmem_zone_t	*qm_dqtrxzone;
+static struct shrinker *xfs_qm_shaker;
 
 static cred_t	xfs_zerocr;
 
@@ -77,11 +78,6 @@ STATIC int	xfs_qm_init_quotainos(xfs_mount_t *);
 STATIC int	xfs_qm_init_quotainfo(xfs_mount_t *);
 STATIC int	xfs_qm_shake(int, gfp_t);
 
-static struct shrinker xfs_qm_shaker = {
-	.shrink = xfs_qm_shake,
-	.seeks = DEFAULT_SEEKS,
-};
-
 #ifdef DEBUG
 extern mutex_t	qcheck_lock;
 #endif
@@ -154,7 +150,7 @@ xfs_Gqm_init(void)
 	} else
 		xqm->qm_dqzone = qm_dqzone;
 
-	register_shrinker(&xfs_qm_shaker);
+	xfs_qm_shaker = set_shrinker(DEFAULT_SEEKS, xfs_qm_shake);
 
 	/*
 	 * The t_dqinfo portion of transactions.
@@ -186,7 +182,7 @@ xfs_qm_destroy(
 
 	ASSERT(xqm != NULL);
 	ASSERT(xqm->qm_nrefs == 0);
-	unregister_shrinker(&xfs_qm_shaker);
+	remove_shrinker(xfs_qm_shaker);
 	hsize = xqm->qm_dqhashmask + 1;
 	for (i = 0; i < hsize; i++) {
 		xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i]));
diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c
index 75b0cd4..9b26919 100644
--- a/fs/xfs/xfs_dfrag.c
+++ b/fs/xfs/xfs_dfrag.c
@@ -91,8 +91,8 @@ xfs_swapext(
 		goto out_put_target_file;
 	}
 
-	ip = XFS_I(file->f_path.dentry->d_inode);
-	tip = XFS_I(target_file->f_path.dentry->d_inode);
+	ip = XFS_I(file->f_dentry->d_inode);
+	tip = XFS_I(target_file->f_dentry->d_inode);
 
 	if (ip->i_mount != tip->i_mount) {
 		error = XFS_ERROR(EINVAL);
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index a391b95..2c1f102 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -580,8 +580,8 @@ xfs_iformat_extents(
 		xfs_validate_extents(ifp, nex, XFS_EXTFMT_INODE(ip));
 		for (i = 0; i < nex; i++, dp++) {
 			xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i);
-			ep->l0 = get_unaligned_be64(&dp->l0);
-			ep->l1 = get_unaligned_be64(&dp->l1);
+			ep->l0 = be64_to_cpu(get_unaligned(&dp->l0));
+			ep->l1 = be64_to_cpu(get_unaligned(&dp->l1));
 		}
 		XFS_BMAP_TRACE_EXLIST(ip, nex, whichfork);
 		if (whichfork != XFS_DATA_FORK ||
@@ -1081,8 +1081,8 @@ xfs_ialloc(
 	ip->i_d.di_onlink = 0;
 	ip->i_d.di_nlink = nlink;
 	ASSERT(ip->i_d.di_nlink == nlink);
-	ip->i_d.di_uid = current_fsuid();
-	ip->i_d.di_gid = current_fsgid();
+	ip->i_d.di_uid = current->fsuid;
+	ip->i_d.di_gid = current->fsgid;
 	ip->i_d.di_projid = prid;
 	memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
 
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 15f5dd2..0c1a768 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -1948,6 +1948,9 @@ xfs_icsb_cpu_notify(
 	mp = (xfs_mount_t *)container_of(nfb, xfs_mount_t, m_icsb_notifier);
 	cntp = (xfs_icsb_cnts_t *)
 			per_cpu_ptr(mp->m_sb_cnts, (unsigned long)hcpu);
+#ifndef CPU_UP_PREPARE_FROZEN
+#define CPU_UP_PREPARE_FROZEN (CPU_UP_PREPARE | CPU_TASKS_FROZEN)
+#endif
 	switch (action) {
 	case CPU_UP_PREPARE:
 	case CPU_UP_PREPARE_FROZEN:
diff --git a/fs/xfs/xfs_mru_cache.c b/fs/xfs/xfs_mru_cache.c
index afee7eb..f9de4e4 100644
--- a/fs/xfs/xfs_mru_cache.c
+++ b/fs/xfs/xfs_mru_cache.c
@@ -274,10 +274,9 @@ _xfs_mru_cache_clear_reap_list(
  * at each interval whether there is anything we need to do.
  */
 STATIC void
-_xfs_mru_cache_reap(
-	struct work_struct	*work)
+_xfs_mru_cache_reap(void *data)
 {
-	xfs_mru_cache_t		*mru = container_of(work, xfs_mru_cache_t, work.work);
+	xfs_mru_cache_t		*mru = data;
 	unsigned long		now, next;
 
 	ASSERT(mru && mru->lists);
@@ -376,7 +375,7 @@ xfs_mru_cache_create(
 	INIT_RADIX_TREE(&mru->store, GFP_ATOMIC);
 	INIT_LIST_HEAD(&mru->reap_list);
 	spin_lock_init(&mru->lock);
-	INIT_DELAYED_WORK(&mru->work, _xfs_mru_cache_reap);
+	INIT_WORK(&mru->work, _xfs_mru_cache_reap, mru);
 
 	mru->grp_time  = grp_time;
 	mru->free_func = free_func;
@@ -408,7 +407,10 @@ xfs_mru_cache_flush(
 	spin_lock(&mru->lock);
 	if (mru->queued) {
 		spin_unlock(&mru->lock);
-		cancel_rearming_delayed_workqueue(xfs_mru_reap_wq, &mru->work);
+		/* HACK: cancel_rearming_delayed_work live-locks
+		   if no work pending */
+		if (delayed_work_pending(&mru->work))
+			cancel_rearming_delayed_workqueue(xfs_mru_reap_wq, &mru->work);
 		spin_lock(&mru->lock);
 	}
 
diff --git a/fs/xfs/xfs_mru_cache.h b/fs/xfs/xfs_mru_cache.h
index dd58ea1..2d195eb 100644
--- a/fs/xfs/xfs_mru_cache.h
+++ b/fs/xfs/xfs_mru_cache.h
@@ -33,7 +33,7 @@ typedef struct xfs_mru_cache
 	unsigned int		lru_grp;   /* Group containing time zero.   */
 	unsigned long		time_zero; /* Time first element was added. */
 	xfs_mru_cache_free_func_t free_func; /* Function pointer for freeing. */
-	struct delayed_work	work;      /* Workqueue data for reaping.   */
+	struct work_struct	work;      /* Workqueue data for reaping.   */
 	unsigned int		queued;	   /* work has been queued */
 } xfs_mru_cache_t;
 
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 8b6812f..3bc89c8 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -182,7 +182,7 @@ xfs_setattr(
 	xfs_ilock(ip, lock_flags);
 
 	/* boolean: are we the file owner? */
-	file_owner = (current_fsuid() == ip->i_d.di_uid);
+	file_owner = (current->fsuid == ip->i_d.di_uid);
 
 	/*
 	 * Change various properties of a file.
@@ -1533,7 +1533,7 @@ xfs_create(
 	 * Make sure that we have allocated dquot(s) on disk.
 	 */
 	error = XFS_QM_DQVOPALLOC(mp, dp,
-			current_fsuid(), current_fsgid(), prid,
+			current->fsuid, current->fsgid, prid,
 			XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, &udqp, &gdqp);
 	if (error)
 		goto std_return;
@@ -2277,7 +2277,7 @@ xfs_mkdir(
 	 * Make sure that we have allocated dquot(s) on disk.
 	 */
 	error = XFS_QM_DQVOPALLOC(mp, dp,
-			current_fsuid(), current_fsgid(), prid,
+			current->fsuid, current->fsgid, prid,
 			XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
 	if (error)
 		goto std_return;
@@ -2503,7 +2503,7 @@ xfs_symlink(
 	 * Make sure that we have allocated dquot(s) on disk.
 	 */
 	error = XFS_QM_DQVOPALLOC(mp, dp,
-			current_fsuid(), current_fsgid(), prid,
+			current->fsuid, current->fsgid, prid,
 			XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
 	if (error)
 		goto std_return;