Sophie

Sophie

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

kernel-2.6.18-194.11.1.el5.src.rpm

From: Steve Dickson <SteveD@redhat.com>
Subject: [RHEL5.?] [PATCH] NFS4: umounts oops in shrink_dcache_for_umount
Date: Thu, 25 Oct 2007 13:31:16 -0400
Bugzilla: 254106
Message-Id: <4720D2E4.2090103@RedHat.com>
Changelog: [nfs] v4: umounts oops in shrink_dcache_for_umount


The attached patch is a back port of the following four
upstream patches that stops a BUG() in shrink_dcache_for_umount()
from popping when there is an outstanding reference on
a dentry:

NFSv4: Ensure that nfs4_do_close() doesn't race with umount
NFS: Replace vfsmount and dentry in nfs_open_context with struct path
NFSv4: Cleanup: pass the nfs_open_context to open recovery code
NFSv4: Ensure asynchronous open() calls always pin the mountpoint

This is a fairly large patch, touching 11 files, but the
changes are most cosmetic due to the addition of the path
structure in the nfs_open_context structure (i.e. the second
patch).

The path structure is need because there has to be a way
to pass around not only the dentry of the open file
but also the vfsmount the file is mounted on, so
both referenced.  This was the cause of the oops.
The open contexts were not keeping a reference on the
vfsmount pointer allowing the filesystem to be unmounted.

I was able to reproduce this oops with the tests/nfs-utils/bz254106
RHTS script which was written by Jan Hutar (from the Brno office).
This help immensely to find/fix this problem, nice work!

This patch fixes the following bugs:
    https://bugzilla.redhat.com/show_bug.cgi?id=218718
    https://bugzilla.redhat.com/show_bug.cgi?id=253663
    https://bugzilla.redhat.com/show_bug.cgi?id=254106

steved.

--- linux-2.6.18.i686/include/linux/nfs_fs.h.orig	2007-10-23 09:05:42.000000000 -0400
+++ linux-2.6.18.i686/include/linux/nfs_fs.h	2007-10-25 09:00:33.000000000 -0400
@@ -79,10 +79,14 @@ struct nfs_access_entry {
 };
 
 struct nfs4_state;
