summaryrefslogtreecommitdiffstats
path: root/cli/src
diff options
context:
space:
mode:
authorKrishnan Parthasarathi <kparthas@redhat.com>2013-05-14 09:59:45 +0530
committerVijay Bellur <vbellur@redhat.com>2013-06-18 22:10:39 -0700
commitbb5ded9bee8cf7671bcb7c06e9ebca91f7bf8d67 (patch)
treefdf3e85a8a786ea5208302bd06c04318b06622f3 /cli/src
parentbda60de187aadc885bbc705ccb9317f680f4b9d3 (diff)
glusterd: Disable transport before cleaning up rpc object
Problem: rpc_transport object, which is part of rpc_clnt, is destroyed prematurely. This is because, rpc_transport object is ref'd by socket layer and rpc layer. These ref's, until the synctask'izing of operations, were unref'd sequentially in the epoll thread. With more threads at play, the sequential unref guarantee is off. Fix: Shutting down the transport before proceeding with cleaning up of rpc_clnt object would serialize the unref's on the rpc_transport object and thus eliminating the race. Also, we don't store the address of brickinfo in brick's rpc notify function, to avoid the possibility of referring a freed brickinfo. Instead we use a string based id to 'reach' the corresponding brickinfo. Change-Id: If2739e2eeaee1e8b071ab2b6754b7ea0f81cfceb BUG: 962619 Signed-off-by: Krishnan Parthasarathi <kparthas@redhat.com> Reviewed-on: http://review.gluster.org/5000 Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Vijay Bellur <vbellur@redhat.com>
Diffstat (limited to 'cli/src')
0 files changed, 0 insertions, 0 deletions
f_log (LIBGF_XL_NAME, GF_LOG_ERROR, "No dcache present"); op_ret = 0; goto out; } /* If we're updating, we must begin with invalidating any previous * entries. */ libgf_dcache_invalidate (fd); fd_ctx->dcache->next = entries->next; /* We still need to store a pointer to the head * so we start free'ing from the head when invalidation * is required. * * Need to delink the entries from the list * given to us by an underlying translators. Most translators will * free this list after this call so we must preserve the dirents in * order to cache them. */ list_splice_init (&entries->list, &fd_ctx->dcache->entries.list); op_ret = 0; out: return op_ret; } int libgf_dcache_readdir (libglusterfs_client_ctx_t *ctx, fd_t *fd, struct dirent *dirp, off_t *offset) { libglusterfs_client_fd_ctx_t *fd_ctx = NULL; int cachevalid = 0; if ((!ctx) || (!fd) || (!dirp) || (!offset)) return 0; fd_ctx = libgf_get_fd_ctx (fd); if (!fd_ctx) { gf_log (LIBGF_XL_NAME, GF_LOG_ERROR, "No fd context present"); errno = EBADF; goto out; } if (!fd_ctx->dcache) { gf_log (LIBGF_XL_NAME, GF_LOG_ERROR, "No dcache present"); goto out; } /* We've either run out of entries in the cache * or the cache is empty. */ if (!fd_ctx->dcache->next) { gf_log (LIBGF_XL_NAME, GF_LOG_TRACE, "No entries present"); goto out; } /* The dirent list is created as a circular linked list * so this check is needed to ensure, we dont start * reading old entries again. * If we're reached this situation, the cache is exhausted * and we'll need to pre-fetch more entries to continue serving. */ if (fd_ctx->dcache->next == &fd_ctx->dcache->entries) { gf_log (LIBGF_XL_NAME, GF_LOG_TRACE, "Entries exhausted"); goto out; } /* During sequential reading we generally expect that the offset * requested is the same as the offset we served in the previous call * to readdir. But, seekdir, rewinddir and libgf_dcache_invalidate * require special handling because seekdir/rewinddir change the offset * in the fd_ctx and libgf_dcache_invalidate changes the prev_off. */ if (*offset != fd_ctx->dcache->prev_off) { /* For all cases of the if branch above, we know that the * cache is now invalid except for the case below. It handles * the case where the two offset values above are different * but different because the previous readdir block was * exhausted, resulting in a prev_off being set to 0 in * libgf_dcache_invalidate, while the requested offset is non * zero because that is what we returned for the last dirent * of the previous readdir block. */ if ((*offset != 0) && (fd_ctx->dcache->prev_off == 0)) { gf_log (LIBGF_XL_NAME, GF_LOG_TRACE, "Entries" " exhausted"); cachevalid = 1; } else gf_log (LIBGF_XL_NAME, GF_LOG_TRACE, "Dcache" " invalidated previously"); } else cachevalid = 1; if (!cachevalid) goto out; dirp->d_ino = fd_ctx->dcache->next->d_ino; strncpy (dirp->d_name, fd_ctx->dcache->next->d_name, fd_ctx->dcache->next->d_len); *offset = fd_ctx->dcache->next->d_off; dirp->d_off = *offset; fd_ctx->dcache->prev_off = fd_ctx->dcache->next->d_off; fd_ctx->dcache->next = fd_ctx->dcache->next->next; out: return cachevalid; } int32_t libgf_client_release (xlator_t *this, fd_t *fd) { libglusterfs_client_fd_ctx_t *fd_ctx = NULL; fd_ctx = libgf_get_fd_ctx (fd); if (IA_ISDIR (fd->inode->ia_type)) { libgf_dcache_invalidate (fd); FREE (fd_ctx->dcache); } libgf_del_fd_ctx (fd); if (fd_ctx != NULL) { pthread_mutex_destroy (&fd_ctx->lock); FREE (fd_ctx); } return 0; } libglusterfs_client_inode_ctx_t * libgf_get_inode_ctx (inode_t *inode) { uint64_t ctxaddr = 0; libglusterfs_client_inode_ctx_t *ictx = NULL; GF_VALIDATE_OR_GOTO (LIBGF_XL_NAME, inode, out); if (inode_ctx_get (inode, libgf_inode_to_xlator (inode), &ctxaddr) < 0) goto out; ictx = (libglusterfs_client_inode_ctx_t *)(long)ctxaddr; out: return ictx; } libglusterfs_client_inode_ctx_t * libgf_del_inode_ctx (inode_t *inode) { uint64_t ctxaddr = 0; libglusterfs_client_inode_ctx_t *ictx = NULL; GF_VALIDATE_OR_GOTO (LIBGF_XL_NAME, inode, out); if (inode_ctx_del (inode, libgf_inode_to_xlator (inode), &ctxaddr) < 0) goto out; ictx = (libglusterfs_client_inode_ctx_t *)(long)ctxaddr; out: return ictx; } libglusterfs_client_inode_ctx_t * libgf_alloc_inode_ctx (libglusterfs_client_ctx_t *ctx, inode_t *inode) { uint64_t ctxaddr = 0; libglusterfs_client_inode_ctx_t *ictx = NULL; GF_VALIDATE_OR_GOTO (LIBGF_XL_NAME, inode, out); GF_VALIDATE_OR_GOTO (LIBGF_XL_NAME, ctx, out); ictx = CALLOC (1, sizeof (*ictx)); if (ictx == NULL) { gf_log (LIBGF_XL_NAME, GF_LOG_ERROR, "memory allocation failure"); goto out; } pthread_mutex_init (&ictx->lock, NULL); ctxaddr = (uint64_t) (long)ictx; if (inode_ctx_put (inode, libgf_inode_to_xlator (inode), ctxaddr) < 0){ FREE (ictx); ictx = NULL; } out: return ictx; } int libgf_transform_iattr (libglusterfs_client_ctx_t *libctx, inode_t *inode, struct iatt *buf) { if ((!libctx) || (!buf) || (!inode)) return -1; buf->ia_dev = libctx->fake_fsid; /* If the inode is root, the inode number must be 1 not the * ino received from the file system. */ if ((inode->ino == 1) && (buf)) buf->ia_ino = 1; return 0; } int libgf_update_iattr_cache (inode_t *inode, int flags, struct iatt *buf) { libglusterfs_client_inode_ctx_t *inode_ctx = NULL; time_t current = 0; int op_ret = -1; GF_VALIDATE_OR_GOTO (LIBGF_XL_NAME, inode, out); inode_ctx = libgf_get_inode_ctx (inode); if (!inode_ctx) { gf_log (LIBGF_XL_NAME, GF_LOG_ERROR, "No inode context" " present"); errno = EINVAL; op_ret = -1; goto out; } pthread_mutex_lock (&inode_ctx->lock); { /* Take a timestamp only after we've acquired the * lock. */ current = time (NULL); if (flags & LIBGF_UPDATE_LOOKUP) { gf_log (LIBGF_XL_NAME, GF_LOG_TRACE, "Updating lookup"); inode_ctx->previous_lookup_time = current; } if (flags & LIBGF_UPDATE_STAT) { gf_log (LIBGF_XL_NAME, GF_LOG_TRACE, "Updating stat"); /* Update the cached stat struct only if a new * stat buf is given. */ if (buf != NULL) { inode_ctx->previous_stat_time = current; memcpy (&inode_ctx->stbuf, buf, sizeof (inode_ctx->stbuf)); } } } pthread_mutex_unlock (&inode_ctx->lock); op_ret = 0; out: return op_ret; } int libgf_invalidate_iattr_cache (inode_t *inode, int flags) { libglusterfs_client_inode_ctx_t *ictx = NULL; if (!inode) return -1; ictx = libgf_get_inode_ctx (inode); if (!ictx) { gf_log (LIBGF_XL_NAME, GF_LOG_ERROR, "No inode context" " present"); return -1; } pthread_mutex_lock (&ictx->lock); { if (flags & LIBGF_INVALIDATE_LOOKUP) { gf_log (LIBGF_XL_NAME, GF_LOG_TRACE, "Invalidating" " lookup"); ictx->previous_lookup_time = 0; } if (flags & LIBGF_INVALIDATE_STAT) { gf_log (LIBGF_XL_NAME, GF_LOG_TRACE, "Invalidating" " stat"); ictx->previous_stat_time = 0; } } pthread_mutex_unlock (&ictx->lock); return 0; } int libgf_is_iattr_cache_valid (libglusterfs_client_ctx_t *ctx, inode_t *inode, struct iatt *sbuf, int flags) { time_t current = 0; time_t prev = 0; libglusterfs_client_inode_ctx_t *inode_ctx = NULL; int cache_valid = 0; time_t timeout = 0; if (inode == NULL) return 0; inode_ctx = libgf_get_inode_ctx (inode); if (!inode_ctx) { gf_log (LIBGF_XL_NAME, GF_LOG_ERROR, "No inode context" " present\n"); return 0; } pthread_mutex_lock (&inode_ctx->lock); { current = time (NULL); if (flags & LIBGF_VALIDATE_LOOKUP) { gf_log (LIBGF_XL_NAME, GF_LOG_TRACE, "Checking lookup"); prev = inode_ctx->previous_lookup_time; timeout = ctx->lookup_timeout; } else { gf_log (LIBGF_XL_NAME, GF_LOG_TRACE, "Checking stat"); prev = inode_ctx->previous_stat_time; timeout = ctx->stat_timeout; } /* Even if the timeout is set to -1 to cache * infinitely, fops like write must invalidate the * stat cache because writev_cbk cannot update * the cache using the stat returned to it. This is * because write-behind can return a stat bufs filled * with zeroes. */ if (prev == 0) { cache_valid = 0; gf_log (LIBGF_XL_NAME, GF_LOG_TRACE, "Cache Invalid"); goto iattr_unlock_out; } /* Cache infinitely */ if (timeout == (time_t)-1) { cache_valid = 1; gf_log (LIBGF_XL_NAME, GF_LOG_TRACE, "Caching On and " "valid"); goto iattr_unlock_out; } /* Disable caching completely */ if (timeout == 0) { cache_valid = 0; gf_log (LIBGF_XL_NAME, GF_LOG_TRACE, "Cache disabled"); goto iattr_unlock_out; } if ((prev > 0) && (timeout >= (current - prev))) { gf_log (LIBGF_XL_NAME, GF_LOG_TRACE, "Cache valid"); cache_valid = 1; } if (flags & LIBGF_VALIDATE_LOOKUP) goto iattr_unlock_out; if ((cache_valid) && (sbuf)) *sbuf = inode_ctx->stbuf; } iattr_unlock_out: pthread_mutex_unlock (&inode_ctx->lock); return cache_valid; } int32_t libgf_client_releasedir (xlator_t *this, fd_t *fd) { libglusterfs_client_fd_ctx_t *fd_ctx = NULL; fd_ctx = libgf_get_fd_ctx (fd); if (IA_ISDIR (fd->inode->ia_type)) { libgf_dcache_invalidate (fd); FREE (fd_ctx->dcache); } libgf_del_fd_ctx (fd); if (fd_ctx != NULL) { pthread_mutex_destroy (&fd_ctx->lock); FREE (fd_ctx); } return 0; } void *poll_proc (void *ptr) { glusterfs_ctx_t *ctx = ptr; event_dispatch (ctx->event_pool); return NULL; } int32_t xlator_graph_init (xlator_t *xl) { xlator_t *trav = xl; int32_t ret = -1; while (trav->prev) trav = trav->prev; while (trav) { if (!trav->ready) { ret = xlator_tree_init (trav); if (ret < 0) break; } trav = trav->next; } return ret; } void xlator_graph_fini (xlator_t *xl) { xlator_t *trav = xl; while (trav->prev) trav = trav->prev; while (trav) { if (!trav->init_succeeded) { break; } xlator_tree_fini (trav); trav = trav->next; } } /* Returns a pointer to the @n'th char matching * @c in string @str, starting the search from right or * end-of-string, rather than starting from left, as rindex * function does. */ char * libgf_rrindex (char *str, int c, int n) { int len = 0; int occurrence = 0; if (str == NULL) return NULL; len = strlen (str); /* Point to last character of string. */ str += (len - 1); while (len > 0) { if ((int)*str == c) { ++occurrence; if (occurrence == n) break; } --len; --str; } return str; } char * libgf_trim_to_prev_dir (char * path) { char *idx = NULL; int len = 0; if (!path) return NULL; /* Check if we're already at root, if yes * then there is no prev dir. */ len = strlen (path); if (len == 1) return path; if (path[len - 1] == '/') { path[len - 1] = '\0'; } idx = libgf_rrindex (path, '/', 1); /* Move to the char after the / */ ++idx; *idx = '\0'; return path; } char * libgf_prepend_cwd (const char *userpath, char *abspath, int size) { if ((!userpath) || (!abspath)) return NULL; if (!getcwd (abspath, size)) return NULL; strcat (abspath, "/"); strcat (abspath, userpath); return abspath; } /* Performs a lightweight path resolution that only * looks for . and .. and replaces those with the * proper names. * * FIXME: This is a stop-gap measure till we have full * fledge path resolution going in here. * Function returns path strdup'ed so remember to FREE the * string as required. */ char * libgf_resolve_path_light (char *path) { char *respath = NULL; char *saveptr = NULL;