?? iscsi-linux.c
字號:
/* * iSCSI driver for Linux * Copyright (C) 2002 Cisco Systems, Inc. * maintained by linux-iscsi-devel@lists.sourceforge.net * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * See the file COPYING included with this distribution for more details. * * $Id: iscsi-linux.c,v 1.19 2005/01/11 03:47:09 mikenc Exp $ * */#include <stdarg.h>#include <fcntl.h>#include <errno.h>#include <signal.h>#include <unistd.h>#include <netinet/in.h>#include <sys/stat.h>#include <sys/time.h>#include <sys/ioctl.h>#include <sys/utsname.h>#include "iscsi-sfnet.h"#include "iscsi-ioctl.h"#include "iscsi-version.h"#include "iscsi-hooks.h"#include "iscsi-login.h"const char *progname = "iscsid";/* set by signal handlers */static int stop_requested = 0;static int reload_config = 0;#define ISCSI_DEVICE "/dev/iscsictl"static int control_fd = -1;voidsigusr1_handler(int unused){ daemon_config.debug_level++; debugmsg(1, "received sigusr1, debug level now %d", daemon_config.debug_level);}voidsigusr2_handler(int unused){ if (daemon_config.debug_level > 0) daemon_config.debug_level--; debugmsg(1, "received sigusr2, debug level now %d", daemon_config.debug_level);}voidsigterm_handler(int unused){ debugmsg(1, "received sigterm", getpid()); stop_requested = 1;}voidsighup_handler(int unused){ debugmsg(1, "received sighup", getpid()); reload_config = 1;}/* Note: test and clear semantics */intiscsi_should_reload_config(void){ int ret = reload_config; reload_config = 0;#ifdef RESET_LUN_PROBING /* see if it works better to have the kernel module automatically reset * whenever the queue empties, and have it ensure the same session is * never queued more than once. It's easier to track this in the kernel, * and we avoid hanging the daemon if a kernel module bug prevents this * reset from ever succeeding. */ if (ret) { /* reset LUN probing now, so that the re-probes we do after * reloading the config occur in a reasonable order. */ while (ioctl(control_fd, ISCSI_RESET_PROBING, NULL) <= 0) { if (stop_requested) exit(0); usleep(10 * 1000); } debugmsg(1, "reset LUN probing before reloading config"); }#endif return ret;}intiscsi_process_should_exit(void){ return stop_requested;}intopen_control_device(void){ int ctlfd; ctlfd = open(ISCSI_DEVICE, O_RDWR); if (ctlfd < 0) { errormsg("cannot open %s", ISCSI_DEVICE); return -1; } return ctlfd;}/* initialize the daemon_config to it's default state, * process the command line, and do any other initialization needed * for the main daemon process. */voidiscsi_daemon_starting(int argc, char **argv){ int c; struct sigaction action; struct utsname host_info; int retry_count; /* signal handling */ memset(&action, 0x0, sizeof (action)); action.sa_sigaction = NULL; action.sa_flags = 0; action.sa_handler = sigusr1_handler; sigaction(SIGUSR1, &action, 0); action.sa_handler = sigusr2_handler; sigaction(SIGUSR2, &action, 0); action.sa_handler = sighup_handler; sigaction(SIGHUP, &action, 0); action.sa_handler = sigterm_handler; sigaction(SIGTERM, &action, 0); sigaction(SIGINT, &action, 0); openlog(progname, LOG_PID, LOG_DAEMON); /* configure default files */ daemon_config.pid_file = "/var/run/iscsid.pid"; daemon_config.config_file = "/etc/iscsi.conf"; daemon_config.initiator_name_file = "/etc/initiatorname.iscsi"; /* dup it so that the memory is writable */ /* determine InitiatorName or exit */ daemon_config.initiator_name = get_iscsi_initiatorname(daemon_config.initiator_name_file); if (daemon_config.initiator_name == NULL) { logmsg(AS_NOTICE, "daemon exiting due to configuration error"); exit(1); } /* optional InitiatorAlias */ memset(&host_info, 0, sizeof (host_info)); if (uname(&host_info) >= 0) { daemon_config.initiator_alias = strdup(host_info.nodename); } daemon_config.debug_level = 0; /* process any command line arguments */ while ((c = getopt(argc, argv, "d:nvf:s:")) >= 0) { switch (c) { case 'd': if (optarg) { daemon_config.debug_level = atoi(optarg); } else daemon_config.debug_level++; debugmsg(1, "iSCSI debug level %d", daemon_config.debug_level); break; case 'f': if (optarg) { daemon_config.config_file = strdup(optarg); debugmsg(1, "using configuration file %s", daemon_config.config_file); } break; case 'n': daemon_config.foreground = 1; debugmsg(1, "daemon will stay in foreground"); break; case 'v': printf("iscsid version %s (%s)\n", ISCSI_DRIVER_VERSION, ISCSI_DATE); exit(0); default: logmsg(LOG_ERR, "iscsid - unexpected option %d, '%c', exiting", c, c); exit(1); } } debugmsg(1, "InitiatorName=%s", daemon_config.initiator_name); debugmsg(1, "InitiatorAlias=%s", daemon_config.initiator_alias); /* log the version, so that we can tell if the daemon and kernel module * match based on what shows up in the syslog. Tarballs releases * always install both, but Linux distributors may put the kernel module * in a different RPM from the daemon and utils, and users may try to * mix and match in ways that don't work. */ logmsg(LOG_NOTICE, "version %s variant (%s)", ISCSI_DRIVER_VERSION, ISCSI_DATE); /* ensure the control device exists, and open it for all of the * child processes to use */ retry_count=0; for (;;) { control_fd = open_control_device(); if (control_fd >= 0) break; logmsg(AS_ERROR, "could not open control device %s. " "Make sure iscsi is loaded", ISCSI_DEVICE); if (stop_requested) exit(0); sleep(10); retry_count++; if (retry_count > 2) { /* 20 seconds max */ exit(0); } } retry_count=0;#ifdef RESET_LUN_PROBING /* reset the LUN probing, to handle cases where the daemon restarts * without reloading the kernel module */ retry_count=0; while (ioctl(control_fd, ISCSI_RESET_PROBING, NULL) <= 0) { debugmsg(1, "failed to reset LUN probing while daemon starting\n"); if (stop_requested) exit(0); usleep(10 * 1000); retry_count++; if (retry_count > 50) { /* 500ms max */ exit(0); } } debugmsg(1, "reset LUN probing while daemon starting");#endif}voidiscsi_daemon_stopping(void){ close(control_fd); /* nothing to do at the moment */}voidiscsi_init_config_defaults(struct iscsi_config_defaults *defaults){ /* enabled/disabled */ defaults->enabled = 1; /* discovery defaults */ defaults->continuous_sendtargets = 1; /* auto detect */ defaults->send_async_text = 1;#ifdef SLP_ENABLE defaults->slp_multicast = 1;#else defaults->slp_multicast = 0;#endif defaults->slp_scopes = NULL; defaults->slp_poll_interval = 5 * 60; /* 5 minutes */ /* auth options */ defaults->auth_options.authmethod = CHAP_AUTHENTICATION; defaults->auth_options.password_length = 0; defaults->auth_options.password_length_in = 0; /* connection timeouts */ defaults->connection_timeout_options.login_timeout = 15; defaults->connection_timeout_options.auth_timeout = 45; defaults->connection_timeout_options.active_timeout = 5; defaults->connection_timeout_options.idle_timeout = 60; defaults->connection_timeout_options.ping_timeout = 5; /* error timeouts */ defaults->error_timeout_options.abort_timeout = 10; defaults->error_timeout_options.reset_timeout = 30; /* session timeouts */ defaults->session_timeout_options.replacement_timeout = 0; /* tcp options */ defaults->tcp_options.window_size = 256 * 1024; /* iSCSI operational parameters */ defaults->iscsi_options.InitialR2T = 0; defaults->iscsi_options.ImmediateData = 1; defaults->iscsi_options.MaxRecvDataSegmentLength = 128 * 1024; defaults->iscsi_options.FirstBurstLength = 256 * 1024; defaults->iscsi_options.MaxBurstLength = (16 * 1024 * 1024) - 1024; defaults->iscsi_options.DefaultTime2Wait = 0; /* we only use session reinstatement (ERL 0) */ defaults->iscsi_options.DefaultTime2Retain = 0; /* we only use session reinstatement (ERL 0) */ defaults->iscsi_options.HeaderDigest = CONFIG_DIGEST_PREFER_OFF; defaults->iscsi_options.DataDigest = CONFIG_DIGEST_PREFER_OFF;}static intioctl_establish_session(struct iscsi_session_config *config, int probe_luns, int config_number, int update){ int rc, ret = 0; struct iscsi_portal_config *portal = config->portal; struct iscsi_session_ioctl *ioctld = NULL; struct sockaddr_in *addr; /* allocate an ioctl structure with enough space for * all of the portal info */ ioctld = calloc(1, sizeof (*ioctld)); if (ioctld == NULL) { logmsg(AS_ERROR, "failed to allocate %d bytes for ioctl data" " structure", sizeof (*ioctld)); return 1; } ioctld->ioctl_version = ISCSI_SESSION_IOCTL_VERSION; ioctld->config_number = config_number; ioctld->update = update; ioctld->portal.login_timeout = portal->connection_timeout_options.login_timeout; ioctld->portal.auth_timeout = portal->connection_timeout_options.auth_timeout; ioctld->portal.active_timeout = portal->connection_timeout_options.active_timeout; ioctld->portal.idle_timeout = portal->connection_timeout_options.idle_timeout; ioctld->portal.ping_timeout = portal->connection_timeout_options.ping_timeout; ioctld->portal.replacement_timeout = portal->session_timeout_options.replacement_timeout; ioctld->portal.abort_timeout = portal->error_timeout_options.abort_timeout; ioctld->portal.reset_timeout = portal->error_timeout_options.reset_timeout; ioctld->portal.initial_r2t = portal->iscsi_options.InitialR2T; ioctld->portal.immediate_data = portal->iscsi_options.ImmediateData; ioctld->portal.max_recv_data_segment_len = portal->iscsi_options.MaxRecvDataSegmentLength; ioctld->portal.first_burst_len = portal->iscsi_options.FirstBurstLength; ioctld->portal.max_burst_len = portal->iscsi_options.MaxBurstLength; ioctld->portal.def_time2wait = portal->iscsi_options.DefaultTime2Wait; ioctld->portal.def_time2retain = portal->iscsi_options.DefaultTime2Retain; switch (portal->iscsi_options.HeaderDigest) { case CONFIG_DIGEST_NEVER: ioctld->portal.header_digest = ISCSI_DIGEST_NONE; break; case CONFIG_DIGEST_ALWAYS: ioctld->portal.header_digest = ISCSI_DIGEST_CRC32C; break; case CONFIG_DIGEST_PREFER_ON: ioctld->portal.header_digest = ISCSI_DIGEST_CRC32C_NONE; break; case CONFIG_DIGEST_PREFER_OFF: ioctld->portal.header_digest = ISCSI_DIGEST_NONE_CRC32C; break; } switch (portal->iscsi_options.DataDigest) { case CONFIG_DIGEST_NEVER: ioctld->portal.data_digest = ISCSI_DIGEST_NONE; break; case CONFIG_DIGEST_ALWAYS: ioctld->portal.data_digest = ISCSI_DIGEST_CRC32C; break; case CONFIG_DIGEST_PREFER_ON: ioctld->portal.data_digest = ISCSI_DIGEST_CRC32C_NONE; break; case CONFIG_DIGEST_PREFER_OFF: ioctld->portal.data_digest = ISCSI_DIGEST_NONE_CRC32C; break; } ioctld->portal.tcp_window_size = portal->tcp_options.window_size; /* * tmp hack - rest of daemon needs to be fixed for * endien and ipv6 junk */ addr = (struct sockaddr_in *)&ioctld->portal.addr; addr->sin_family = AF_INET; memcpy(&addr->sin_addr.s_addr, portal->descriptor->ip, portal->descriptor->ip_length); addr->sin_port = htons(portal->descriptor->port); ioctld->portal.tag = portal->descriptor->tag; if (config->target->auth_options.username[0] && config->target->auth_options.password_length) { ioctld->password_length = config->target->auth_options.password_length; strncpy(ioctld->username, config->target->auth_options.username, sizeof (ioctld->username)); ioctld->username[sizeof (ioctld->username) - 1] = '\0'; memcpy(ioctld->password, config->target->auth_options.password, MIN(config->target->auth_options.password_length, sizeof (ioctld->password))); ioctld->password[sizeof (ioctld->password) - 1] = '\0';
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -