📄 iscsid.c
字号:
/* Sendtargets returns with no data */ no_data = 1; } process_sendtarget_discovery_data(count, no_data, discovery, config, targets, discovery_auth_options); }}/* make the target's new_config the current_config */static voiduse_new_target_config(struct iscsi_target *target){ struct iscsi_target_config *old_target_config = NULL; struct iscsi_session_config *new_sessions, *existing_sessions, *tail; struct iscsi_session_config *new_session, *existing_session; struct iscsi_session_process *process; int new_target_config = 0; if (target->new_config == NULL) return; /* if the target config has changed, we consider all session * configs as changed. we want to propagate the fact that the * per-target settings have changed to all session processes. */ if (!same_target_config(target->new_config, target->current_config)) { debugmsg(1, "target config %p for target %p to %s has changed", target->new_config, target, target->TargetName); new_target_config = 1; } /* we always switch to the new data structures, even when they're * the same, to simplify the memory management. This way we * can always free the old stuff. */ new_sessions = target->new_config->sessions; target->new_config->sessions = NULL; if (target->current_config) { old_target_config = target->current_config; existing_sessions = target->current_config->sessions; target->current_config->sessions = NULL; } else existing_sessions = NULL; target->current_config = target->new_config; target->new_config = NULL; /* For simplicity, we use a sequential mapping from the new session * configs to the existing session configs. If portals are reported * in a different order after a portal is added or removed, this may * cause us to change the config of every existing session just to * shuffle the portals around. Since portals don't change often, this * shouldn't cause any real problems. * We iterate over both the new session configs and the existing * session configs at the same time. * - If both exist and have the same config, we do nothing. * - If both exist with different configs, we call the * config_changed() hook. * - If a new session exists and there is no existing session, we * add it. * - If an existing session exists and there is no new session, * we delete it. */ new_session = new_sessions; existing_session = existing_sessions; tail = NULL; while ((new_session = new_sessions)) { /* pop off a new session */ new_sessions = new_session->next; new_session->next = NULL; /* we always ignore any unbound new sessions */ if (new_session->target_id < 0) { logmsg(AS_NOTICE, "discarding unbound session %p to " "%s", new_session, new_session->target->TargetName); free_session_config(new_session); continue; } /* append the new session to the existing sessions */ if (tail) { tail->next = new_session; tail = new_session; } else { target->current_config->sessions = tail = new_session; } /* get a process using this session config */ if (existing_session && (process = existing_session->process)) { /* connect the new_config and the existing process */ new_session->process = process; process->config = new_session; if (new_target_config || !same_session_config(new_session, existing_session)) { process->config_number++; debugmsg(2, "new session config %p is " "different than existing session " "config %p, notifying process %p\n", new_session, existing_session, process); /* notify platform-specific code of the * config change */ iscsi_config_changed(process, new_session, existing_session); } else { debugmsg(7, "new session config %p is the same" " as existing session config %p\n", new_session, existing_session); } } else { /* try to start a new process */ process = calloc(1, sizeof (*process)); if (process == NULL) { logmsg(AS_ERROR, "failed to allocate session " "process for session config %p", new_session); free_session_config(new_session); continue; } /* cross-link them */ process->config = new_session; process->config_number = 1; new_session->process = process; debugmsg(1, "allocated session process %p for session " "config %p", process, new_session); /* do we really need these in a separate list? */ add_session_process(&session_processes, process); /* start the session */ fork_session_process(process); /* and give it a chance to get going */ usleep(10 * 1000); } if (existing_session) { /* pop the existing session config, and go on to the * next */ debugmsg(6, "popping and freeing existing session " "config %p", existing_session); existing_sessions = existing_session->next; free_session_config(existing_session); existing_session = existing_sessions; } else { debugmsg(7, "no existing session config"); } } /* any other existing sessions need to be killed off */ while ((existing_session = existing_sessions)) { /* pop an existing session */ existing_sessions = existing_session->next; if (existing_session->process) { debugmsg(1, "killing existing session process %p " "for bus %d target %d TargetName %s", existing_session, existing_session->iscsi_bus, existing_session->target_id, existing_session->target->TargetName); stop_session_process(existing_session->process); existing_session->process = NULL; } /* and free the obsolete session config */ free_session_config(existing_session); existing_session = NULL; } /* we've already freed every old session, so the old target * config is no longer needed either */ if (old_target_config) free_target_config(old_target_config); if (target->new_portals) { /* we're now done with the target's old portals. Everything has * been updated to use the new portals, even if they're * equivalent, so that we can free all of the old ones. */ if (target->current_portals) free_portal_descriptors(target->current_portals); target->current_portals = target->new_portals; target->new_portals = NULL; }}static intstart_polling(struct discovery_poll_info *poll_info, struct iscsi_config *config){ int rc; int n; int setup_poll; rc = poll(poll_info->poll_fds, poll_info->valid_length, -1); if (rc < 0) debugmsg(7, "daemon returned from poll, rc %d, errno %d, %s", rc, errno, strerror(errno)); else debugmsg(7, "daemon returned from poll, rc %d", rc); while (rc > 0) { setup_poll = 0; if (iscsi_process_should_exit()) return -1; /* if one or more pipes has discovery info, process them all */ for (n = 0; n < poll_info->valid_length; n++) { if (poll_info->poll_fds[n]. revents & (POLLIN | POLLPRI)) { /* process discovery info from this pipe, and " * update sessions based on it */ debugmsg(7, "input on fd %d from discovery" " process %p", poll_info->poll_fds[n].fd, poll_info->processes[n]); update_targets(poll_info->processes[n], config, &targets); } if (poll_info->poll_fds[n].revents & POLLHUP) { debugmsg(1, "poll hangup on index %d, fd %d, " "discovery %p", n, poll_info->poll_fds[n].fd, poll_info->processes[n]); if (poll_info->processes[n]->pipe_fd >= 0) { close(poll_info->processes[n]-> pipe_fd); poll_info->processes[n]->pipe_fd = -1; discovery_processes.changed = 1; /* make sure we remove it later */ } usleep(20 * 1000); setup_poll = 1; } if (poll_info->poll_fds[n].revents & POLLNVAL) { logmsg(AS_ERROR, "invalid poll on index %d, " "fd %d, discovery %p", n, poll_info->poll_fds[n].fd, poll_info->processes[n]); usleep(20 * 1000); setup_poll = 1; } if (poll_info->poll_fds[n].revents & POLLERR) { logmsg(AS_ERROR, "poll error on index %d, fd " "%d, discovery %p", n, poll_info->poll_fds[n].fd, poll_info->processes[n]); usleep(20 * 1000); setup_poll = 1; } poll_info->poll_fds[n].revents = 0; } if (setup_poll) { /* rebuild the pollfd array */ debugmsg(7, "rebuilding poll info after poll revents"); setup_polling(poll_info, &discovery_processes); } /* non-blocking poll to check for more input before * processing any config changes or new targets, so * that we tend to do that all at once. */ rc = poll(poll_info->poll_fds, poll_info->valid_length, 0); if (rc < 0) debugmsg(7, "daemon returned from non-blocking poll rc" " %d, errno %d, %s", rc, errno, strerror(errno)); else debugmsg(7, "daemon returned from non-blocking " "poll, rc %d", rc); } return 1;}static voidreload_config(struct iscsi_config *config, struct discovery_poll_info *poll_info){ struct iscsi_session_process *process; struct iscsi_target *target; if (update_iscsi_config(daemon_config.config_file, config)) { /* kill all the existing discovery processes */ stop_discovery_processes(&discovery_processes); for (target = targets.head; target; target = target->next) { struct iscsi_portal_descriptor *portals; struct iscsi_target_config *target_config; /* always use the most recent portal descriptors */ portals = target->new_portals ? target->new_portals : target->current_portals; /* let the first discovery process to rediscover this * target pass on new auth credentials */ target->discovery = NULL; target->discovered = 0; /* Propagate the current target config's auth * settings for now. These may change when the target * gets rediscovered, but for now we want to keep using * what we already have, since it may have been * propagated from a previous discovery, rather than a * global default. If it was a global default that * included the discovery entry, and that default has * changed, we'll switch to the new default when the * target gets rediscovered. If a global default * applies to a TargetName entry but not the discovery * entry, we'll probably lose it. Propagation from * discovery and dynamic config reloads largely make it * impossible to configure auth credentials by * TargetName, but nobody has really asked for that yet * either, so as long as we train everyone put to put * global defaults before the discovery entries, there * shouldn't be any problems. */ target_config = create_target_config(target-> TargetName, portals, config, &target-> current_config-> auth_options); if (target_config) { /* replace any unused new config */ if (target->new_config) { debugmsg(6, "freeing unused new target" " config %p for target %p " "after config reload", target->new_config, target); free_target_config(target->new_config); } target->new_config = target_config; targets.check_configs = 1; } else { logmsg(AS_ERROR, "failed to allocate target " "config for target %p after config " "reload\n", target); } } for (process = session_processes.head; process; process = process->next) { if (process->failed) { /* restart any process that failed with no * retries. We treat a config reload as an * explicit user request to retry the failed * session */ debugmsg(1, "restarting failed session process" " %p", process); process->restart = 1; session_processes.changed = 1; } else { /* treat a config reload as a * request for a new LUN probe */ debugmsg(1, "assuming LUN inventory may have " "changed for session process %p", process); process->lun_inventory_changed = 1; session_processes.lun_inventory_changed = 1; } } /* start new discovery processes based on the current config */ debugmsg(1, "restarting discovery after config reload"); start_discovery_processes(config, &discovery_processes); setup_polling(poll_info, &discovery_processes); /* give discovery a chance to produce some * results before we start LUN probing. */ usleep(100 * 1000); } else { logmsg(AS_ERROR, "failed to reload configuration file %s", daemon_config.config_file); /* keep running with what we have */ }}static voidupdate_discovery_processes(struct discovery_poll_info *poll_info){ int setup_poll = 0; struct iscsi_discovery_process *discovery; discovery_processes.changed = 0; /* scan the discovery list and make any changes needed */ discovery = discovery_processes.head; while (discovery) { debugmsg(7, "checking discovery process %p, pid %d pipe_fd %d," " restart %d, remove %d, next %p", discovery, discovery->pid, discovery->pipe_fd, discovery->restart, discovery->remove, discovery->next); if (discovery->restart) { discovery->restart = 0; if (discovery->pid == 0) { debugmsg(1, "restarting discovery %p", discovery); if (discovery->pipe_fd >= 0) { close(discovery->pipe_fd); discovery->pipe_fd = -1; } fork_discovery_process(discovery); setup_poll = 1; } discovery = discovery->next; } else if (discovery->pipe_fd == -1) { struct iscsi_discovery_process *next = discovery->next; struct iscsi_target *target; /* no point keeping it around if we can't read from it. * we don't remove it right after SIGCHLD, since we * may still need to drain it's pipe. */ debugmsg(1, "removing discovery %p, pipe has closed", discovery); /* any target first discovered by this process needs * it's discovery pointer cleared, so that there are * no stale pointers, and so that the next process to * discover this target can pass along auth * credentials. */ for (target = targets.head; target; target = target->next) { if (target->discovery == discovery) { target->discovery = NULL; } } stop_discovery_process(discovery); discovery
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -