/** * auth_cache_lookup -- Lookup an item from the cache * * @cache: cache to lookup from * @fh : FH to use in lookup * @host_addr: Address to use in lookup * @timestamp: The timestamp to set when lookup succeeds * @can_write: Is the host authorized to write to the filehandle? * * If the current time - entry time of the cache entry > ttl_sec, * we remove the element from the dict and return ENTRY_EXPIRED. * * @return: ENTRY_EXPIRED if entry expired * ENTRY_NOT_FOUND if entry not found in dict * 0 if found */ enum auth_cache_lookup_results auth_cache_lookup (struct auth_cache *cache, struct nfs3_fh *fh, const char *host_addr, time_t *timestamp, gf_boolean_t *can_write) { char *hashkey = NULL; data_t *entry_data = NULL; struct auth_cache_entry *lookup_res = NULL; int ret = ENTRY_NOT_FOUND; GF_VALIDATE_OR_GOTO (GF_NFS, cache, out); GF_VALIDATE_OR_GOTO (GF_NFS, cache->cache_dict, out); GF_VALIDATE_OR_GOTO (GF_NFS, fh, out); GF_VALIDATE_OR_GOTO (GF_NFS, host_addr, out); GF_VALIDATE_OR_GOTO (GF_NFS, timestamp, out); GF_VALIDATE_OR_GOTO (GF_NFS, can_write, out); hashkey = make_hashkey (fh, host_addr); if (!hashkey) { ret = -ENOMEM; goto out; } entry_data = dict_get (cache->cache_dict, hashkey); if (!entry_data) { gf_msg_debug (GF_NFS, 0, "could not find entry for %s", host_addr); goto out; } lookup_res = (struct auth_cache_entry *)(entry_data->data); if ((time (NULL) - lookup_res->timestamp) > cache->ttl_sec) { gf_msg_debug (GF_NFS, 0, "entry for host %s has expired", host_addr); GF_FREE (lookup_res); entry_data->data = NULL; /* Remove from the cache */ dict_del (cache->cache_dict, hashkey); ret = ENTRY_EXPIRED; goto out; } *timestamp = lookup_res->timestamp; *can_write = lookup_res->item->opts->rw; ret = ENTRY_FOUND; out: GF_FREE (hashkey); return ret; }
/** * exp_dir_get_host -- Given a host string and an exports directory structure, * find and return an struct export_item structure that * represents the requested host. * * @expdir: Export directory to lookup from * @host : Host string to lookup * * @return: success: Pointer to a export item structure * failure: NULL */ struct export_item * exp_dir_get_host(const struct export_dir *expdir, const char *host) { struct export_item *lookup_res = NULL; data_t *dict_res = NULL; GF_VALIDATE_OR_GOTO(GF_EXP, expdir, out); GF_VALIDATE_OR_GOTO(GF_EXP, host, out); if (!expdir->hosts) goto out; dict_res = dict_get(expdir->hosts, (char *)host); if (!dict_res) { gf_msg_debug(GF_EXP, 0, "%s not found for %s", host, expdir->dir_name); /* Check if wildcards are allowed for the host */ dict_res = dict_get(expdir->hosts, "*"); if (!dict_res) { goto out; } } lookup_res = (struct export_item *)dict_res->data; out: return lookup_res; }
/** * exp_file_get_dir -- Return an export dir given a directory name * Does a lookup from the dict in the file structure. * * @file : Exports file structure to lookup from * @dir : Directory name to lookup * * @return : success: Pointer to an export directory structure * failure: NULL */ struct export_dir * exp_file_get_dir(const struct exports_file *file, const char *dir) { struct export_dir *lookup_res = NULL; data_t *dict_res = NULL; char *dirdup = NULL; size_t dirlen = 0; GF_VALIDATE_OR_GOTO(GF_EXP, file, out); GF_VALIDATE_OR_GOTO(GF_EXP, dir, out); dirlen = strlen(dir); if (dirlen <= 0) goto out; dirdup = (char *)dir; /* Point at the directory */ /* If directories don't contain a leading slash */ if (*dir != '/') { dirdup = alloca(dirlen + 2); /* Leading slash & null byte */ snprintf(dirdup, dirlen + 2, "/%s", dir); } dict_res = dict_get(file->exports_dict, dirdup); if (!dict_res) { gf_msg_debug(GF_EXP, 0, "%s not found in %s", dirdup, file->filename); goto out; } lookup_res = (struct export_dir *)dict_res->data; out: return lookup_res; }
static int glusterd_mgmt_v3_unlock_send_resp (rpcsvc_request_t *req, int32_t status) { gd1_mgmt_v3_unlock_rsp rsp = {{0},}; int ret = -1; xlator_t *this = NULL; this = THIS; GF_ASSERT (this); GF_ASSERT (req); rsp.op_ret = status; if (rsp.op_ret) rsp.op_errno = errno; glusterd_get_uuid (&rsp.uuid); ret = glusterd_submit_reply (req, &rsp, NULL, 0, NULL, (xdrproc_t)xdr_gd1_mgmt_v3_unlock_rsp); gf_msg_debug (this->name, 0, "Responded to mgmt_v3 unlock, ret: %d", ret); return ret; }
/* Parses the string to be of the form <key1>:<value1>,<key2>:<value2>... * * takes two optional validaters key_validator and value_validator */ static int validate_list_elements (const char *string, volume_option_t *opt, int (key_validator)( const char *), int (value_validator)( const char *, volume_option_t *)) { char *dup_string = NULL; char *str_sav = NULL; char *substr_sav = NULL; char *str_ptr = NULL; char *key = NULL; char *value = NULL; int ret = 0; GF_ASSERT (string); dup_string = gf_strdup (string); if (NULL == dup_string) goto out; str_ptr = strtok_r (dup_string, ",", &str_sav); if (str_ptr == NULL) { ret = -1; goto out; } while (str_ptr) { key = strtok_r (str_ptr, ":", &substr_sav); if (!key || (key_validator && key_validator(key))) { ret = -1; gf_msg (THIS->name, GF_LOG_WARNING, 0, LG_MSG_INVALID_ENTRY, "invalid list '%s', key " "'%s' not valid.", string, key); goto out; } value = strtok_r (NULL, ":", &substr_sav); if (!value || (value_validator && value_validator(value, opt))) { ret = -1; gf_msg (THIS->name, GF_LOG_WARNING, 0, LG_MSG_INVALID_ENTRY, "invalid list '%s', " "value '%s' not valid.", string, key); goto out; } str_ptr = strtok_r (NULL, ",", &str_sav); substr_sav = NULL; } out: GF_FREE (dup_string); gf_msg_debug (THIS->name, 0, "Returning %d", ret); return ret; }
void cb_buffer_show (buffer_t *buffer) { pthread_mutex_lock (&buffer->lock); { gf_msg_debug ("circ-buff", 0, "w_index: %d, size: %" GF_PRI_SIZET" used_buffer: %d", buffer->w_index, buffer->size_buffer, buffer->used_len); } pthread_mutex_unlock (&buffer->lock); }
int gf_changelog_done (char *file) { int ret = -1; char *buffer = NULL; xlator_t *this = NULL; gf_changelog_journal_t *jnl = NULL; char to_path[PATH_MAX] = {0,}; errno = EINVAL; this = THIS; if (!this) goto out; jnl = (gf_changelog_journal_t *) GF_CHANGELOG_GET_API_PTR (this); if (!jnl) goto out; if (!file || !strlen (file)) goto out; /* make sure 'file' is inside ->jnl_working_dir */ buffer = realpath (file, NULL); if (!buffer) goto out; if (strncmp (jnl->jnl_working_dir, buffer, strlen (jnl->jnl_working_dir))) goto out; (void) snprintf (to_path, PATH_MAX, "%s%s", jnl->jnl_processed_dir, basename (buffer)); gf_msg_debug (this->name, 0, "moving %s to processed directory", file); ret = sys_rename (buffer, to_path); if (ret) { gf_smsg (this->name, GF_LOG_ERROR, errno, CHANGELOG_LIB_MSG_RENAME_FAILED, "cannot move changelog file", "from=%s", file, "to=%s", to_path, NULL); goto out; } ret = 0; out: if (buffer) free (buffer); /* allocated by realpath() */ return ret; }
int solaris_xattr_resolve_path (const char *real_path, char **path) { int ret = -1; char *export_path = NULL; char xattr_path[PATH_MAX] = {0, }; struct stat lstatbuf = {0, }; struct iatt stbuf = {0, }; struct stat statbuf = {0, }; ret = lstat (real_path, &lstatbuf); if (ret != 0 ) return ret; iatt_from_stat (&stbuf, &lstatbuf); if (IA_ISREG(stbuf.ia_type) || IA_ISDIR(stbuf.ia_type)) return -1; ret = make_export_path (real_path, &export_path); if (!ret && export_path) { strcat (export_path, "/"GF_SOLARIS_XATTR_DIR); if (lstat (export_path, &statbuf)) { ret = mkdir (export_path, 0777); if (ret && (errno != EEXIST)) { gf_msg_debug (THIS->name, 0, "mkdir failed," " errno: %d", errno); goto out; } } snprintf(xattr_path, PATH_MAX, "%s%s%lu", export_path, "/", stbuf.ia_ino); ret = lstat (xattr_path, &statbuf); if (ret) { ret = mknod (xattr_path, S_IFREG|O_WRONLY, 0); if (ret && (errno != EEXIST)) { gf_msg (THIS->name, GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED, "Failed to " "create mapped file %s", xattr_path); goto out; } } *path = gf_strdup (xattr_path); } out: GF_FREE (export_path); if (*path) return 0; else return -1; }
int xlator_volopt_dynload (char *xlator_type, void **dl_handle, volume_opt_list_t *opt_list) { int ret = -1; char *name = NULL; void *handle = NULL; GF_VALIDATE_OR_GOTO ("xlator", xlator_type, out); /* socket.so doesn't fall under the default xlator directory, hence we * need this check */ if (!strstr(xlator_type, "rpc-transport")) ret = gf_asprintf (&name, "%s/%s.so", XLATORDIR, xlator_type); else ret = gf_asprintf (&name, "%s/%s.so", XLATORPARENTDIR, xlator_type); if (-1 == ret) { goto out; } ret = -1; gf_msg_trace ("xlator", 0, "attempt to load file %s", name); handle = dlopen (name, RTLD_NOW|RTLD_GLOBAL); if (!handle) { gf_msg ("xlator", GF_LOG_WARNING, 0, LG_MSG_DLOPEN_FAILED, "%s", dlerror ()); goto out; } if (!(opt_list->given_opt = dlsym (handle, "options"))) { dlerror (); gf_msg ("xlator", GF_LOG_ERROR, 0, LG_MSG_LOAD_FAILED, "Failed to load xlator opt table"); goto out; } *dl_handle = handle; handle = NULL; ret = 0; out: GF_FREE (name); if (handle) dlclose (handle); gf_msg_debug ("xlator", 0, "Returning %d", ret); return ret; }
void eh_dump (eh_t *history, void *data, int (dump_fn) (circular_buffer_t *buffer, void *data)) { if (!history) { gf_msg_debug ("event-history", 0, "history is NULL"); goto out; } cb_buffer_dump (history->buffer, data, dump_fn); out: return; }
int xlator_volopt_dynload (char *xlator_type, void **dl_handle, volume_opt_list_t *opt_list) { int ret = -1; char *name = NULL; void *handle = NULL; GF_VALIDATE_OR_GOTO ("xlator", xlator_type, out); ret = gf_asprintf (&name, "%s/%s.so", XLATORDIR, xlator_type); if (-1 == ret) { goto out; } ret = -1; gf_msg_trace ("xlator", 0, "attempt to load file %s", name); handle = dlopen (name, RTLD_NOW|RTLD_GLOBAL); if (!handle) { gf_msg ("xlator", GF_LOG_WARNING, 0, LG_MSG_DLOPEN_FAILED, "%s", dlerror ()); goto out; } if (!(opt_list->given_opt = dlsym (handle, "options"))) { dlerror (); gf_msg ("xlator", GF_LOG_ERROR, 0, LG_MSG_LOAD_FAILED, "Failed to load xlator opt table"); goto out; } *dl_handle = handle; handle = NULL; ret = 0; out: GF_FREE (name); if (handle) dlclose (handle); gf_msg_debug ("xlator", 0, "Returning %d", ret); return ret; }
/*XXX: the rules to validate are as per block-size required for stripe xlator */ static int gf_validate_size (const char *sizestr, volume_option_t *opt) { size_t value = 0; int ret = 0; GF_ASSERT (opt); if (gf_string2bytesize_size (sizestr, &value) != 0 || value < opt->min || value % 512) { ret = -1; goto out; } out: gf_msg_debug (THIS->name, 0, "Returning %d", ret); return ret; }
static int glusterd_mgmt_v3_post_validate_send_resp (rpcsvc_request_t *req, int32_t op, int32_t status, char *op_errstr, dict_t *rsp_dict) { gd1_mgmt_v3_post_val_rsp rsp = {{0},}; int ret = -1; xlator_t *this = NULL; this = THIS; GF_ASSERT (this); GF_ASSERT (req); rsp.op_ret = status; glusterd_get_uuid (&rsp.uuid); rsp.op = op; if (op_errstr) rsp.op_errstr = op_errstr; else rsp.op_errstr = ""; ret = dict_allocate_and_serialize (rsp_dict, &rsp.dict.dict_val, &rsp.dict.dict_len); if (ret < 0) { gf_msg (this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SERL_LENGTH_GET_FAIL, "failed to get serialized length of dict"); goto out; } ret = glusterd_submit_reply (req, &rsp, NULL, 0, NULL, (xdrproc_t)xdr_gd1_mgmt_v3_post_val_rsp); GF_FREE (rsp.dict.dict_val); out: gf_msg_debug (this->name, 0, "Responded to post validation, ret: %d", ret); return ret; }
struct export_item * exp_dir_get_netgroup(const struct export_dir *expdir, const char *netgroup) { struct export_item *lookup_res = NULL; data_t *dict_res = NULL; GF_VALIDATE_OR_GOTO(GF_EXP, expdir, out); GF_VALIDATE_OR_GOTO(GF_EXP, netgroup, out); if (!expdir->netgroups) goto out; dict_res = dict_get(expdir->netgroups, (char *)netgroup); if (!dict_res) { gf_msg_debug(GF_EXP, 0, "%s not found for %s", netgroup, expdir->dir_name); goto out; } lookup_res = (struct export_item *)dict_res->data; out: return lookup_res; }
/** * exp_file_parse -- Parse an exports file into a structure * that can be looked up through simple * function calls. * * @filepath: Path to the exports file * @ms : Current mount state (useful to match with gluster vol files) * * @return : success: 0 * failure: -1 on parsing failure, -EINVAL on bad arguments, * -ENOMEM on allocation failures. * * The caller is responsible for freeing memory allocated by this function. * The caller should free this memory using the exp_file_deinit () function. * Calling GF_FREE ( ) on the pointer will NOT free all the allocated memory. * * Externally usable. */ int exp_file_parse(const char *filepath, struct exports_file **expfile, struct mount3_state *ms) { FILE *fp = NULL; struct exports_file *file = NULL; size_t len = 0; int ret = -EINVAL; unsigned long line_number = 0; char *line = NULL; struct export_dir *expdir = NULL; /* Sets whether we we should parse the entire file or just that which * is present in the mount state */ gf_boolean_t parse_complete_file = _gf_false; GF_VALIDATE_OR_GOTO(GF_EXP, expfile, parse_done); if (!ms) { /* If mount state is null that means that we * should go through and parse the whole file * since we don't have anything to compare against. */ parse_complete_file = _gf_true; } fp = fopen(filepath, "r"); if (!fp) { ret = -errno; goto parse_done; } ret = _exp_init_parsers(); if (ret < 0) goto parse_done; /* Process the file line by line, with each line being parsed into * an struct export_dir struct. If 'parse_complete_file' is set to TRUE * then */ while (getline(&line, &len, fp) != -1) { line_number++; /* Keeping track of line number allows us to * to log which line numbers were wrong */ strtok(line, "\n"); /* removes the newline character from * the line */ /* Parse the line from the file into an struct export_dir * structure. The process is as follows: * Given a line like : * "/vol @test(sec=sys,rw,anonuid=0) 10.35.11.31(sec=sys,rw)" * * This function will allocate an export dir and set its name * to '/vol', using the function _exp_line_dir_parse (). * * Then it will extract the netgroups from the line, in this * case it would be '@test(sec=sys,rw,anonuid=0)', and set the * item structure's name to '@test'. * It will also extract the options from that string and parse * them into an struct export_options which will be pointed * to by the item structure. This will be put into a dict * which will be pointed to by the export directory structure. * * The same process happens above for the host string * '10.35.11.32(sec=sys,rw)' */ ret = _exp_line_parse(line, &expdir, parse_complete_file, ms); if (ret == -ENOMEM) { /* If we get memory allocation errors, we really should * not continue parsing, so just free the allocated * memory and exit. */ goto free_and_done; } if (ret < 0) { gf_msg(GF_EXP, GF_LOG_ERROR, -ret, NFS_MSG_PARSE_FAIL, "Failed to parse line #%lu", line_number); continue; /* Skip entering this line and continue */ } if (ret == GF_EXP_PARSE_LINE_IGNORING) { /* This just means the line was empty or started with a * '#' or a ' ' and we are ignoring it. */ gf_msg_debug(GF_EXP, 0, "Ignoring line #%lu because it started " "with a %c", line_number, *line); continue; } if (!file) { file = _exports_file_init(); GF_CHECK_ALLOC_AND_LOG(GF_EXP, file, ret, "Allocation error while " "allocating file struct", parse_done); file->filename = gf_strdup(filepath); GF_CHECK_ALLOC_AND_LOG(GF_EXP, file, ret, "Allocation error while " "duping filepath", free_and_done); } /* If the parsing is successful store the export directory * in the file structure. */ _exp_file_insert(file, expdir); } /* line got allocated through getline(), don't use GF_FREE() for it */ free(line); *expfile = file; goto parse_done; free_and_done: exp_file_deinit(file); _export_dir_deinit(expdir); parse_done: if (fp) fclose(fp); _exp_deinit_parsers(); return ret; }
static int glusterd_handle_mgmt_v3_unlock_fn (rpcsvc_request_t *req) { gd1_mgmt_v3_unlock_req lock_req = {{0},}; int32_t ret = -1; glusterd_op_lock_ctx_t *ctx = NULL; xlator_t *this = NULL; gf_boolean_t is_synctasked = _gf_false; gf_boolean_t free_ctx = _gf_false; this = THIS; GF_ASSERT (this); GF_ASSERT (req); ret = xdr_to_generic (req->msg[0], &lock_req, (xdrproc_t)xdr_gd1_mgmt_v3_unlock_req); if (ret < 0) { gf_msg (this->name, GF_LOG_ERROR, 0, GD_MSG_REQ_DECODE_FAIL, "Failed to decode unlock " "request received from peer"); req->rpc_err = GARBAGE_ARGS; goto out; } gf_msg_debug (this->name, 0, "Received volume unlock req " "from uuid: %s", uuid_utoa (lock_req.uuid)); if (glusterd_peerinfo_find_by_uuid (lock_req.uuid) == NULL) { gf_msg (this->name, GF_LOG_WARNING, 0, GD_MSG_PEER_NOT_FOUND, "%s doesn't " "belong to the cluster. Ignoring request.", uuid_utoa (lock_req.uuid)); ret = -1; goto out; } ctx = GF_CALLOC (1, sizeof (*ctx), gf_gld_mt_op_lock_ctx_t); if (!ctx) { ret = -1; goto out; } gf_uuid_copy (ctx->uuid, lock_req.uuid); ctx->req = req; ctx->dict = dict_new (); if (!ctx->dict) { ret = -1; goto out; } ret = dict_unserialize (lock_req.dict.dict_val, lock_req.dict.dict_len, &ctx->dict); if (ret) { gf_msg (this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_UNSERIALIZE_FAIL, "failed to unserialize the dictionary"); goto out; } is_synctasked = dict_get_str_boolean (ctx->dict, "is_synctasked", _gf_false); if (is_synctasked) { ret = glusterd_syctasked_mgmt_v3_unlock (req, &lock_req, ctx); if (ret) { gf_msg (this->name, GF_LOG_ERROR, 0, GD_MSG_MGMTV3_UNLOCK_FAIL, "Failed to release mgmt_v3_locks"); /* Ignore the return code, as it shouldn't be propagated * from the handler function so as to avoid double * deletion of the req */ ret = 0; } /* The above function does not take ownership of ctx. * Therefore we need to free the ctx explicitly. */ free_ctx = _gf_true; } else { /* Shouldn't ignore the return code here, and it should * be propagated from the handler function as in failure * case it doesn't delete the req object */ ret = glusterd_op_state_machine_mgmt_v3_unlock (req, &lock_req, ctx); if (ret) gf_msg (this->name, GF_LOG_ERROR, 0, GD_MSG_MGMTV3_UNLOCK_FAIL, "Failed to release mgmt_v3_locks"); } out: if (ctx && (ret || free_ctx)) { if (ctx->dict) dict_unref (ctx->dict); GF_FREE (ctx); } free (lock_req.dict.dict_val); gf_msg_trace (this->name, 0, "Returning %d", ret); return ret; }
/** * __exp_line_dir_parse -- Extract directory name from a line in the exports * file. * * @line : The line to parse * @dirname : Double pointer to the string we need to hold the directory name. * If the parsing failed, the string will point to NULL, otherwise * it will point to a valid memory region that is allocated by * this function. * @check_ms: If this variable is set then we cross check the directory line * with what's in gluster's vol files and reject them if they don't * match. * * @return : success: GF_EXP_PARSE_SUCCESS * failure: GF_EXP_PARSE_ITEM_FAILURE on parse failure, * -EINVAL on bad arguments, -ENOMEM on allocation failures, * GF_EXP_PARSE_ITEM_NOT_IN_MOUNT_STATE if we failed to match * with gluster's mountstate. * * The caller is responsible for freeing memory allocated by this function * * Not for external use. */ static int __exp_line_dir_parse(const char *line, char **dirname, struct mount3_state *ms) { char *dir = NULL; char *delim = NULL; int ret = -EINVAL; char *linedup = NULL; struct mnt3_export *mnt3export = NULL; size_t dirlen = 0; GF_VALIDATE_OR_GOTO(GF_EXP, line, out); GF_VALIDATE_OR_GOTO(GF_EXP, dirname, out); /* Duplicate the line because we don't * want to modify the original string. */ linedup = strdupa(line); /* We use strtok_r () here to split the string by space/tab and get the * the result. We only need the first result of the split. * a simple task. It is worth noting that dirnames always have to be * validated against gluster's vol files so if they don't * match it will be rejected. */ dir = linedup; delim = linedup + strcspn(linedup, " \t"); *delim = 0; if (ms) { /* Match the directory name with an existing * export in the mount state. */ mnt3export = mnt3_mntpath_to_export(ms, dir, _gf_true); if (!mnt3export) { gf_msg_debug(GF_EXP, 0, "%s not in mount state, " "ignoring!", dir); ret = GF_EXP_PARSE_ITEM_NOT_IN_MOUNT_STATE; goto out; } } /* Directories can be 1024 bytes in length, check * that the argument provided adheres to * that restriction. */ if (strlen(dir) > DIR_MAX_LEN) { ret = -EINVAL; goto out; } /* Copy the result of the split */ dir = gf_strdup(dir); GF_CHECK_ALLOC(dir, ret, out); /* Ensure that trailing slashes are stripped before storing the name */ dirlen = strlen(dir); if (dirlen > 0 && dir[dirlen - 1] == '/') dir[dirlen - 1] = '\0'; /* Set the argument to point to the allocated string */ *dirname = dir; ret = GF_EXP_PARSE_SUCCESS; out: return ret; }
static int event_dispatch_epoll_handler (struct event_pool *event_pool, struct epoll_event *event) { struct event_data *ev_data = NULL; struct event_slot_epoll *slot = NULL; event_handler_t handler = NULL; void *data = NULL; int idx = -1; int gen = -1; int ret = -1; int fd = -1; ev_data = (void *)&event->data; handler = NULL; data = NULL; idx = ev_data->idx; gen = ev_data->gen; slot = event_slot_get (event_pool, idx); LOCK (&slot->lock); { fd = slot->fd; if (fd == -1) { gf_msg ("epoll", GF_LOG_ERROR, 0, LG_MSG_STALE_FD_FOUND, "stale fd found on " "idx=%d, gen=%d, events=%d, slot->gen=%d", idx, gen, event->events, slot->gen); /* fd got unregistered in another thread */ goto pre_unlock; } if (gen != slot->gen) { gf_msg ("epoll", GF_LOG_ERROR, 0, LG_MSG_GENERATION_MISMATCH, "generation " "mismatch on idx=%d, gen=%d, slot->gen=%d, " "slot->fd=%d", idx, gen, slot->gen, slot->fd); /* slot was re-used and therefore is another fd! */ goto pre_unlock; } handler = slot->handler; data = slot->data; slot->in_handler++; } pre_unlock: UNLOCK (&slot->lock); if (!handler) goto out; ret = handler (fd, idx, data, (event->events & (EPOLLIN|EPOLLPRI)), (event->events & (EPOLLOUT)), (event->events & (EPOLLERR|EPOLLHUP))); LOCK (&slot->lock); { slot->in_handler--; if (gen != slot->gen) { /* event_unregister() happened while we were in handler() */ gf_msg_debug ("epoll", 0, "generation bumped on idx=%d" " from gen=%d to slot->gen=%d, fd=%d, " "slot->fd=%d", idx, gen, slot->gen, fd, slot->fd); goto post_unlock; } /* This call also picks up the changes made by another thread calling event_select_on_epoll() while this thread was busy in handler() */ if (slot->in_handler == 0) { event->events = slot->events; ret = epoll_ctl (event_pool->fd, EPOLL_CTL_MOD, fd, event); } } post_unlock: UNLOCK (&slot->lock); out: event_slot_unref (event_pool, slot, idx); return ret; }