From: NeilBrown <nfbrown@suse.com>
Subject: Ensure NFS doesn't block on dead server during unmount
Patch-mainline: NO - mainline is planing a different approach I think.
References: bnc#794529

We set a namei_data flag for unmount requests, and get NFS d_validate
to not try to validate dentries while the flag is set.  As we only want
to unmount, there is no really need to validate anything.

Acked-by: NeilBrown <neilb@suse.de>
Signed-off-by: Neil Brown <neilb@suse.de>

---
 fs/namespace.c        |    2 +-
 fs/nfs/dir.c          |    7 ++++++-
 include/linux/namei.h |    3 +++
 3 files changed, 10 insertions(+), 2 deletions(-)

--- linux-3.0-SLE11-SP2.orig/fs/namespace.c
+++ linux-3.0-SLE11-SP2/fs/namespace.c
@@ -1361,7 +1361,7 @@ SYSCALL_DEFINE2(umount, char __user *, n
 {
 	struct path path;
 	int retval;
-	int lookup_flags = 0;
+	int lookup_flags = LOOKUP_UMOUNT;
 
 	if (flags & ~(MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW))
 		return -EINVAL;
--- linux-3.0-SLE11-SP2.orig/fs/nfs/dir.c
+++ linux-3.0-SLE11-SP2/fs/nfs/dir.c
@@ -1107,6 +1107,10 @@ static int nfs_lookup_revalidate(struct
 	if (nd && (nd->flags & LOOKUP_RCU))
 		return -ECHILD;
 
+	if (nd && (nd->flags & LOOKUP_UMOUNT))
+		/* on unmount, assume all dentries are correct */
+		return 1;
+
 	parent = dget_parent(dentry);
 	dir = parent->d_inode;
 	nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE);
@@ -1138,7 +1142,8 @@ static int nfs_lookup_revalidate(struct
 	if (NFS_STALE(inode))
 		goto out_bad;
 
-	if (nd->last_type != LAST_NORM) {
+	if (nd && (nd->last_type != LAST_NORM ||
+		   (nd->flags & LOOKUP_JUMPED))) {
 		/* name not relevant, just inode */
 		error = nfs_revalidate_inode(NFS_SERVER(inode), inode);
 		if (error)
--- linux-3.0-SLE11-SP2.orig/include/linux/namei.h
+++ linux-3.0-SLE11-SP2/include/linux/namei.h
@@ -66,6 +66,9 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LA
 #define LOOKUP_JUMPED		0x1000
 #define LOOKUP_ROOT		0x2000
 #define LOOKUP_EMPTY		0x4000
+#define LOOKUP_UMOUNT		0x8000 /* Am unmounting, don't contact NFS
+					* server if at all possible.
+					*/
 
 extern int user_path_at(int, const char __user *, unsigned, struct path *);
 extern int user_path_at_empty(int, const char __user *, unsigned, struct path *, int *empty);
