summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKrishna Srinivas <ksriniva@redhat.com>2012-10-18 17:14:39 +0530
committerVijay Bellur <vbellur@redhat.com>2012-10-19 08:25:39 -0400
commit890eb31ca8c37c6e083a418824d0b2dec81b15f0 (patch)
tree4054804112f9ac6907985d4b040462684a03d519
parenta94be52f3fe058d29274a30948dc84f8848e1180 (diff)
nfs: do lookup on getattr after brick-status change
(ported from Jeff Darcy's upstream commit) By doing a lookup, we get a chance to do all of the self-heal checks that would occur if we were using native protocol, and return proper status if the self-heal fails. Best of all, we don't need to misrepresent times. BUG: 830134 Change-Id: I9f4f0ab58373c0a8d7a880cc96a29ece2cc4f668 Signed-off-by: Krishna Srinivas <ksriniva@redhat.com> Reviewed-on: https://code.engineering.redhat.com/gerrit/125 Reviewed-by: Vijay Bellur <vbellur@redhat.com> Tested-by: Vijay Bellur <vbellur@redhat.com>
-rw-r--r--xlators/nfs/server/src/nfs-common.c35
-rw-r--r--xlators/nfs/server/src/nfs-common.h3
-rw-r--r--xlators/nfs/server/src/nfs-fops.c40
-rw-r--r--xlators/nfs/server/src/nfs-mem-types.h1
-rw-r--r--xlators/nfs/server/src/nfs.c35
-rw-r--r--xlators/nfs/server/src/nfs.h6
-rw-r--r--xlators/nfs/server/src/nfs3.c32
-rw-r--r--xlators/nfs/server/src/nlm4.c59
8 files changed, 171 insertions, 40 deletions
diff --git a/xlators/nfs/server/src/nfs-common.c b/xlators/nfs/server/src/nfs-common.c
index ec76c294f01..af3057bdcef 100644
--- a/xlators/nfs/server/src/nfs-common.c
+++ b/xlators/nfs/server/src/nfs-common.c
@@ -434,3 +434,38 @@ nfs_hash_gfid (uuid_t gfid)
}
+void
+nfs_fix_generation (xlator_t *this, inode_t *inode)
+{
+ uint64_t raw_ctx = 0;
+ struct nfs_inode_ctx *ictx = NULL;
+ struct nfs_state *priv = NULL;
+ int ret = -1;
+
+ if (!inode) {
+ return;
+ }
+ priv = this->private;
+
+ if (inode_ctx_get(inode,this,&raw_ctx) == 0) {
+ ictx = (struct nfs_inode_ctx *)raw_ctx;
+ ictx->generation = priv->generation;
+ }
+ else {
+ ictx = GF_CALLOC (1, sizeof (struct nfs_inode_ctx),
+ gf_nfs_mt_inode_ctx);
+ if (!ictx) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "could not allocate nfs inode ctx");
+ return;
+ }
+ INIT_LIST_HEAD(&ictx->shares);
+ ictx->generation = priv->generation;
+ ret = inode_ctx_put (inode, this, (uint64_t)ictx);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "could not store nfs inode ctx");
+ return;
+ }
+ }
+}
diff --git a/xlators/nfs/server/src/nfs-common.h b/xlators/nfs/server/src/nfs-common.h
index 88fc1496176..f74bb3187cd 100644
--- a/xlators/nfs/server/src/nfs-common.h
+++ b/xlators/nfs/server/src/nfs-common.h
@@ -84,4 +84,7 @@ nfs_hash_gfid (uuid_t gfid);
extern int
nfs_gfid_loc_fill (inode_table_t *itable, uuid_t gfid, loc_t *loc, int how);
+
+void
+nfs_fix_generation (xlator_t *this, inode_t *inode);
#endif
diff --git a/xlators/nfs/server/src/nfs-fops.c b/xlators/nfs/server/src/nfs-fops.c
index 6e2b334842b..dfd09e35dd2 100644
--- a/xlators/nfs/server/src/nfs-fops.c
+++ b/xlators/nfs/server/src/nfs-fops.c
@@ -274,9 +274,6 @@ out:
} \
} while (0) \
-
-
-
/* Fops Layer Explained
* The fops layer has three types of functions. They can all be identified by
* their names. Here are the three patterns:
@@ -309,6 +306,23 @@ nfs_fop_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
{
struct nfs_fop_local *local = NULL;
fop_lookup_cbk_t progcbk;
+ char *sh_fail_val = NULL;
+
+ /*
+ * With native protocol, self-heal failures would be detected during
+ * open. NFS doesn't issue that open when revalidating cache, so we
+ * have to check for failures here instead.
+ */
+ if (dict_get_str(xattr,"sh-failed",&sh_fail_val) == 0) {
+ if (strcmp(sh_fail_val,"1") == 0) {
+ op_ret = -1;
+ op_errno = EIO;
+ }
+ }
+
+ if (op_ret == 0) {
+ nfs_fix_generation(this,inode);
+ }
nfl_to_prog_data (local, progcbk, frame);
nfs_fop_restore_root_ino (local, op_ret, buf, NULL, NULL, postparent);
@@ -680,6 +694,10 @@ nfs_fop_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
struct nfs_fop_local *nfl = NULL;
fop_create_cbk_t progcbk = NULL;
+ if (op_ret == 0) {
+ nfs_fix_generation(this,inode);
+ }
+
nfl_to_prog_data (nfl, progcbk, frame);
nfs_fop_restore_root_ino (nfl, op_ret, buf, NULL, preparent,
postparent);
@@ -782,6 +800,10 @@ nfs_fop_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
struct nfs_fop_local *nfl = NULL;
fop_mkdir_cbk_t progcbk = NULL;
+ if (op_ret == 0) {
+ nfs_fix_generation(this,inode);
+ }
+
nfl_to_prog_data (nfl, progcbk, frame);
nfs_fop_restore_root_ino (nfl, op_ret, buf, NULL,preparent, postparent);
if (progcbk)
@@ -831,6 +853,10 @@ nfs_fop_symlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
struct nfs_fop_local *nfl = NULL;
fop_symlink_cbk_t progcbk = NULL;
+ if (op_ret == 0) {
+ nfs_fix_generation(this,inode);
+ }
+
nfl_to_prog_data (nfl, progcbk, frame);
nfs_fop_restore_root_ino (nfl, op_ret,buf, NULL, preparent, postparent);
if (progcbk)
@@ -927,6 +953,10 @@ nfs_fop_mknod_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
struct nfs_fop_local *nfl = NULL;
fop_mknod_cbk_t progcbk = NULL;
+ if (op_ret == 0) {
+ nfs_fix_generation(this,inode);
+ }
+
nfl_to_prog_data (nfl, progcbk, frame);
nfs_fop_restore_root_ino (nfl, op_ret,buf, NULL, preparent, postparent);
if (progcbk)
@@ -1074,6 +1104,10 @@ nfs_fop_link_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
struct nfs_fop_local *nfl = NULL;
fop_link_cbk_t progcbk = NULL;
+ if (op_ret == 0) {
+ nfs_fix_generation(this,inode);
+ }
+
nfl_to_prog_data (nfl, progcbk, frame);
nfs_fop_restore_root_ino (nfl, op_ret, buf, NULL, preparent,
postparent);
diff --git a/xlators/nfs/server/src/nfs-mem-types.h b/xlators/nfs/server/src/nfs-mem-types.h
index d9edc95b90c..defdaa541f4 100644
--- a/xlators/nfs/server/src/nfs-mem-types.h
+++ b/xlators/nfs/server/src/nfs-mem-types.h
@@ -52,6 +52,7 @@ enum gf_nfs_mem_types_ {
gf_nfs_mt_nlm4_fde,
gf_nfs_mt_nlm4_nlmclnt,
gf_nfs_mt_nlm4_share,
+ gf_nfs_mt_inode_ctx,
gf_nfs_mt_end
};
#endif
diff --git a/xlators/nfs/server/src/nfs.c b/xlators/nfs/server/src/nfs.c
index 6ed3614296f..878a1762e12 100644
--- a/xlators/nfs/server/src/nfs.c
+++ b/xlators/nfs/server/src/nfs.c
@@ -745,6 +745,7 @@ nfs_init_state (xlator_t *this)
this->private = (void *)nfs;
INIT_LIST_HEAD (&nfs->versions);
+ nfs->generation = 1965;
ret = 0;
@@ -829,24 +830,26 @@ int
notify (xlator_t *this, int32_t event, void *data, ...)
{
xlator_t *subvol = NULL;
+ struct nfs_state *priv = NULL;
subvol = (xlator_t *)data;
gf_log (GF_NFS, GF_LOG_TRACE, "Notification received: %d",
event);
- switch (event)
- {
- case GF_EVENT_CHILD_UP:
- {
- nfs_startup_subvolume (this, subvol);
- break;
- }
- case GF_EVENT_PARENT_UP:
- {
- default_notify (this, GF_EVENT_PARENT_UP, data);
- break;
- }
+ switch (event) {
+ case GF_EVENT_CHILD_UP:
+ nfs_startup_subvolume (this, subvol);
+ break;
+
+ case GF_EVENT_CHILD_MODIFIED:
+ priv = this->private;
+ ++(priv->generation);
+ break;
+
+ case GF_EVENT_PARENT_UP:
+ default_notify (this, GF_EVENT_PARENT_UP, data);
+ break;
}
return 0;
@@ -868,14 +871,14 @@ fini (xlator_t *this)
int32_t
nfs_forget (xlator_t *this, inode_t *inode)
{
- uint64_t ctx = 0;
- struct list_head *head = NULL;
+ uint64_t ctx = 0;
+ struct nfs_inode_ctx *ictx = NULL;
if (inode_ctx_del (inode, this, &ctx))
return -1;
- head = (struct list_head *)ctx;
- GF_FREE (head);
+ ictx = (struct nfs_inode_ctx *)ctx;
+ GF_FREE (ictx);
return 0;
}
diff --git a/xlators/nfs/server/src/nfs.h b/xlators/nfs/server/src/nfs.h
index 4c6d039f8d2..10346f8f0b4 100644
--- a/xlators/nfs/server/src/nfs.h
+++ b/xlators/nfs/server/src/nfs.h
@@ -88,6 +88,12 @@ struct nfs_state {
int enable_nlm;
int mount_udp;
struct rpc_clnt *rpc_clnt;
+ uint32_t generation;
+};
+
+struct nfs_inode_ctx {
+ struct list_head shares;
+ uint32_t generation;
};
#define gf_nfs_dvm_on(nfsstt) (((struct nfs_state *)nfsstt)->dynamicvolumes == GF_NFS_DVM_ON)
diff --git a/xlators/nfs/server/src/nfs3.c b/xlators/nfs/server/src/nfs3.c
index f950b9273ee..fb3f17b3d18 100644
--- a/xlators/nfs/server/src/nfs3.c
+++ b/xlators/nfs/server/src/nfs3.c
@@ -32,6 +32,7 @@
#include "nfs3.h"
#include "mem-pool.h"
#include "logging.h"
+#include "nfs-common.h"
#include "nfs-fops.h"
#include "nfs-inodes.h"
#include "nfs-generics.h"
@@ -694,12 +695,21 @@ nfs3svc_getattr_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
cs = frame->local;
+ /*
+ * Somewhat counter-intuitively, we don't need to look for sh-failed
+ * here. Failing this getattr will generate a new lookup from the
+ * client, and nfs_fop_lookup_cbk will detect any self-heal failures.
+ */
+
if (op_ret == -1) {
gf_log (GF_NFS, GF_LOG_WARNING,
"%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req),
cs->resolvedloc.path, strerror (op_errno));
status = nfs3_errno_to_nfsstat3 (op_errno);
}
+ else {
+ nfs_fix_generation(this,inode);
+ }
nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_GETATTR,
status, op_errno);
@@ -745,6 +755,9 @@ nfs3_getattr_resume (void *carg)
int ret = -EFAULT;
nfs_user_t nfu = {0, };
nfs3_call_state_t *cs = NULL;
+ uint64_t raw_ctx = 0;
+ struct nfs_inode_ctx *ictx = NULL;
+ struct nfs_state *priv = NULL;
if (!carg)
return ret;
@@ -771,9 +784,28 @@ nfs3_getattr_resume (void *carg)
goto nfs3err;
}
+ /*
+ * If brick state changed, we need to force a proper lookup cycle (as
+ * would happen in native protocol) to do self-heal checks. We detect
+ * this by comparing the generation number for the last successful
+ * creation/lookup on the inode to the current number, so inodes that
+ * haven't been validated since the state change are affected.
+ */
+ if (inode_ctx_get(cs->resolvedloc.inode,cs->nfsx,&raw_ctx) == 0) {
+ ictx = (struct nfs_inode_ctx *)raw_ctx;
+ priv = cs->nfsx->private;
+ if (ictx->generation != priv->generation) {
+ ret = nfs_lookup (cs->nfsx, cs->vol, &nfu,
+ &cs->resolvedloc,
+ nfs3svc_getattr_lookup_cbk, cs);
+ goto check_err;
+ }
+ }
+
ret = nfs_stat (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc,
nfs3svc_getattr_stat_cbk, cs);
+check_err:
if (ret < 0) {
gf_log (GF_NFS3, GF_LOG_ERROR, "Stat fop failed: %s: %s",
cs->oploc.path, strerror (-ret));
diff --git a/xlators/nfs/server/src/nlm4.c b/xlators/nfs/server/src/nlm4.c
index 3e39fc080dc..c717baf57af 100644
--- a/xlators/nfs/server/src/nlm4.c
+++ b/xlators/nfs/server/src/nlm4.c
@@ -1802,25 +1802,38 @@ nlm4_add_share_to_inode (nlm_share_t *share)
struct list_head *head = NULL;
xlator_t *this = NULL;
inode_t *inode = NULL;
+ struct nfs_inode_ctx *ictx = NULL;
+ struct nfs_state *priv = NULL;
this = THIS;
+ priv = this->private;
inode = share->inode;
ret = inode_ctx_get (inode, this, &ctx);
- head = (struct list_head *)ctx;
-
if (ret || !head) {
- head = GF_CALLOC (1, sizeof (struct list_head),
- gf_common_mt_list_head);
- if (!head ) {
+ ictx = GF_CALLOC (1, sizeof (struct nfs_inode_ctx),
+ gf_nfs_mt_inode_ctx);
+ if (!ictx ) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "could not allocate nfs inode ctx");
ret = -1;
goto out;
}
+ ictx->generation = priv->generation;
+ head = &ictx->shares;
INIT_LIST_HEAD (head);
- ret = inode_ctx_put (inode, this, (uint64_t)head);
- if (ret)
+
+ ret = inode_ctx_put (inode, this, (uint64_t)ictx);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "could not store share list");
goto out;
+ }
+ }
+ else {
+ ictx = (struct nfs_inode_ctx *)ctx;
+ head = &ictx->shares;
}
list_add (&share->inode_list, head);
@@ -1842,6 +1855,7 @@ nlm4_approve_share_reservation (nfs3_call_state_t *cs)
inode_t *inode = NULL;
nlm_share_t *share = NULL;
struct list_head *head = NULL;
+ struct nfs_inode_ctx *ictx = NULL;
if (!cs)
goto out;
@@ -1853,8 +1867,9 @@ nlm4_approve_share_reservation (nfs3_call_state_t *cs)
ret = 0;
goto out;
}
+ ictx = (struct nfs_inode_ctx *)ctx;
- head = (struct list_head *)ctx;
+ head = &ictx->shares;
if (!head || list_empty (head))
goto out;
@@ -2028,18 +2043,19 @@ nlm4svc_share (rpcsvc_request_t *req)
int
nlm4_remove_share_reservation (nfs3_call_state_t *cs)
{
- int ret = -1;
- uint64_t ctx = 0;
- fsh_mode req_mode = 0;
- fsh_access req_access = 0;
- nlm_share_t *share = NULL;
- nlm_share_t *tmp = NULL;
- nlm_client_t *client = NULL;
- char *caller = NULL;
- inode_t *inode = NULL;
- xlator_t *this = NULL;
- struct list_head *head = NULL;
- nlm4_shareargs *args = NULL;
+ int ret = -1;
+ uint64_t ctx = 0;
+ fsh_mode req_mode = 0;
+ fsh_access req_access = 0;
+ nlm_share_t *share = NULL;
+ nlm_share_t *tmp = NULL;
+ nlm_client_t *client = NULL;
+ char *caller = NULL;
+ inode_t *inode = NULL;
+ xlator_t *this = NULL;
+ struct list_head *head = NULL;
+ nlm4_shareargs *args = NULL;
+ struct nfs_inode_ctx *ictx = NULL;
LOCK (&nlm_client_list_lk);
@@ -2069,8 +2085,9 @@ nlm4_remove_share_reservation (nfs3_call_state_t *cs)
inode->gfid, caller);
goto out;
}
+ ictx = (struct nfs_inode_ctx *)ctx;
- head = (struct list_head *)ctx;
+ head = &ictx->shares;
if (list_empty (head)) {
ret = -1;
goto out;