+
+struct path {
+	struct vfsmount *mnt;
+	struct dentry *dentry;
+};
 struct nfs_open_context {
 	atomic_t count;
-	struct vfsmount *vfsmnt;
-	struct dentry *dentry;
+	struct path path;
 	struct rpc_cred *cred;
 	struct nfs4_state *state;
 	fl_owner_t lockowner;
--- linux-2.6.18.i686/fs/nfs/read.c.orig	2007-10-23 09:05:46.000000000 -0400
+++ linux-2.6.18.i686/fs/nfs/read.c	2007-10-25 09:00:33.000000000 -0400
@@ -256,7 +256,7 @@ int nfs_readpage_async(struct nfs_open_c
 
 static void nfs_readpage_release(struct nfs_page *req)
 {
-	struct inode *d_inode = req->wb_context->dentry->d_inode;
+	struct inode *d_inode = req->wb_context->path.dentry->d_inode;
 
 	if (PageUptodate(req->wb_page))
 		nfs_readpage_to_fscache(d_inode, req->wb_page, 0);
@@ -264,8 +264,8 @@ static void nfs_readpage_release(struct 
 	unlock_page(req->wb_page);
 
 	dprintk("NFS: read done (%s/%Ld %d@%Ld)\n",
-			req->wb_context->dentry->d_inode->i_sb->s_id,
-			(long long)NFS_FILEID(req->wb_context->dentry->d_inode),
+			req->wb_context->path.dentry->d_inode->i_sb->s_id,
+			(long long)NFS_FILEID(req->wb_context->path.dentry->d_inode),
 			req->wb_bytes,
 			(long long)req_offset(req));
 	nfs_clear_request(req);
@@ -283,7 +283,7 @@ static void nfs_read_rpcsetup(struct nfs
 	int flags;
 
 	data->req	  = req;
-	data->inode	  = inode = req->wb_context->dentry->d_inode;
+	data->inode	  = inode = req->wb_context->path.dentry->d_inode;
 	data->cred	  = req->wb_context->cred;
 
 	data->args.fh     = NFS_FH(inode);
@@ -462,7 +462,7 @@ nfs_pagein_list(struct list_head *head, 
 	while (!list_empty(head)) {
 		pages += nfs_coalesce_requests(head, &one_request, rpages);
 		req = nfs_list_entry(one_request.next);
-		error = nfs_pagein_one(&one_request, req->wb_context->dentry->d_inode);
+		error = nfs_pagein_one(&one_request, req->wb_context->path.dentry->d_inode);
 		if (error < 0)
 			break;
 	}
--- linux-2.6.18.i686/fs/nfs/inode.c.orig	2007-10-25 08:56:25.000000000 -0400
+++ linux-2.6.18.i686/fs/nfs/inode.c	2007-10-25 09:00:33.000000000 -0400
@@ -450,8 +450,8 @@ static struct nfs_open_context *alloc_nf
 	ctx = (struct nfs_open_context *)kmalloc(sizeof(*ctx), GFP_KERNEL);
 	if (ctx != NULL) {
 		atomic_set(&ctx->count, 1);
-		ctx->dentry = dget(dentry);
-		ctx->vfsmnt = mntget(mnt);
+		ctx->path.dentry = dget(dentry);
+		ctx->path.mnt = mntget(mnt);
 		ctx->cred = get_rpccred(cred);
 		ctx->state = NULL;
 		ctx->lockowner = current->files;
@@ -472,17 +472,17 @@ void put_nfs_open_context(struct nfs_ope
 {
 	if (atomic_dec_and_test(&ctx->count)) {
 		if (!list_empty(&ctx->list)) {
-			struct inode *inode = ctx->dentry->d_inode;
+			struct inode *inode = ctx->path.dentry->d_inode;
 			spin_lock(&inode->i_lock);
 			list_del(&ctx->list);
 			spin_unlock(&inode->i_lock);
 		}
 		if (ctx->state != NULL)
-			nfs4_close_state(ctx->state, ctx->mode);
+			nfs4_close_state(&ctx->path, ctx->state, ctx->mode);
 		if (ctx->cred != NULL)
 			put_rpccred(ctx->cred);
-		dput(ctx->dentry);
-		mntput(ctx->vfsmnt);
+		dput(ctx->path.dentry);
+		mntput(ctx->path.mnt);
 		kfree(ctx);
 	}
 }
@@ -1045,27 +1045,10 @@ static int nfs_update_inode(struct inode
  */
 void nfs4_clear_inode(struct inode *inode)
 {
-	struct nfs_inode *nfsi = NFS_I(inode);
-
 	/* If we are holding a delegation, return it! */
 	nfs_inode_return_delegation(inode);
 	/* First call standard NFS clear_inode() code */
 	nfs_clear_inode(inode);
-	/* Now clear out any remaining state */
-	while (!list_empty(&nfsi->open_states)) {
-		struct nfs4_state *state;
-		
-		state = list_entry(nfsi->open_states.next,
-				struct nfs4_state,
-				inode_states);
-		dprintk("%s(%s/%Ld): found unclaimed NFSv4 state %p\n",
-				__FUNCTION__,
-				inode->i_sb->s_id,
-				(long long)NFS_FILEID(inode),
-				state);
-		BUG_ON(atomic_read(&state->count) != 1);
-		nfs4_close_state(state, state->state);
-	}
 }
 #endif
 
--- linux-2.6.18.i686/fs/nfs/delegation.c.orig	2007-10-25 07:57:12.000000000 -0400
+++ linux-2.6.18.i686/fs/nfs/delegation.c	2007-10-25 09:00:33.000000000 -0400
@@ -79,7 +79,7 @@ again:
 			continue;
 		get_nfs_open_context(ctx);
 		spin_unlock(&inode->i_lock);
-		err = nfs4_open_delegation_recall(ctx->dentry, state);
+		err = nfs4_open_delegation_recall(ctx, state);
 		if (err >= 0)
 			err = nfs_delegation_claim_locks(ctx, state);
 		put_nfs_open_context(ctx);
--- linux-2.6.18.i686/fs/nfs/write.c.orig	2007-10-23 09:05:42.000000000 -0400
+++ linux-2.6.18.i686/fs/nfs/write.c	2007-10-25 09:00:33.000000000 -0400
@@ -447,7 +447,7 @@ static int nfs_inode_add_request(struct 
  */
 static void nfs_inode_remove_request(struct nfs_page *req)
 {
-	struct inode *inode = req->wb_context->dentry->d_inode;
+	struct inode *inode = req->wb_context->path.dentry->d_inode;
 	struct nfs_inode *nfsi = NFS_I(inode);
 
 	BUG_ON (!NFS_WBACK_BUSY(req));
@@ -499,7 +499,7 @@ nfs_find_request(struct inode *inode, un
 static void
 nfs_mark_request_dirty(struct nfs_page *req)
 {
-	struct inode *inode = req->wb_context->dentry->d_inode;
+	struct inode *inode = req->wb_context->path.dentry->d_inode;
 	struct nfs_inode *nfsi = NFS_I(inode);
 
 	spin_lock(&nfsi->req_lock);
@@ -518,7 +518,7 @@ nfs_mark_request_dirty(struct nfs_page *
 static inline int
 nfs_dirty_request(struct nfs_page *req)
 {
-	struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode);
+	struct nfs_inode *nfsi = NFS_I(req->wb_context->path.dentry->d_inode);
 	return !list_empty(&req->wb_list) && req->wb_list_head == &nfsi->dirty;
 }
 
@@ -529,7 +529,7 @@ nfs_dirty_request(struct nfs_page *req)
 static void
 nfs_mark_request_commit(struct nfs_page *req)
 {
-	struct inode *inode = req->wb_context->dentry->d_inode;
+	struct inode *inode = req->wb_context->path.dentry->d_inode;
 	struct nfs_inode *nfsi = NFS_I(inode);
 
 	spin_lock(&nfsi->req_lock);
@@ -959,7 +959,7 @@ static void nfs_write_rpcsetup(struct nf
 	 * NB: take care not to mess about with data->commit et al. */
 
 	data->req = req;
-	data->inode = inode = req->wb_context->dentry->d_inode;
+	data->inode = inode = req->wb_context->path.dentry->d_inode;
 	data->cred = req->wb_context->cred;
 
 	data->args.fh     = NFS_FH(inode);
@@ -1159,8 +1159,8 @@ static void nfs_writeback_done_partial(s
 	struct page		*page = req->wb_page;
 
 	dprintk("NFS: write (%s/%Ld %d@%Ld)",
-		req->wb_context->dentry->d_inode->i_sb->s_id,
-		(long long)NFS_FILEID(req->wb_context->dentry->d_inode),
+		req->wb_context->path.dentry->d_inode->i_sb->s_id,
+		(long long)NFS_FILEID(req->wb_context->path.dentry->d_inode),
 		req->wb_bytes,
 		(long long)req_offset(req));
 
@@ -1220,8 +1220,8 @@ static void nfs_writeback_done_full(stru
 		page = req->wb_page;
 
 		dprintk("NFS: write (%s/%Ld %d@%Ld)",
-			req->wb_context->dentry->d_inode->i_sb->s_id,
-			(long long)NFS_FILEID(req->wb_context->dentry->d_inode),
+			req->wb_context->path.dentry->d_inode->i_sb->s_id,
+			(long long)NFS_FILEID(req->wb_context->path.dentry->d_inode),
 			req->wb_bytes,
 			(long long)req_offset(req));
 
@@ -1356,7 +1356,7 @@ static void nfs_commit_rpcsetup(struct l
 
 	list_splice_init(head, &data->pages);
 	first = nfs_list_entry(data->pages.next);
-	inode = first->wb_context->dentry->d_inode;
+	inode = first->wb_context->path.dentry->d_inode;
 
 	data->inode	  = inode;
 	data->cred	  = first->wb_context->cred;
@@ -1432,8 +1432,8 @@ static void nfs_commit_done(struct rpc_t
 		dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
 
 		dprintk("NFS: commit (%s/%Ld %d@%Ld)",
-			req->wb_context->dentry->d_inode->i_sb->s_id,
-			(long long)NFS_FILEID(req->wb_context->dentry->d_inode),
+			req->wb_context->path.dentry->d_inode->i_sb->s_id,
+			(long long)NFS_FILEID(req->wb_context->path.dentry->d_inode),
 			req->wb_bytes,
 			(long long)req_offset(req));
 		if (task->tk_status < 0) {
--- linux-2.6.18.i686/fs/nfs/delegation.h.orig	2007-10-24 15:36:40.000000000 -0400
+++ linux-2.6.18.i686/fs/nfs/delegation.h	2007-10-25 09:00:33.000000000 -0400
@@ -39,7 +39,7 @@ void nfs_delegation_reap_unclaimed(struc
 
 /* NFSv4 delegation-related procedures */
 int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid);
-int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state);
+int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state);
 int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl);
 int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode);
 
--- linux-2.6.18.i686/fs/nfs/direct.c.orig	2007-10-23 09:05:46.000000000 -0400
+++ linux-2.6.18.i686/fs/nfs/direct.c	2007-10-25 09:00:33.000000000 -0400
@@ -266,7 +266,7 @@ static const struct rpc_call_ops nfs_rea
 static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos)
 {
 	struct nfs_open_context *ctx = dreq->ctx;
-	struct inode *inode = ctx->dentry->d_inode;
+	struct inode *inode = ctx->path.dentry->d_inode;
 	size_t rsize = NFS_SERVER(inode)->rsize;
 	unsigned int pgbase;
 	int result;
@@ -602,7 +602,7 @@ static const struct rpc_call_ops nfs_wri
 static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos, int sync)
 {
 	struct nfs_open_context *ctx = dreq->ctx;
-	struct inode *inode = ctx->dentry->d_inode;
+	struct inode *inode = ctx->path.dentry->d_inode;
 	size_t wsize = NFS_SERVER(inode)->wsize;
 	unsigned int pgbase;
 	int result;
--- linux-2.6.18.i686/fs/nfs/nfs4state.c.orig	2007-10-23 09:05:35.000000000 -0400
+++ linux-2.6.18.i686/fs/nfs/nfs4state.c	2007-10-25 09:00:33.000000000 -0400
@@ -341,7 +341,7 @@ void nfs4_put_open_state(struct nfs4_sta
 /*
  * Close the current file.
  */
-void nfs4_close_state(struct nfs4_state *state, mode_t mode)
+void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode)
 {
 	struct inode *inode = state->inode;
 	struct nfs4_state_owner *owner = state->owner;
@@ -375,7 +375,7 @@ void nfs4_close_state(struct nfs4_state 
 	spin_unlock(&inode->i_lock);
 	spin_unlock(&owner->so_lock);
 
-	if (oldstate != newstate && nfs4_do_close(inode, state) == 0)
+	if (oldstate != newstate && nfs4_do_close(path, state) == 0)
 		return;
 	nfs4_put_open_state(state);
 	nfs4_put_state_owner(owner);
--- linux-2.6.18.i686/fs/nfs/nfs4proc.c.orig	2007-10-25 08:59:54.000000000 -0400
+++ linux-2.6.18.i686/fs/nfs/nfs4proc.c	2007-10-25 09:00:33.000000000 -0400
@@ -221,7 +221,7 @@ struct nfs4_opendata {
 	struct nfs_open_confirmres c_res;
 	struct nfs_fattr f_attr;
 	struct nfs_fattr dir_attr;
-	struct dentry *dentry;
+	struct path path;
 	struct dentry *dir;
 	struct nfs4_state_owner *owner;
 	struct iattr attrs;
@@ -230,11 +230,11 @@ struct nfs4_opendata {
 	int cancelled;
 };
 
-static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
+static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
 		struct nfs4_state_owner *sp, int flags,
 		const struct iattr *attrs)
 {
-	struct dentry *parent = dget_parent(dentry);
+	struct dentry *parent = dget_parent(path->dentry);
 	struct inode *dir = parent->d_inode;
 	struct nfs_server *server = NFS_SERVER(dir);
 	struct nfs4_opendata *p;
@@ -246,7 +246,8 @@ static struct nfs4_opendata *nfs4_openda
 	if (p->o_arg.seqid == NULL)
 		goto err_free;
 	atomic_set(&p->count, 1);
-	p->dentry = dget(dentry);
+	p->path.mnt = mntget(path->mnt);
+	p->path.dentry = dget(path->dentry);
 	p->dir = parent;
 	p->owner = sp;
 	atomic_inc(&sp->so_count);
@@ -254,7 +255,7 @@ static struct nfs4_opendata *nfs4_openda
 	p->o_arg.open_flags = flags,
 	p->o_arg.clientid = server->nfs_client->cl_clientid;
 	p->o_arg.id = sp->so_id;
-	p->o_arg.name = &dentry->d_name;
+	p->o_arg.name = &p->path.dentry->d_name;
 	p->o_arg.server = server;
 	p->o_arg.bitmask = server->attr_bitmask;
 	p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
@@ -288,7 +289,8 @@ static void nfs4_opendata_free(struct nf
 		nfs_free_seqid(p->o_arg.seqid);
 		nfs4_put_state_owner(p->owner);
 		dput(p->dir);
-		dput(p->dentry);
+		dput(p->path.dentry);
+		mntput(p->path.mnt);
 		kfree(p);
 	}
 }
@@ -451,7 +453,7 @@ static int nfs4_open_recover(struct nfs4
 						opendata->owner->so_cred,
 						&opendata->o_res);
 		}
-		nfs4_close_state(newstate, opendata->o_arg.open_flags);
+		nfs4_close_state(&opendata->path, newstate, opendata->o_arg.open_flags);
 	}
 	if (newstate != state)
 		return -ESTALE;
@@ -462,7 +464,7 @@ static int nfs4_open_recover(struct nfs4
  * OPEN_RECLAIM:
  * 	reclaim state on the server after a reboot.
  */
-static int _nfs4_do_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry)
+static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state)
 {
 	struct nfs_delegation *delegation = NFS_I(state->inode)->delegation;
 	struct nfs4_opendata *opendata;
@@ -478,7 +480,7 @@ static int _nfs4_do_open_reclaim(struct 
 		}
 		delegation_type = delegation->type;
 	}
-	opendata = nfs4_opendata_alloc(dentry, sp, 0, NULL);
+	opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL);
 	if (opendata == NULL)
 		return -ENOMEM;
 	opendata->o_arg.claim = NFS4_OPEN_CLAIM_PREVIOUS;
@@ -490,13 +492,13 @@ static int _nfs4_do_open_reclaim(struct 
 	return status;
 }
 
-static int nfs4_do_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry)
+static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state)
 {
 	struct nfs_server *server = NFS_SERVER(state->inode);
 	struct nfs4_exception exception = { };
 	int err;
 	do {
-		err = _nfs4_do_open_reclaim(sp, state, dentry);
+		err = _nfs4_do_open_reclaim(ctx, state);
 		if (err != -NFS4ERR_DELAY)
 			break;
 		nfs4_handle_exception(server, err, &exception);
@@ -512,12 +514,12 @@ static int nfs4_open_reclaim(struct nfs4
 	ctx = nfs4_state_find_open_context(state);
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
-	ret = nfs4_do_open_reclaim(sp, state, ctx->dentry);
+	ret = nfs4_do_open_reclaim(ctx, state);
 	put_nfs_open_context(ctx);
 	return ret;
 }
 
-static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state)
+static int _nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state)
 {
 	struct nfs4_state_owner  *sp  = state->owner;
 	struct nfs4_opendata *opendata;
@@ -525,7 +527,7 @@ static int _nfs4_open_delegation_recall(
 
 	if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
 		return 0;
-	opendata = nfs4_opendata_alloc(dentry, sp, 0, NULL);
+	opendata = nfs4_opendata_alloc(&ctx->path, sp, 0, NULL);
 	if (opendata == NULL)
 		return -ENOMEM;
 	opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR;
@@ -536,13 +538,13 @@ static int _nfs4_open_delegation_recall(
 	return ret;
 }
 
-int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state)
+int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state)
 {
 	struct nfs4_exception exception = { };
-	struct nfs_server *server = NFS_SERVER(dentry->d_inode);
+	struct nfs_server *server = NFS_SERVER(state->inode);
 	int err;
 	do {
-		err = _nfs4_open_delegation_recall(dentry, state);
+		err = _nfs4_open_delegation_recall(ctx, state);
 		switch (err) {
 			case 0:
 				return err;
@@ -601,7 +603,7 @@ static void nfs4_open_confirm_release(vo
 	nfs_confirm_seqid(&data->owner->so_seqid, 0);
 	state = nfs4_opendata_to_nfs4_state(data);
 	if (state != NULL)
-		nfs4_close_state(state, data->o_arg.open_flags);
+		nfs4_close_state(&data->path, state, data->o_arg.open_flags);
 out_free:
 	nfs4_opendata_free(data);
 }
@@ -704,7 +706,7 @@ static void nfs4_open_release(void *call
 	nfs_confirm_seqid(&data->owner->so_seqid, 0);
 	state = nfs4_opendata_to_nfs4_state(data);
 	if (state != NULL)
-		nfs4_close_state(state, data->o_arg.open_flags);
+		nfs4_close_state(&data->path, state, data->o_arg.open_flags);
 out_free:
 	nfs4_opendata_free(data);
 }
@@ -804,7 +806,7 @@ int nfs4_recover_expired_lease(struct nf
  * 	reclaim state on the server after a network partition.
  * 	Assumes caller holds the appropriate lock
  */
-static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry)
+static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state)
 {
 	struct inode *inode = state->inode;
 	struct nfs_delegation *delegation = NFS_I(inode)->delegation;
@@ -813,34 +815,34 @@ static int _nfs4_open_expired(struct nfs
 	int ret;
 
 	if (delegation != NULL && !(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) {
-		ret = _nfs4_do_access(inode, sp->so_cred, openflags);
+		ret = _nfs4_do_access(inode, ctx->cred, openflags);
 		if (ret < 0)
 			return ret;
 		memcpy(&state->stateid, &delegation->stateid, sizeof(state->stateid));
 		set_bit(NFS_DELEGATED_STATE, &state->flags);
 		return 0;
 	}
-	opendata = nfs4_opendata_alloc(dentry, sp, openflags, NULL);
+	opendata = nfs4_opendata_alloc(&ctx->path, state->owner, openflags, NULL);
 	if (opendata == NULL)
 		return -ENOMEM;
 	ret = nfs4_open_recover(opendata, state);
 	if (ret == -ESTALE) {
 		/* Invalidate the state owner so we don't ever use it again */
-		nfs4_drop_state_owner(sp);
-		d_drop(dentry);
+		nfs4_drop_state_owner(state->owner);
+		d_drop(ctx->path.dentry);
 	}
 	nfs4_opendata_free(opendata);
 	return ret;
 }
 
-static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry)
+static inline int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state)
 {
-	struct nfs_server *server = NFS_SERVER(dentry->d_inode);
+	struct nfs_server *server = NFS_SERVER(state->inode);
 	struct nfs4_exception exception = { };
 	int err;
 
 	do {
-		err = _nfs4_open_expired(sp, state, dentry);
+		err = _nfs4_open_expired(ctx, state);
 		if (err == -NFS4ERR_DELAY)
 			nfs4_handle_exception(server, err, &exception);
 	} while (exception.retry);
@@ -855,7 +857,7 @@ static int nfs4_open_expired(struct nfs4
 	ctx = nfs4_state_find_open_context(state);
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
-	ret = nfs4_do_open_expired(sp, state, ctx->dentry);
+	ret = nfs4_do_open_expired(ctx, state);
 	put_nfs_open_context(ctx);
 	return ret;
 }
@@ -948,7 +950,7 @@ static struct nfs4_state *nfs4_open_dele
 /*
  * Returns a referenced nfs4_state
  */
-static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res)
+static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res)
 {
 	struct nfs4_state_owner  *sp;
 	struct nfs4_state     *state = NULL;
@@ -968,7 +970,7 @@ static int _nfs4_do_open(struct inode *d
 		goto err_put_state_owner;
 	down_read(&clp->cl_sem);
 	status = -ENOMEM;
-	opendata = nfs4_opendata_alloc(dentry, sp, flags, sattr);
+	opendata = nfs4_opendata_alloc(path, sp, flags, sattr);
 	if (opendata == NULL)
 		goto err_release_rwsem;
 
@@ -999,14 +1001,14 @@ out_err:
 }
 
 
-static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred)
+static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred)
 {
 	struct nfs4_exception exception = { };
 	struct nfs4_state *res;
 	int status;
 
 	do {
-		status = _nfs4_do_open(dir, dentry, flags, sattr, cred, &res);
+		status = _nfs4_do_open(dir, path, flags, sattr, cred, &res);
 		if (status == 0)
 			break;
 		/* NOTE: BAD_SEQID means the server and client disagree about the
@@ -1094,6 +1096,7 @@ static int nfs4_do_setattr(struct inode 
 }
 
 struct nfs4_closedata {
+	struct path path;
 	struct inode *inode;
 	struct nfs4_state *state;
 	struct nfs_closeargs arg;
@@ -1110,6 +1113,8 @@ static void nfs4_free_closedata(void *da
 	nfs4_put_open_state(calldata->state);
 	nfs_free_seqid(calldata->arg.seqid);
 	nfs4_put_state_owner(sp);
+	dput(calldata->path.dentry);
+	mntput(calldata->path.mnt);
 	kfree(calldata);
 }
 
@@ -1203,18 +1208,18 @@ static const struct rpc_call_ops nfs4_cl
  *
  * NOTE: Caller must be holding the sp->so_owner semaphore!
  */
-int nfs4_do_close(struct inode *inode, struct nfs4_state *state) 
+int nfs4_do_close(struct path *path, struct nfs4_state *state)
 {
-	struct nfs_server *server = NFS_SERVER(inode);
+	struct nfs_server *server = NFS_SERVER(state->inode);
 	struct nfs4_closedata *calldata;
 	int status = -ENOMEM;
 
 	calldata = kmalloc(sizeof(*calldata), GFP_KERNEL);
 	if (calldata == NULL)
 		goto out;
-	calldata->inode = inode;
+	calldata->inode = state->inode;
 	calldata->state = state;
-	calldata->arg.fh = NFS_FH(inode);
+	calldata->arg.fh = NFS_FH(state->inode);
 	calldata->arg.stateid = &state->stateid;
 	/* Serialization for the sequence id */
 	calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid);
@@ -1223,6 +1228,8 @@ int nfs4_do_close(struct inode *inode, s
 	calldata->arg.bitmask = server->attr_bitmask;
 	calldata->res.fattr = &calldata->fattr;
 	calldata->res.server = server;
+	calldata->path.mnt = mntget(path->mnt);
+	calldata->path.dentry = dget(path->dentry);
 
 	status = nfs4_call_async(server->client, &nfs4_close_ops, calldata);
 	if (status == 0)
@@ -1235,24 +1242,28 @@ out:
 	return status;
 }
 
-static int nfs4_intent_set_file(struct nameidata *nd, struct dentry *dentry, struct nfs4_state *state)
+static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct nfs4_state *state)
 {
 	struct file *filp;
 
-	filp = lookup_instantiate_filp(nd, dentry, NULL);
+	filp = lookup_instantiate_filp(nd, path->dentry, NULL);
 	if (!IS_ERR(filp)) {
 		struct nfs_open_context *ctx;
 		ctx = (struct nfs_open_context *)filp->private_data;
 		ctx->state = state;
 		return 0;
 	}
-	nfs4_close_state(state, nd->intent.open.flags);
+	nfs4_close_state(path, state, nd->intent.open.flags);
 	return PTR_ERR(filp);
 }
 
 struct dentry *
 nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 {
+	struct path path = {
+		.mnt = nd->mnt,
+		.dentry = dentry,
+	};
 	struct iattr attr;
 	struct rpc_cred *cred;
 	struct nfs4_state *state;
@@ -1271,7 +1282,7 @@ nfs4_atomic_open(struct inode *dir, stru
 	cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);
 	if (IS_ERR(cred))
 		return (struct dentry *)cred;
-	state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred);
+	state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred);
 	put_rpccred(cred);
 	if (IS_ERR(state)) {
 		if (PTR_ERR(state) == -ENOENT)
@@ -1281,13 +1292,17 @@ nfs4_atomic_open(struct inode *dir, stru
 	res = d_add_unique(dentry, igrab(state->inode));
 	if (res != NULL)
 		dentry = res;
-	nfs4_intent_set_file(nd, dentry, state);
+	nfs4_intent_set_file(nd, &path, state);
 	return res;
 }
 
 int
 nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, struct nameidata *nd)
 {
+	struct path path = {
+		.mnt = nd->mnt,
+		.dentry = dentry,
+	};
 	struct rpc_cred *cred;
 	struct nfs4_state *state;
 
@@ -1296,7 +1311,7 @@ nfs4_open_revalidate(struct inode *dir, 
 		return PTR_ERR(cred);
 	state = nfs4_open_delegated(dentry->d_inode, openflags, cred);
 	if (IS_ERR(state))
-		state = nfs4_do_open(dir, dentry, openflags, NULL, cred);
+		state = nfs4_do_open(dir, &path, openflags, NULL, cred);
 	put_rpccred(cred);
 	if (IS_ERR(state)) {
 		switch (PTR_ERR(state)) {
@@ -1314,10 +1329,10 @@ nfs4_open_revalidate(struct inode *dir, 
 		goto out_drop;
 	}
 	if (state->inode == dentry->d_inode) {
-		nfs4_intent_set_file(nd, dentry, state);
+		nfs4_intent_set_file(nd, &path, state);
 		return 1;
 	}
-	nfs4_close_state(state, openflags);
+	nfs4_close_state(&path, state, openflags);
 out_drop:
 	d_drop(dentry);
 	return 0;
@@ -1872,6 +1887,10 @@ static int
 nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
                  int flags, struct nameidata *nd)
 {
+	struct path path = {
+		.mnt = nd->mnt,
+		.dentry = dentry,
+	};
 	struct nfs4_state *state;
 	struct rpc_cred *cred;
 	int status = 0;
@@ -1881,7 +1900,7 @@ nfs4_proc_create(struct inode *dir, stru
 		status = PTR_ERR(cred);
 		goto out;
 	}
-	state = nfs4_do_open(dir, dentry, flags, sattr, cred);
+	state = nfs4_do_open(dir, &path, flags, sattr, cred);
 	put_rpccred(cred);
 	if (IS_ERR(state)) {
 		status = PTR_ERR(state);
@@ -1894,10 +1913,10 @@ nfs4_proc_create(struct inode *dir, stru
 		if (status == 0)
 			nfs_setattr_update_inode(state->inode, sattr);
 	}
-	if (status == 0 && nd != NULL && (nd->flags & LOOKUP_OPEN))
-		status = nfs4_intent_set_file(nd, dentry, state);
+	if (status == 0 && (nd->flags & LOOKUP_OPEN))
+		status = nfs4_intent_set_file(nd, &path, state);
 	else
-		nfs4_close_state(state, flags);
+		nfs4_close_state(&path, state, flags);
 out:
 	return status;
 }
@@ -3405,7 +3424,7 @@ static void nfs4_lock_done(struct rpc_ta
 		memcpy(data->lsp->ls_stateid.data, data->res.stateid.data,
 					sizeof(data->lsp->ls_stateid.data));
 		data->lsp->ls_flags |= NFS_LOCK_INITIALIZED;
-		renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), data->timestamp);
+		renew_lease(NFS_SERVER(data->ctx->path.dentry->d_inode), data->timestamp);
 	}
 	nfs_increment_lock_seqid(data->rpc_status, data->arg.lock_seqid);
 out:
--- linux-2.6.18.i686/fs/nfs/pagelist.c.orig	2007-10-23 09:05:35.000000000 -0400
+++ linux-2.6.18.i686/fs/nfs/pagelist.c	2007-10-25 09:00:33.000000000 -0400
@@ -120,7 +120,7 @@ void nfs_unlock_request(struct nfs_page 
  */
 int nfs_set_page_writeback_locked(struct nfs_page *req)
 {
-	struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode);
+	struct nfs_inode *nfsi = NFS_I(req->wb_context->path.dentry->d_inode);
 
 	if (!nfs_lock_request(req))
 		return 0;
@@ -133,7 +133,7 @@ int nfs_set_page_writeback_locked(struct
  */
 void nfs_clear_page_writeback(struct nfs_page *req)
 {
-	struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode);
+	struct nfs_inode *nfsi = NFS_I(req->wb_context->path.dentry->d_inode);
 
 	if (req->wb_page != NULL) {
 		spin_lock(&nfsi->req_lock);
@@ -204,7 +204,7 @@ static int nfs_wait_bit_interruptible(vo
 int
 nfs_wait_on_request(struct nfs_page *req)
 {
-        struct rpc_clnt	*clnt = NFS_CLIENT(req->wb_context->dentry->d_inode);
+	struct rpc_clnt *clnt = NFS_CLIENT(req->wb_context->path.dentry->d_inode);
 	sigset_t oldmask;
 	int ret = 0;
 
--- linux-2.6.18.i686/fs/nfs/nfs4_fs.h.orig	2007-10-23 09:05:35.000000000 -0400
+++ linux-2.6.18.i686/fs/nfs/nfs4_fs.h	2007-10-25 09:00:33.000000000 -0400
@@ -165,7 +165,7 @@ extern int nfs4_proc_setclientid(struct 
 extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *);
 extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *);
 extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *);
-extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state);
+extern int nfs4_do_close(struct path *path, struct nfs4_state *state);
 extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
 extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *);
 extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
@@ -196,7 +196,7 @@ extern void nfs4_put_state_owner(struct 
 extern void nfs4_drop_state_owner(struct nfs4_state_owner *);
 extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *);
 extern void nfs4_put_open_state(struct nfs4_state *);
-extern void nfs4_close_state(struct nfs4_state *, mode_t);
+extern void nfs4_close_state(struct path *, struct nfs4_state *, mode_t);
 extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t);
 extern void nfs4_schedule_state_recovery(struct nfs_client *);
 extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
@@ -222,7 +222,7 @@ extern struct svc_version nfs4_callback_
 
 #else
 
-#define nfs4_close_state(a, b) do { } while (0)
+#define nfs4_close_state(a, b, c) do { } while (0)
 
 #endif /* CONFIG_NFS_V4 */
 #endif /* __LINUX_FS_NFS_NFS4_FS.H */