From f5afcc47f9f00472d6c2b3f48127e02332cd457a Mon Sep 17 00:00:00 2001 From: Shehjar Tikoo Date: Fri, 1 Oct 2010 01:58:05 +0000 Subject: nfs3: Revalidate inode on receiving ESTALE on lookup Signed-off-by: Shehjar Tikoo Signed-off-by: Vijay Bellur BUG: 1756 (NFS must revalidate inode on first ESTALE on lookup) URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=1756 --- xlators/nfs/server/src/nfs3.c | 45 ++++++++++++++++++++++++++++++++++++++++++- xlators/nfs/server/src/nfs3.h | 7 +++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/xlators/nfs/server/src/nfs3.c b/xlators/nfs/server/src/nfs3.c index ad2b6581c3e..67af3ee2ad6 100644 --- a/xlators/nfs/server/src/nfs3.c +++ b/xlators/nfs/server/src/nfs3.c @@ -1025,6 +1025,41 @@ nfs3_lookup_reply (rpcsvc_request_t *req, nfsstat3 stat, struct nfs3_fh *newfh, } +int +nfs3_lookup_resume (void *carg); + + +int +nfs3_revalidate_lookup (nfs3_call_state_t *cs) +{ + int ret = -EFAULT; + char *oldresolventry = NULL; + + if (!cs) + return -1; + + gf_log (GF_NFS3, GF_LOG_DEBUG, "inode needs revalidation"); + inode_unlink (cs->resolvedloc.inode, cs->resolvedloc.parent, + cs->resolventry); + inode_unref (cs->resolvedloc.inode); + nfs_loc_wipe (&cs->resolvedloc); + + /* Store pointer to currently allocated resolventry because it gets over + * written in fh_resolve_and_resume. + */ + oldresolventry = cs->resolventry; + cs->revalidate = GF_NFS3_REVALIDATE; + ret = nfs3_fh_resolve_and_resume (cs, &cs->resolvefh, cs->resolventry, + nfs3_lookup_resume); + /* Allocated in the previous call to fh_resolve_and_resume using the + * same call_state. + */ + GF_FREE (oldresolventry); + + return ret; +} + + int nfs3svc_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, inode_t *inode, @@ -1043,11 +1078,18 @@ nfs3svc_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, nfs3_fh_build_child_fh (&cs->parent, buf, &newfh); xmit_res: + /* Only revalidate if it wasnt already a revalidation lookup. */ + if ((op_errno == ESTALE) && (!nfs3_is_revalidate_lookup (cs))) { + op_ret = nfs3_revalidate_lookup (cs); + if (op_ret < 0) + goto out; + } + nfs3_log_newfh_res (nfs_rpcsvc_request_xid (cs->req), "LOOKUP", status, op_errno, &newfh); nfs3_lookup_reply (cs->req, status, &newfh, buf, postparent); nfs3_call_state_wipe (cs); - +out: return 0; } @@ -1225,6 +1267,7 @@ nfs3_lookup (rpcsvc_request_t *req, struct nfs3_fh *fh, int fhlen, char *name) nfs3_volume_disabled_check (nfs3, vol, ret, out); nfs3_handle_call_state_init (nfs3, cs, req, vol, stat, nfs3err); + cs->revalidate = GF_NFS3_NONREVALIDATE; if (!nfs3_is_parentdir_entry (name)) ret = nfs3_fh_resolve_and_resume (cs, fh, name, nfs3_lookup_resume); diff --git a/xlators/nfs/server/src/nfs3.h b/xlators/nfs/server/src/nfs3.h index f7683eaa789..219c5ed4bde 100644 --- a/xlators/nfs/server/src/nfs3.h +++ b/xlators/nfs/server/src/nfs3.h @@ -134,6 +134,10 @@ struct nfs3_state { int fdcount; }; +typedef enum nfs3_revalidate { + GF_NFS3_REVALIDATE = 1, + GF_NFS3_NONREVALIDATE +} nfs3_revalidate_t; typedef int (*nfs3_resume_fn_t) (void *cs); /* Structure used to communicate state between a fop and its callback. @@ -197,8 +201,11 @@ struct nfs3_local { int hashidx; fd_t *resolve_dir_fd; char *resolventry; + nfs3_revalidate_t revalidate; }; +#define nfs3_is_revalidate_lookup(cst) ((cst)->revalidate == GF_NFS3_REVALIDATE) + typedef struct nfs3_local nfs3_call_state_t; /* Queue of ops waiting for open fop to return. */ -- cgit