mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-14 01:01:27 +00:00
Explicit ALUA user space
git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@6579 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
4
Makefile
4
Makefile
@@ -45,7 +45,7 @@ QLA_DIR=qla2x00t_git/qla2x00-target
|
||||
QLA_OLD_INI_DIR=qla2x00t
|
||||
QLA_OLD_DIR=qla2x00t/qla2x00-target
|
||||
LSI_DIR=mpt
|
||||
USR_DIR=usr/fileio
|
||||
USR_DIR=usr
|
||||
SRP_DIR=srpt
|
||||
SCST_LOCAL_DIR=scst_local
|
||||
MVSAS_DIR=mvsas_tgt
|
||||
@@ -129,7 +129,7 @@ help:
|
||||
@echo " scst_local_install : scst_local target: install"
|
||||
@echo " scst_local_uninstall : scst_local target: uninstall"
|
||||
@echo ""
|
||||
@echo " usr : make user space fileio_tgt target"
|
||||
@echo " usr : make user space targets"
|
||||
@echo " usr_clean : usr target: clean "
|
||||
@echo " usr_extraclean : usr target: clean + clean dependencies"
|
||||
@echo " usr_install : usr target: install"
|
||||
|
||||
78
usr/Makefile
Normal file
78
usr/Makefile
Normal file
@@ -0,0 +1,78 @@
|
||||
#
|
||||
# Common makefile for SCSI target mid-level and its drivers
|
||||
#
|
||||
# Copyright (C) 2004 - 2015 Vladislav Bolkhovitin <vst@vlnb.net>
|
||||
# Copyright (C) 2004 - 2005 Leonid Stoljar
|
||||
# Copyright (C) 2007 - 2015 SanDisk Corporation
|
||||
#
|
||||
# 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, version 2
|
||||
# of the License.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
|
||||
SHELL=/bin/bash
|
||||
# Decide to use which kernel src. If not specified, is current running kernel.
|
||||
#export KDIR=/usr/src/linux-2.6
|
||||
|
||||
FILEIO_DIR=fileio
|
||||
STPGD_DIR=stpgd
|
||||
|
||||
all:
|
||||
cd $(FILEIO_DIR) && $(MAKE) $@
|
||||
cd $(STPGD_DIR) && $(MAKE) $@
|
||||
|
||||
install:
|
||||
cd $(FILEIO_DIR) && $(MAKE) $@
|
||||
cd $(STPGD_DIR) && $(MAKE) $@
|
||||
|
||||
uninstall:
|
||||
cd $(FILEIO_DIR) && $(MAKE) $@
|
||||
cd $(STPGD_DIR) && $(MAKE) $@
|
||||
|
||||
clean:
|
||||
cd $(FILEIO_DIR) && $(MAKE) $@
|
||||
cd $(STPGD_DIR) && $(MAKE) $@
|
||||
|
||||
extraclean:
|
||||
cd $(FILEIO_DIR) && $(MAKE) $@
|
||||
cd $(STPGD_DIR) && $(MAKE) $@
|
||||
|
||||
2release:
|
||||
cd $(FILEIO_DIR) && $(MAKE) $@
|
||||
cd $(STPGD_DIR) && $(MAKE) $@
|
||||
|
||||
2debug:
|
||||
cd $(FILEIO_DIR) && $(MAKE) $@
|
||||
cd $(STPGD_DIR) && $(MAKE) $@
|
||||
|
||||
2perf:
|
||||
cd $(FILEIO_DIR) && $(MAKE) $@
|
||||
cd $(STPGD_DIR) && $(MAKE) $@
|
||||
|
||||
disable_proc:
|
||||
cd $(FILEIO_DIR) && $(MAKE) $@
|
||||
cd $(STPGD_DIR) && $(MAKE) $@
|
||||
|
||||
enable_proc:
|
||||
cd $(FILEIO_DIR) && $(MAKE) $@
|
||||
cd $(STPGD_DIR) && $(MAKE) $@
|
||||
|
||||
help:
|
||||
@echo " all (the default) : make all"
|
||||
@echo " clean : clean files"
|
||||
@echo " extraclean : clean + clean dependencies"
|
||||
@echo " install : install"
|
||||
@echo " uninstall : uninstall"
|
||||
@echo " Notes :"
|
||||
@echo " - install and uninstall must be made as root."
|
||||
@echo " - be sure to compile qla against the correct initiator"
|
||||
@echo " driver. Read its README for details."
|
||||
|
||||
.PHONY: all install uninstall clean extraclean help 2release 2debug 2perf disable_proc enable_proc
|
||||
@@ -29,10 +29,11 @@ OBJS_F = $(SRCS_F:.c=.o)
|
||||
SCST_INC_DIR := $(shell if [ -e "$$PWD/../../scst" ]; \
|
||||
then echo "$$PWD/../../scst/include"; \
|
||||
else echo "$(DESTDIR)$(PREFIX)/include/scst"; fi)
|
||||
DEBUG_INC_DIR := ../include
|
||||
INSTALL_DIR := $(DESTDIR)$(PREFIX)/bin/scst
|
||||
|
||||
CFLAGS += -O2 -Wall -Wextra -Wno-unused-parameter -Wstrict-prototypes \
|
||||
-I$(SCST_INC_DIR) -D_GNU_SOURCE -D__USE_FILE_OFFSET64 \
|
||||
-I$(SCST_INC_DIR) -I$(DEBUG_INC_DIR) -D_GNU_SOURCE -D__USE_FILE_OFFSET64 \
|
||||
-D__USE_LARGEFILE64
|
||||
PROGS = fileio_tgt
|
||||
LIBS = -lpthread
|
||||
|
||||
@@ -1,148 +1 @@
|
||||
/*
|
||||
* debug.c
|
||||
*
|
||||
* Copyright (C) 2004 - 2015 Vladislav Bolkhovitin <vst@vlnb.net>
|
||||
* Copyright (C) 2004 - 2005 Leonid Stoljar
|
||||
* Copyright (C) 2007 - 2015 SanDisk Corporation
|
||||
*
|
||||
* Contains helper functions for execution tracing and error reporting.
|
||||
* Intended to be included in main .c file.
|
||||
*
|
||||
* 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, version 2
|
||||
* of the License.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
pid_t gettid (void)
|
||||
{
|
||||
return syscall(__NR_gettid);
|
||||
}
|
||||
|
||||
#if defined(DEBUG) || defined(TRACING)
|
||||
|
||||
#define TRACE_BUF_SIZE 512
|
||||
|
||||
static char trace_buf[TRACE_BUF_SIZE];
|
||||
static pthread_spinlock_t trace_buf_lock;
|
||||
|
||||
int debug_print_prefix(unsigned long trace_flag, const char *prefix,
|
||||
const char *func, int line)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
pthread_spin_lock(&trace_buf_lock);
|
||||
|
||||
if (trace_flag & TRACE_TIME) {
|
||||
struct tm t;
|
||||
time_t tt;
|
||||
time(&tt);
|
||||
localtime_r(&tt, &t);
|
||||
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "%d:%d:%d ",
|
||||
t.tm_hour, t.tm_min, t.tm_sec);
|
||||
}
|
||||
if (trace_flag & TRACE_PID)
|
||||
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "[%d]: ",
|
||||
gettid());
|
||||
if (prefix != NULL)
|
||||
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "%s:", prefix);
|
||||
if (trace_flag & TRACE_FUNCTION)
|
||||
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "%s:", func);
|
||||
if (trace_flag & TRACE_LINE)
|
||||
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "%i:", line);
|
||||
|
||||
if (i > 0)
|
||||
PRINTN("%s", trace_buf);
|
||||
|
||||
pthread_spin_unlock(&trace_buf_lock);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
void debug_print_buffer(const void *data, int len)
|
||||
{
|
||||
int z, z1, i;
|
||||
const unsigned char *buf = (const unsigned char *) data;
|
||||
int f = 0;
|
||||
|
||||
if (buf == NULL)
|
||||
return;
|
||||
|
||||
pthread_spin_lock(&trace_buf_lock);
|
||||
|
||||
PRINT(" (h)___0__1__2__3__4__5__6__7__8__9__A__B__C__D__E__F");
|
||||
for (z = 0, z1 = 0, i = 0; z < len; z++) {
|
||||
if (z % 16 == 0) {
|
||||
if (z != 0) {
|
||||
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i,
|
||||
" ");
|
||||
for (; (z1 < z) && (i < TRACE_BUF_SIZE - 1);
|
||||
z1++) {
|
||||
if ((buf[z1] >= 0x20) &&
|
||||
(buf[z1] < 0x80))
|
||||
trace_buf[i++] = buf[z1];
|
||||
else
|
||||
trace_buf[i++] = '.';
|
||||
}
|
||||
trace_buf[i] = '\0';
|
||||
PRINT("%s", trace_buf);
|
||||
i = 0;
|
||||
f = 1;
|
||||
}
|
||||
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i,
|
||||
"%4x: ", z);
|
||||
}
|
||||
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "%02x ",
|
||||
buf[z]);
|
||||
}
|
||||
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, " ");
|
||||
for (; (z1 < z) && (i < TRACE_BUF_SIZE - 1); z1++) {
|
||||
if ((buf[z1] > 0x20) && (buf[z1] < 0x80))
|
||||
trace_buf[i++] = buf[z1];
|
||||
else
|
||||
trace_buf[i++] = '.';
|
||||
}
|
||||
trace_buf[i] = '\0';
|
||||
if (f) {
|
||||
PRINT("%s", trace_buf)
|
||||
} else {
|
||||
PRINT("%s", trace_buf);
|
||||
}
|
||||
|
||||
pthread_spin_unlock(&trace_buf_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
int debug_init(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = pthread_spin_init(&trace_buf_lock, PTHREAD_PROCESS_PRIVATE);
|
||||
if (res != 0) {
|
||||
res = errno;
|
||||
PRINT_ERROR("pthread_spin_init() failed: %s", strerror(res));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void debug_done(void)
|
||||
{
|
||||
pthread_spin_destroy(&trace_buf_lock);
|
||||
}
|
||||
|
||||
#endif /* DEBUG || TRACING */
|
||||
#include "../include/debug.c"
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <stdint.h>
|
||||
#include <getopt.h>
|
||||
#include <malloc.h>
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
@@ -36,7 +37,9 @@
|
||||
|
||||
char *app_name;
|
||||
|
||||
#include "version.h"
|
||||
#include "common.h"
|
||||
#include "debug.h"
|
||||
|
||||
#if defined(DEBUG) || defined(TRACING)
|
||||
|
||||
@@ -62,11 +65,11 @@ char *app_name;
|
||||
# endif
|
||||
#endif /* DEBUG */
|
||||
|
||||
bool log_daemon = false;
|
||||
unsigned long trace_flag = DEFAULT_LOG_FLAGS;
|
||||
#endif /* defined(DEBUG) || defined(TRACING) */
|
||||
|
||||
#define DEF_BLOCK_SHIFT 9
|
||||
#define VERSION_STR "3.1.0-pre1"
|
||||
#define THREADS 7
|
||||
|
||||
#define MAX_VDEVS 10
|
||||
|
||||
147
usr/include/debug.c
Normal file
147
usr/include/debug.c
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* debug.c
|
||||
*
|
||||
* Copyright (C) 2004 - 2015 Vladislav Bolkhovitin <vst@vlnb.net>
|
||||
* Copyright (C) 2004 - 2005 Leonid Stoljar
|
||||
* Copyright (C) 2007 - 2015 SanDisk Corporation
|
||||
*
|
||||
* Contains helper functions for execution tracing and error reporting.
|
||||
* Intended to be included in main .c file.
|
||||
*
|
||||
* 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, version 2
|
||||
* of the License.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
pid_t gettid(void)
|
||||
{
|
||||
return syscall(__NR_gettid);
|
||||
}
|
||||
|
||||
#if defined(DEBUG) || defined(TRACING)
|
||||
|
||||
#define TRACE_BUF_SIZE 512
|
||||
|
||||
static char trace_buf[TRACE_BUF_SIZE];
|
||||
static pthread_spinlock_t trace_buf_lock;
|
||||
|
||||
int debug_print_prefix(unsigned long trace_flag, const char *prefix,
|
||||
const char *func, int line)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
pthread_spin_lock(&trace_buf_lock);
|
||||
|
||||
if (trace_flag & TRACE_TIME) {
|
||||
struct tm t;
|
||||
time_t tt;
|
||||
|
||||
time(&tt);
|
||||
localtime_r(&tt, &t);
|
||||
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "%d:%d:%d ",
|
||||
t.tm_hour, t.tm_min, t.tm_sec);
|
||||
}
|
||||
if (trace_flag & TRACE_PID)
|
||||
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "[%d]: ",
|
||||
gettid());
|
||||
if (prefix != NULL)
|
||||
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "%s:", prefix);
|
||||
if (trace_flag & TRACE_FUNCTION)
|
||||
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "%s:", func);
|
||||
if (trace_flag & TRACE_LINE)
|
||||
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "%i:", line);
|
||||
|
||||
if (i > 0)
|
||||
PRINTN(LOG_INFO, "%s", trace_buf);
|
||||
|
||||
pthread_spin_unlock(&trace_buf_lock);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
void debug_print_buffer(const void *data, int len)
|
||||
{
|
||||
int z, z1, i;
|
||||
const unsigned char *buf = (const unsigned char *) data;
|
||||
int f = 0;
|
||||
|
||||
if (buf == NULL)
|
||||
return;
|
||||
|
||||
pthread_spin_lock(&trace_buf_lock);
|
||||
|
||||
PRINT(LOG_INFO, " (h)___0__1__2__3__4__5__6__7__8__9__A__B__C__D__E__F");
|
||||
for (z = 0, z1 = 0, i = 0; z < len; z++) {
|
||||
if (z % 16 == 0) {
|
||||
if (z != 0) {
|
||||
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i,
|
||||
" ");
|
||||
for (; (z1 < z) && (i < TRACE_BUF_SIZE - 1);
|
||||
z1++) {
|
||||
if ((buf[z1] >= 0x20) &&
|
||||
(buf[z1] < 0x80))
|
||||
trace_buf[i++] = buf[z1];
|
||||
else
|
||||
trace_buf[i++] = '.';
|
||||
}
|
||||
trace_buf[i] = '\0';
|
||||
PRINT(LOG_INFO, "%s", trace_buf);
|
||||
i = 0;
|
||||
f = 1;
|
||||
}
|
||||
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i,
|
||||
"%4x: ", z);
|
||||
}
|
||||
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "%02x ",
|
||||
buf[z]);
|
||||
}
|
||||
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, " ");
|
||||
for (; (z1 < z) && (i < TRACE_BUF_SIZE - 1); z1++) {
|
||||
if ((buf[z1] > 0x20) && (buf[z1] < 0x80))
|
||||
trace_buf[i++] = buf[z1];
|
||||
else
|
||||
trace_buf[i++] = '.';
|
||||
}
|
||||
trace_buf[i] = '\0';
|
||||
if (f)
|
||||
PRINT(LOG_INFO, "%s", trace_buf);
|
||||
else
|
||||
PRINT(LOG_INFO, "%s", trace_buf);
|
||||
|
||||
pthread_spin_unlock(&trace_buf_lock);
|
||||
}
|
||||
|
||||
int debug_init(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = pthread_spin_init(&trace_buf_lock, PTHREAD_PROCESS_PRIVATE);
|
||||
if (res != 0) {
|
||||
res = errno;
|
||||
PRINT_ERROR("pthread_spin_init() failed: %s", strerror(res));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void debug_done(void)
|
||||
{
|
||||
pthread_spin_destroy(&trace_buf_lock);
|
||||
}
|
||||
|
||||
#endif /* DEBUG || TRACING */
|
||||
@@ -24,6 +24,8 @@
|
||||
#include <sys/types.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
extern pid_t gettid(void);
|
||||
|
||||
@@ -55,8 +57,21 @@ extern pid_t gettid(void);
|
||||
#define TRACE_ORDER 0x00008000
|
||||
#define TRACE_ALL 0xffffffff
|
||||
|
||||
#define PRINT(format, args...) fprintf(stdout, format "\n", ## args);
|
||||
#define PRINTN(format, args...) fprintf(stdout, format, ## args);
|
||||
#define PRINT(priority, format, args...) \
|
||||
do { \
|
||||
if (log_daemon) \
|
||||
syslog(priority, format "\n", ## args); \
|
||||
else \
|
||||
fprintf(stdout, format "\n", ## args); \
|
||||
} while (0)
|
||||
|
||||
#define PRINTN(priority, format, args...) \
|
||||
do { \
|
||||
if (log_daemon) \
|
||||
syslog(priority, format, ## args); \
|
||||
else \
|
||||
fprintf(stdout, format, ## args); \
|
||||
} while (0)
|
||||
|
||||
extern char *app_name;
|
||||
#define LOG_PREFIX app_name
|
||||
@@ -69,6 +84,7 @@ extern char *app_name;
|
||||
|
||||
#if defined(DEBUG) || defined(TRACING)
|
||||
|
||||
extern bool log_daemon;
|
||||
extern unsigned long trace_flag;
|
||||
|
||||
extern int debug_init(void);
|
||||
@@ -80,24 +96,23 @@ extern void debug_done(void);
|
||||
*/
|
||||
|
||||
extern int debug_print_prefix(unsigned long trace_flag, const char *prefix,
|
||||
const char *func, int line);
|
||||
const char *func, int line);
|
||||
extern void debug_print_buffer(const void *data, int len);
|
||||
|
||||
#define TRACE(trace, format, args...) \
|
||||
do { \
|
||||
if (trace_flag & (trace)) \
|
||||
{ \
|
||||
debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__, \
|
||||
__LINE__); \
|
||||
PRINT(format, args); \
|
||||
} \
|
||||
} while(0)
|
||||
if (trace_flag & (trace)) { \
|
||||
debug_print_prefix(trace_flag, __LOG_PREFIX, \
|
||||
__func__, __LINE__); \
|
||||
PRINT(LOG_DEBUG, format, args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define PRINT_BUFFER(message, buff, len) \
|
||||
do { \
|
||||
PRINT("%s:", message); \
|
||||
debug_print_buffer(buff, len); \
|
||||
} while(0)
|
||||
PRINT(LOG_INFO, "%s:", message); \
|
||||
debug_print_buffer(buff, len); \
|
||||
} while (0)
|
||||
|
||||
#else /* DEBUG || TRACING */
|
||||
|
||||
@@ -115,142 +130,126 @@ static inline void debug_done(void) {}
|
||||
|
||||
#define TRACE_MEM(format, args...) \
|
||||
do { \
|
||||
if (trace_flag & TRACE_MEMORY) \
|
||||
{ \
|
||||
debug_print_prefix(trace_flag, NULL, __FUNCTION__, \
|
||||
__LINE__); \
|
||||
PRINT(format, args); \
|
||||
} \
|
||||
} while(0)
|
||||
if (trace_flag & TRACE_MEMORY) { \
|
||||
debug_print_prefix(trace_flag, NULL, \
|
||||
__func__, __LINE__); \
|
||||
PRINT(LOG_DEBUG, format, args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TRACE_DBG(format, args...) \
|
||||
do { \
|
||||
if (trace_flag & TRACE_DEBUG) \
|
||||
{ \
|
||||
debug_print_prefix(trace_flag, NULL, __FUNCTION__, \
|
||||
__LINE__); \
|
||||
PRINT(format, args); \
|
||||
} \
|
||||
} while(0)
|
||||
if (trace_flag & TRACE_DEBUG) { \
|
||||
debug_print_prefix(trace_flag, NULL, \
|
||||
__func__, __LINE__); \
|
||||
PRINT(LOG_DEBUG, format, args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TRACE_DBG_SPECIAL(args...) TRACE(TRACE_DEBUG|TRACE_SPECIAL, args)
|
||||
|
||||
#define TRACE_MGMT_DBG(format, args...) \
|
||||
do { \
|
||||
if (trace_flag & TRACE_MGMT_DEBUG) \
|
||||
{ \
|
||||
debug_print_prefix(trace_flag, NULL, __FUNCTION__, \
|
||||
__LINE__); \
|
||||
PRINT(format, args); \
|
||||
} \
|
||||
} while(0)
|
||||
if (trace_flag & TRACE_MGMT_DEBUG) { \
|
||||
debug_print_prefix(trace_flag, NULL, \
|
||||
__func__, __LINE__); \
|
||||
PRINT(LOG_DEBUG, format, args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TRACE_BUFFER(message, buff, len) \
|
||||
do { \
|
||||
if (trace_flag & TRACE_BUFF) \
|
||||
{ \
|
||||
debug_print_prefix(trace_flag, NULL, __FUNCTION__, \
|
||||
__LINE__); \
|
||||
PRINT("%s:", message); \
|
||||
debug_print_buffer(buff, len); \
|
||||
} \
|
||||
} while(0)
|
||||
if (trace_flag & TRACE_BUFF) { \
|
||||
debug_print_prefix(trace_flag, NULL, \
|
||||
__func__, __LINE__); \
|
||||
PRINT(LOG_DEBUG, "%s:", message); \
|
||||
debug_print_buffer(buff, len); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TRACE_BUFF_FLAG(flag, message, buff, len) \
|
||||
do { \
|
||||
if (trace_flag & (flag)) \
|
||||
{ \
|
||||
debug_print_prefix(trace_flag, NULL, __FUNCTION__, \
|
||||
__LINE__); \
|
||||
PRINT("%s:", message); \
|
||||
debug_print_buffer(buff, len); \
|
||||
} \
|
||||
} while(0)
|
||||
if (trace_flag & (flag)) { \
|
||||
debug_print_prefix(trace_flag, NULL, \
|
||||
__func__, __LINE__); \
|
||||
PRINT(LOG_DEBUG, "%s:", message); \
|
||||
debug_print_buffer(buff, len); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define PRINT_INFO(format, args...) \
|
||||
do { \
|
||||
debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__, \
|
||||
__LINE__); \
|
||||
PRINT(format, args); \
|
||||
} while(0)
|
||||
debug_print_prefix(trace_flag, __LOG_PREFIX, \
|
||||
__func__, __LINE__); \
|
||||
PRINT(LOG_INFO, format, args); \
|
||||
} while (0)
|
||||
|
||||
#define PRINT_WARNING(format, args...) \
|
||||
do { \
|
||||
debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__, \
|
||||
__LINE__); \
|
||||
PRINT("***WARNING*** " format, args); \
|
||||
} while(0)
|
||||
debug_print_prefix(trace_flag, __LOG_PREFIX, \
|
||||
__func__, __LINE__); \
|
||||
PRINT(LOG_WARNING, "***WARNING*** " format, args); \
|
||||
} while (0)
|
||||
|
||||
#define PRINT_ERROR(format, args...) \
|
||||
do { \
|
||||
debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__, \
|
||||
__LINE__); \
|
||||
PRINT("***ERROR*** " format, args); \
|
||||
} while(0)
|
||||
debug_print_prefix(trace_flag, __LOG_PREFIX, \
|
||||
__func__, __LINE__); \
|
||||
PRINT(LOG_ERR, "***ERROR*** " format, args); \
|
||||
} while (0)
|
||||
|
||||
#define TRACE_ENTRY() \
|
||||
do { \
|
||||
if (trace_flag & TRACE_ENTRYEXIT) \
|
||||
{ \
|
||||
if (trace_flag & TRACE_PID) \
|
||||
{ \
|
||||
PRINT("[%d]: ENTRY %s", gettid(), \
|
||||
__FUNCTION__); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
PRINT("ENTRY %s", __FUNCTION__); \
|
||||
} \
|
||||
} \
|
||||
} while(0)
|
||||
if (trace_flag & TRACE_ENTRYEXIT) { \
|
||||
if (trace_flag & TRACE_PID) { \
|
||||
PRINT(LOG_DEBUG, "[%d]: ENTRY %s", \
|
||||
gettid(), __func__); \
|
||||
} else { \
|
||||
PRINT(LOG_DEBUG, "ENTRY %s", \
|
||||
__func__); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TRACE_EXIT() \
|
||||
do { \
|
||||
if (trace_flag & TRACE_ENTRYEXIT) \
|
||||
{ \
|
||||
if (trace_flag & TRACE_PID) \
|
||||
{ \
|
||||
PRINT("[%d]: EXIT %s", gettid(), \
|
||||
__FUNCTION__); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
PRINT("EXIT %s", __FUNCTION__); \
|
||||
} \
|
||||
} \
|
||||
} while(0)
|
||||
if (trace_flag & TRACE_ENTRYEXIT) { \
|
||||
if (trace_flag & TRACE_PID) { \
|
||||
PRINT(LOG_DEBUG, "[%d]: EXIT %s", \
|
||||
gettid(), __func__); \
|
||||
} else { \
|
||||
PRINT(LOG_DEBUG, "EXIT %s", __func__); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TRACE_EXIT_RES(res) \
|
||||
do { \
|
||||
if (trace_flag & TRACE_ENTRYEXIT) \
|
||||
{ \
|
||||
if (trace_flag & TRACE_PID) \
|
||||
{ \
|
||||
PRINT("[%d]: EXIT %s: %ld", gettid(), \
|
||||
__FUNCTION__, (long)(res)); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
PRINT("EXIT %s: %ld", __FUNCTION__, (long)(res)); \
|
||||
} \
|
||||
} \
|
||||
} while(0)
|
||||
if (trace_flag & TRACE_ENTRYEXIT) { \
|
||||
if (trace_flag & TRACE_PID) { \
|
||||
PRINT(LOG_DEBUG, "[%d]: EXIT %s: %ld", \
|
||||
gettid(), __func__, \
|
||||
(long)(res)); \
|
||||
} else { \
|
||||
PRINT(LOG_DEBUG, "EXIT %s: %ld", \
|
||||
__func__, (long)(res)); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TRACE_EXIT_HRES(res) \
|
||||
do { \
|
||||
if (trace_flag & TRACE_ENTRYEXIT) \
|
||||
{ \
|
||||
if (trace_flag & TRACE_PID) \
|
||||
{ \
|
||||
PRINT("[%d]: EXIT %s: 0x%lx", gettid(), \
|
||||
__FUNCTION__, (long)(res)); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
PRINT("EXIT %s: %lx", __FUNCTION__, (long)(res)); \
|
||||
} \
|
||||
} \
|
||||
} while(0)
|
||||
if (trace_flag & TRACE_ENTRYEXIT) { \
|
||||
if (trace_flag & TRACE_PID) { \
|
||||
PRINT(LOG_DEBUG, "[%d]: EXIT %s: 0x%lx",\
|
||||
gettid(), __func__, \
|
||||
(long)(res)); \
|
||||
} else { \
|
||||
PRINT(LOG_DEBUG, "EXIT %s: %lx", \
|
||||
__func__, (long)(res)); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#else /* DEBUG */
|
||||
|
||||
@@ -271,39 +270,25 @@ do { \
|
||||
#ifdef LOG_PREFIX
|
||||
|
||||
#define PRINT_INFO(format, args...) \
|
||||
do { \
|
||||
PRINT("%s: " format, LOG_PREFIX, args); \
|
||||
} while(0)
|
||||
PRINT(LOG_INFO, "%s: " format, LOG_PREFIX, args) \
|
||||
|
||||
#define PRINT_WARNING(format, args...) \
|
||||
do { \
|
||||
PRINT("%s: ***WARNING*** " \
|
||||
format, LOG_PREFIX, args); \
|
||||
} while(0)
|
||||
PRINT(LOG_WARNING, "%s: ***WARNING*** " format, \
|
||||
LOG_PREFIX, args) \
|
||||
|
||||
#define PRINT_ERROR(format, args...) \
|
||||
do { \
|
||||
PRINT("%s: ***ERROR*** " \
|
||||
format, LOG_PREFIX, args); \
|
||||
} while(0)
|
||||
PRINT(LOG_ERR, "%s: ***ERROR*** " format, \
|
||||
LOG_PREFIX, args) \
|
||||
|
||||
#else
|
||||
|
||||
#define PRINT_INFO(format, args...) \
|
||||
do { \
|
||||
PRINT(format, args); \
|
||||
} while(0)
|
||||
#define PRINT_INFO(format, args...) PRINT(LOG_INFO, format, args)
|
||||
|
||||
#define PRINT_WARNING(format, args...) \
|
||||
do { \
|
||||
PRINT("***WARNING*** " format, args); \
|
||||
} while(0)
|
||||
|
||||
PRINT(LOG_WARNING, "***WARNING*** " format, args) \
|
||||
|
||||
#define PRINT_ERROR(format, args...) \
|
||||
do { \
|
||||
PRINT("***ERROR*** " format, args); \
|
||||
} while(0)
|
||||
PRINT(LOG_ERR, "***ERROR*** " format, args) \
|
||||
|
||||
#endif /* LOG_PREFIX */
|
||||
|
||||
24
usr/include/version.h
Normal file
24
usr/include/version.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* version.h
|
||||
*
|
||||
* Copyright (C) 2015 SanDisk Corporation
|
||||
*
|
||||
* Contains macroses for execution tracing and error reporting
|
||||
*
|
||||
* 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, version 2
|
||||
* of the License.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __VERSION_H
|
||||
#define __VERSION_H
|
||||
|
||||
#define VERSION_STR "3.1.0-pre1"
|
||||
|
||||
#endif /* __VERSION_H */
|
||||
104
usr/stpgd/Makefile
Normal file
104
usr/stpgd/Makefile
Normal file
@@ -0,0 +1,104 @@
|
||||
ifndef PREFIX
|
||||
PREFIX=/usr/local
|
||||
endif
|
||||
|
||||
SHELL=/bin/bash
|
||||
|
||||
SRCS_F = stpgd_main.c debug.c
|
||||
OBJS_F = $(SRCS_F:.c=.o)
|
||||
|
||||
#SRCS_C =
|
||||
#OBJS_C = $(SRCS_C:.c=.o)
|
||||
|
||||
SCST_INC_DIR := $(shell if [ -e "$$PWD/../../scst" ]; \
|
||||
then echo "$$PWD/../../scst/include"; \
|
||||
else echo "$(DESTDIR)$(PREFIX)/include/scst"; fi)
|
||||
DEBUG_INC_DIR := ../include
|
||||
INSTALL_DIR := $(DESTDIR)$(PREFIX)/sbin
|
||||
ON_STPG := $(DESTDIR)$(PREFIX)/bin/scst/scst_on_stpg
|
||||
|
||||
CFLAGS += -O2 -Wall -Wextra -Wno-unused-parameter -Wstrict-prototypes \
|
||||
-I$(SCST_INC_DIR) -I$(DEBUG_INC_DIR) -D_GNU_SOURCE -D__USE_FILE_OFFSET64 \
|
||||
-D__USE_LARGEFILE64
|
||||
PROGS = stpgd
|
||||
LIBS = -lpthread
|
||||
|
||||
CFLAGS += -DEXTRACHECKS
|
||||
#CFLAGS += -DTRACING
|
||||
CFLAGS += -DDEBUG -g -fno-inline -fno-inline-functions
|
||||
CFLAGS += -W -Wno-unused-parameter
|
||||
CFLAGS += $(LOCAL_CFLAGS)
|
||||
|
||||
#CFLAGS += -DDEBUG_NOMEM
|
||||
|
||||
all: $(PROGS)
|
||||
|
||||
stpgd: .depend_f $(OBJS_F)
|
||||
$(CC) $(OBJS_F) $(LIBS) $(LOCAL_LD_FLAGS) -o $@
|
||||
|
||||
#cdrom_tgt: .depend_c $(OBJS_C)
|
||||
# $(CC) $(OBJS_C) $(LIBS) $(LOCAL_LD_FLAGS) -o $@
|
||||
|
||||
ifeq (.depend_f,$(wildcard .depend_f))
|
||||
-include .depend_f
|
||||
endif
|
||||
|
||||
#ifeq (.depend_c,$(wildcard .depend_c))
|
||||
#-include .depend_c
|
||||
#endif
|
||||
|
||||
%.o: %.c Makefile
|
||||
$(CC) -c -o $(@) $(CFLAGS) $(<)
|
||||
|
||||
.depend_f:
|
||||
$(CC) -M $(CFLAGS) $(SRCS_F) >$(@)
|
||||
|
||||
#.depend_c:
|
||||
# $(CC) -M $(CFLAGS) $(SRCS_C) >$(@)
|
||||
|
||||
install: all
|
||||
install -d $(INSTALL_DIR)
|
||||
install -m 700 $(PROGS) $(INSTALL_DIR)
|
||||
install -m 700 scst_on_stpg $(ON_STPG)
|
||||
|
||||
uninstall:
|
||||
rm -f $(INSTALL_DIR)/$(PROGS)
|
||||
rm -rf $(INSTALL_DIR)
|
||||
|
||||
clean:
|
||||
rm -f *.o $(PROGS) .depend*
|
||||
|
||||
extraclean: clean
|
||||
rm -f *.orig *.rej
|
||||
|
||||
2release:
|
||||
sed -i.aa s/"^C\?FLAGS += \-DEXTRACHECKS"/"#CFLAGS += \-DEXTRACHECKS"/ Makefile
|
||||
grep "^#CFLAGS += \-DEXTRACHECKS" Makefile >/dev/null
|
||||
sed -i.aa s/"^#\?CFLAGS += \-DTRACING"/"CFLAGS += \-DTRACING"/ Makefile
|
||||
grep "^CFLAGS += \-DTRACING" Makefile >/dev/null
|
||||
sed -i.aa s/"^C\?FLAGS += \-DDEBUG -g -fno-inline -fno-inline-functions"/"#CFLAGS += \-DDEBUG -g -fno-inline -fno-inline-functions"/ Makefile
|
||||
grep "^#CFLAGS += \-DDEBUG -g -fno-inline -fno-inline-functions" Makefile >/dev/null
|
||||
rm Makefile.aa
|
||||
|
||||
2debug:
|
||||
sed -i.aa s/"^#\?CFLAGS += \-DEXTRACHECKS"/"CFLAGS += \-DEXTRACHECKS"/ Makefile
|
||||
grep "^CFLAGS += \-DEXTRACHECKS" Makefile >/dev/null
|
||||
sed -i.aa s/"^C\?FLAGS += \-DTRACING"/"#CFLAGS += \-DTRACING"/ Makefile
|
||||
grep "^#CFLAGS += \-DTRACING" Makefile >/dev/null
|
||||
sed -i.aa s/"^#\?CFLAGS += \-DDEBUG -g -fno-inline -fno-inline-functions"/"CFLAGS += \-DDEBUG -g -fno-inline -fno-inline-functions"/ Makefile
|
||||
grep "^CFLAGS += \-DDEBUG -g -fno-inline -fno-inline-functions" Makefile >/dev/null
|
||||
rm Makefile.aa
|
||||
|
||||
2perf:
|
||||
sed -i.aa s/"^C\?FLAGS += \-DEXTRACHECKS"/"#CFLAGS += \-DEXTRACHECKS"/ Makefile
|
||||
grep "^#CFLAGS += \-DEXTRACHECKS" Makefile >/dev/null
|
||||
sed -i.aa s/"^C\?FLAGS += \-DTRACING"/"#CFLAGS += \-DTRACING"/ Makefile
|
||||
grep "^#CFLAGS += \-DTRACING" Makefile >/dev/null
|
||||
sed -i.aa s/"^C\?FLAGS += \-DDEBUG -g -fno-inline -fno-inline-functions"/"#CFLAGS += \-DDEBUG -g -fno-inline -fno-inline-functions"/ Makefile
|
||||
grep "^#CFLAGS += \-DDEBUG -g -fno-inline -fno-inline-functions" Makefile >/dev/null
|
||||
rm Makefile.aa
|
||||
|
||||
release-archive:
|
||||
../../scripts/generate-release-archive stpgd "$$(sed -n 's/^#define[[:blank:]]VERSION_STR[[:blank:]]*\"\([^\"]*\)\".*/\1/p' stpgd_main.c)"
|
||||
|
||||
.PHONY: all install uninstall clean extraclean 2release 2debug 2perf
|
||||
9
usr/stpgd/README
Normal file
9
usr/stpgd/README
Normal file
@@ -0,0 +1,9 @@
|
||||
This is stpgd service called by the SCST core upon receiving SET TARGET
|
||||
PORT GROUPS command via SCST events subsystem. In turn, stpgd calls
|
||||
external script to actually modify ALUA state as requested by the SET
|
||||
TARGET PORT GROUPS command via cluster manager and SCST sysfs. You can
|
||||
find example of such script in scst_on_stpg file.
|
||||
|
||||
Reason why such dual stage approach is used is, because there is no way
|
||||
from inside the kernel to control execution of external programs and
|
||||
there is no way to write a service calling IOCTLs on shell.
|
||||
1
usr/stpgd/debug.c
Normal file
1
usr/stpgd/debug.c
Normal file
@@ -0,0 +1 @@
|
||||
#include "../include/debug.c"
|
||||
11
usr/stpgd/scst_on_stpg
Normal file
11
usr/stpgd/scst_on_stpg
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Script invoked by SCST for processing a SCSI SET TARGET PORT GROUPS command
|
||||
#
|
||||
# Arguments: SCST_DEVICE_NAME (device name where this STPG command was
|
||||
# received on), SCST_PREV_ALUA_STATE, SCST_ALUA_STATE,
|
||||
# SCST_DEVICE_GROUP and SCST_TARGET_GROUP + environmental variables
|
||||
# with the same names set
|
||||
#
|
||||
|
||||
echo $SCST_ALUA_STATE >/sys/kernel/scst_tgt/device_groups/$SCST_DEVICE_GROUP/target_groups/$SCST_TARGET_GROUP/state
|
||||
562
usr/stpgd/stpgd_main.c
Normal file
562
usr/stpgd/stpgd_main.c
Normal file
@@ -0,0 +1,562 @@
|
||||
/*
|
||||
* stpgd_main.c
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <malloc.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdbool.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <syslog.h>
|
||||
#include <signal.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include "version.h"
|
||||
#include "debug.h"
|
||||
#include "scst_event.h"
|
||||
|
||||
char *app_name;
|
||||
|
||||
#define DEFAULT_TRANSITION_TIME 17
|
||||
|
||||
#if defined(DEBUG) || defined(TRACING)
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#define DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MINOR | TRACE_PID | \
|
||||
TRACE_FUNCTION | TRACE_SPECIAL | TRACE_MGMT | TRACE_MGMT_DEBUG | \
|
||||
TRACE_TIME)
|
||||
|
||||
#define TRACE_SN(args...) TRACE(TRACE_SCSI_SERIALIZING, args)
|
||||
|
||||
#else /* DEBUG */
|
||||
|
||||
# ifdef TRACING
|
||||
#define DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MGMT | \
|
||||
TRACE_TIME | TRACE_SPECIAL)
|
||||
# else
|
||||
#define DEFAULT_LOG_FLAGS 0
|
||||
# endif
|
||||
#endif /* DEBUG */
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
|
||||
|
||||
bool log_daemon = true;
|
||||
unsigned long trace_flag = DEFAULT_LOG_FLAGS;
|
||||
#endif /* defined(DEBUG) || defined(TRACING) */
|
||||
|
||||
int transition_timeout = DEFAULT_TRANSITION_TIME;
|
||||
|
||||
static struct option const long_options[] = {
|
||||
{"path", required_argument, 0, 'p'},
|
||||
{"timeout", required_argument, 0, 't'},
|
||||
{"foreground", no_argument, 0, 'f'},
|
||||
#if defined(DEBUG) || defined(TRACING)
|
||||
{"debug", required_argument, 0, 'd'},
|
||||
#endif
|
||||
{"version", no_argument, 0, 'v'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
|
||||
int stpg_init_report_pipe[2];
|
||||
char *stpg_path;
|
||||
|
||||
static void usage(int status)
|
||||
{
|
||||
if (status != 0)
|
||||
fprintf(stderr, "Try '%s --help' for more information.\n", app_name);
|
||||
else {
|
||||
printf("Usage: %s [OPTIONS]\n", app_name);
|
||||
printf("STPG target daemon\n");
|
||||
printf(" -f, --foreground make the program run in the foreground\n");
|
||||
printf(" -p, --path absolute path to the STPG script\n");
|
||||
printf(" -t, --timeout transition timeout\n");
|
||||
#if defined(DEBUG) || defined(TRACING)
|
||||
printf(" -d, --debug=level debug tracing level\n");
|
||||
#endif
|
||||
printf(" -h, --help display this help and exit\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void stpg_handle_tm_received(struct scst_event_user *event_user)
|
||||
{
|
||||
/*
|
||||
* Put code to abort state transition here, if this STPG cmd,
|
||||
* identified by cmd_to_abort_tag or RESET, requested to be aborted
|
||||
*/
|
||||
}
|
||||
|
||||
int invoke_stpg(const uint8_t *device_name,
|
||||
const struct scst_event_stpg_descr *descr, pid_t *out_pid)
|
||||
{
|
||||
char *args[7], *env[7];
|
||||
int res = 0, ret, i;
|
||||
pid_t c_pid;
|
||||
|
||||
args[0] = stpg_path;
|
||||
args[1] = (char *)device_name;
|
||||
args[2] = (char *)descr->prev_state;
|
||||
args[3] = (char *)descr->new_state;
|
||||
args[4] = (char *)descr->dg_name;
|
||||
args[5] = (char *)descr->tg_name;
|
||||
args[6] = NULL;
|
||||
|
||||
env[0] = "PATH=/bin:/usr/bin:/sbin:/usr/sbin";
|
||||
ret = asprintf(&env[1], "SCST_DEVICE_NAME=%s", device_name);
|
||||
if (ret < 0) {
|
||||
res = -errno;
|
||||
PRINT_ERROR("asprintf() failed: %d (%s)", res, strerror(-res));
|
||||
goto out;
|
||||
}
|
||||
ret = asprintf(&env[2], "SCST_PREV_ALUA_STATE=%s", descr->prev_state);
|
||||
if (ret < 0) {
|
||||
res = -errno;
|
||||
PRINT_ERROR("asprintf() failed: %d (%s)", res, strerror(-res));
|
||||
goto out;
|
||||
}
|
||||
ret = asprintf(&env[3], "SCST_ALUA_STATE=%s", descr->new_state);
|
||||
if (ret < 0) {
|
||||
res = -errno;
|
||||
PRINT_ERROR("asprintf() failed: %d (%s)", res, strerror(-res));
|
||||
goto out;
|
||||
}
|
||||
ret = asprintf(&env[4], "SCST_DEVICE_GROUP=%s", descr->dg_name);
|
||||
if (ret < 0) {
|
||||
res = -errno;
|
||||
PRINT_ERROR("asprintf() failed: %d (%s)", res, strerror(-res));
|
||||
goto out;
|
||||
}
|
||||
ret = asprintf(&env[5], "SCST_TARGET_GROUP=%s", descr->tg_name);
|
||||
if (ret < 0) {
|
||||
res = -errno;
|
||||
PRINT_ERROR("asprintf() failed: %d (%s)", res, strerror(-res));
|
||||
goto out;
|
||||
}
|
||||
env[6] = NULL;
|
||||
|
||||
PRINT_INFO("Invoking script %s with parameters: %s %s %s %s %s and environment: "
|
||||
"%s %s %s %s %s", stpg_path, args[1], args[2], args[3],
|
||||
args[4], args[5], env[1], env[2], env[3], env[4], env[5]);
|
||||
|
||||
c_pid = fork();
|
||||
if (c_pid == 0) {
|
||||
ret = setpgid(getpid(), getpid());
|
||||
if (ret < 0) {
|
||||
res = -errno;
|
||||
PRINT_ERROR("setgid failed %d (%s)", ret, strerror(-ret));
|
||||
}
|
||||
TRACE_DBG("pgid %d (pid %d)", getpgid(getpid()), getpid());
|
||||
ret = execve(stpg_path, args, env);
|
||||
if (ret < 0) {
|
||||
res = -errno;
|
||||
PRINT_ERROR("EXEC failed %d (%s)", ret, strerror(-ret));
|
||||
}
|
||||
exit(0);
|
||||
} else if (c_pid < 0) {
|
||||
res = -errno;
|
||||
PRINT_ERROR("fork() failed: %d (%s)", res, strerror(-res));
|
||||
}
|
||||
|
||||
*out_pid = c_pid;
|
||||
|
||||
for (i = 1; i < (signed)ARRAY_SIZE(env); i++)
|
||||
free(env[i]);
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Returns 0, if the pid is still running, >0 if it was exited or <0 error code */
|
||||
int wait_until_finished(pid_t pid, unsigned long deadline, int *status, int child)
|
||||
{
|
||||
int res;
|
||||
time_t start, end;
|
||||
double elapsed;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
time(&start);
|
||||
do {
|
||||
res = waitpid(pid, status, WNOHANG);
|
||||
if (res != 0) {
|
||||
if (res < 0) {
|
||||
res = -errno;
|
||||
PRINT_ERROR("Waitpid for pid %d (child %d) "
|
||||
"failed: %d (%s)", pid, child,
|
||||
errno, strerror(errno));
|
||||
}
|
||||
break;
|
||||
}
|
||||
sleep(0.1);
|
||||
time(&end);
|
||||
elapsed = difftime(end, start);
|
||||
} while (elapsed < deadline);
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
int handle_stpg_received(struct scst_event_user *event_user)
|
||||
{
|
||||
const struct scst_event_stpg_payload *p = (struct scst_event_stpg_payload *)event_user->out_event.payload;
|
||||
int num, k;
|
||||
int res = 0;
|
||||
pid_t pids[p->stpg_descriptors_cnt];
|
||||
|
||||
TRACE_DBG("device name %s, stpg_descriptors_cnt %d", p->device_name,
|
||||
p->stpg_descriptors_cnt);
|
||||
|
||||
for (num = 0; num < p->stpg_descriptors_cnt; num++) {
|
||||
res = invoke_stpg(p->device_name, &p->stpg_descriptors[num], &pids[num]);
|
||||
TRACE_DBG("num %d, res %d, pid %d", num, res, pids[num]);
|
||||
if (res != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
TRACE_DBG("num %d", num);
|
||||
for (k = 0; k < num; k++) {
|
||||
int status = 0, rc;
|
||||
|
||||
TRACE_DBG("k %d, pid %d", k, pids[k]);
|
||||
|
||||
rc = wait_until_finished(pids[k], transition_timeout, &status, k);
|
||||
TRACE_DBG("rc %d, status %d", rc, WEXITSTATUS(status));
|
||||
if (rc > 0) {
|
||||
if (res == 0)
|
||||
res = WEXITSTATUS(status);
|
||||
continue;
|
||||
} else if (rc < 0) {
|
||||
if (res == 0)
|
||||
res = rc;
|
||||
continue;
|
||||
}
|
||||
|
||||
PRINT_WARNING("on_stpg %d (pid %d) did not finish on time - "
|
||||
"sending SIGTERM", k, pids[k]);
|
||||
if (res == 0)
|
||||
res = -ETIMEDOUT;
|
||||
rc = killpg(pids[k], SIGTERM);
|
||||
if (rc < 0)
|
||||
PRINT_ERROR("Failed to send SIGTERM to child %d (pid %d): %d/%s",
|
||||
k, pids[k], errno, strerror(errno));
|
||||
|
||||
rc = wait_until_finished(pids[k], 1, &status, k);
|
||||
if (rc != 0)
|
||||
continue;
|
||||
|
||||
while (1) {
|
||||
PRINT_WARNING("on_stpg %d (pid %d) did not finish on time - "
|
||||
"sending SIGKILL", k, pids[k]);
|
||||
rc = killpg(pids[k], SIGKILL);
|
||||
if (rc < 0) {
|
||||
PRINT_ERROR("Failed to send SIGKILL to child %d "
|
||||
"(pid %d): %d/%s", k, pids[k], errno,
|
||||
strerror(errno));
|
||||
break;
|
||||
}
|
||||
rc = wait_until_finished(pids[k], 1, &status, k);
|
||||
if (rc != 0)
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int stpg_event_loop(void)
|
||||
{
|
||||
int res = 0, status;
|
||||
int event_fd;
|
||||
uint8_t event_user_buf[1024*1024];
|
||||
pid_t c_pid = 0;
|
||||
struct pollfd pl;
|
||||
struct scst_event_user *event_user =
|
||||
(struct scst_event_user *)event_user_buf;
|
||||
struct scst_event e1;
|
||||
bool first_error = true;
|
||||
|
||||
event_fd = open(SCST_EVENT_DEV, O_RDWR);
|
||||
if (event_fd < 0) {
|
||||
res = -errno;
|
||||
PRINT_ERROR("Unable to open SCST event device %s (%s)",
|
||||
SCST_EVENT_DEV, strerror(-res));
|
||||
goto out;
|
||||
}
|
||||
|
||||
close(stpg_init_report_pipe[0]);
|
||||
|
||||
if (log_daemon)
|
||||
res = write(stpg_init_report_pipe[1], &res, sizeof(res));
|
||||
|
||||
close(stpg_init_report_pipe[1]);
|
||||
|
||||
memset(&pl, 0, sizeof(pl));
|
||||
pl.fd = event_fd;
|
||||
pl.events = POLLIN;
|
||||
|
||||
memset(&e1, 0, sizeof(e1));
|
||||
e1.event_code = SCST_EVENT_STPG_USER_INVOKE;
|
||||
strncpy(e1.issuer_name, SCST_EVENT_SCST_CORE_ISSUER,
|
||||
sizeof(e1.issuer_name));
|
||||
e1.issuer_name[sizeof(e1.issuer_name)-1] = '\0';
|
||||
PRINT_INFO("Setting allowed event code %d, issuer_name %s",
|
||||
e1.event_code, e1.issuer_name);
|
||||
|
||||
res = ioctl(event_fd, SCST_EVENT_ALLOW_EVENT, &e1);
|
||||
if (res != 0) {
|
||||
res = -errno;
|
||||
PRINT_ERROR("SCST_EVENT_ALLOW_EVENT failed: %d (%s)",
|
||||
res, strerror(-res));
|
||||
goto out;
|
||||
}
|
||||
|
||||
e1.event_code = SCST_EVENT_TM_FN_RECEIVED;
|
||||
strncpy(e1.issuer_name, SCST_EVENT_SCST_CORE_ISSUER,
|
||||
sizeof(e1.issuer_name));
|
||||
e1.issuer_name[sizeof(e1.issuer_name)-1] = '\0';
|
||||
PRINT_INFO("Setting allowed event code %d, issuer_name %s",
|
||||
e1.event_code, e1.issuer_name);
|
||||
res = ioctl(event_fd, SCST_EVENT_ALLOW_EVENT, &e1);
|
||||
if (res != 0) {
|
||||
res = -errno;
|
||||
PRINT_ERROR("SCST_EVENT_ALLOW_EVENT failed: %d (%s)",
|
||||
res, strerror(-res));
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
memset(event_user_buf, 0, sizeof(event_user_buf));
|
||||
event_user->max_event_size = sizeof(event_user_buf);
|
||||
res = ioctl(event_fd, SCST_EVENT_GET_NEXT_EVENT, event_user);
|
||||
if (res != 0) {
|
||||
res = -errno;
|
||||
switch (-res) {
|
||||
case ESRCH:
|
||||
case EBUSY:
|
||||
TRACE_MGMT_DBG("SCST_EVENT_GET_NEXT_EVENT "
|
||||
"returned %d (%s)", res, strerror(res));
|
||||
/* go through */
|
||||
case EINTR:
|
||||
continue;
|
||||
case EAGAIN:
|
||||
TRACE_DBG("SCST_EVENT_GET_NEXT_EVENT, "
|
||||
"returned EAGAIN (%d)", -res);
|
||||
continue;
|
||||
default:
|
||||
PRINT_ERROR("SCST_EVENT_GET_NEXT_EVENT "
|
||||
"failed: %d (%s)", res, strerror(-res));
|
||||
if (!first_error)
|
||||
goto out;
|
||||
first_error = false;
|
||||
continue;
|
||||
}
|
||||
first_error = true;
|
||||
again_poll:
|
||||
res = poll(&pl, 1, c_pid > 0 ? 1 : 0);
|
||||
if (res > 0)
|
||||
continue;
|
||||
else if (res == 0)
|
||||
goto again_poll;
|
||||
else {
|
||||
res = -errno;
|
||||
switch (res) {
|
||||
case ESRCH:
|
||||
case EBUSY:
|
||||
case EAGAIN:
|
||||
TRACE_MGMT_DBG("poll() returned %d "
|
||||
"(%s)", res, strerror(-res));
|
||||
case EINTR:
|
||||
goto again_poll;
|
||||
default:
|
||||
PRINT_ERROR("poll() failed: %d (%s)",
|
||||
res, strerror(-res));
|
||||
goto again_poll;
|
||||
}
|
||||
}
|
||||
}
|
||||
first_error = true;
|
||||
#ifdef DEBUG
|
||||
PRINT_INFO("event_code %d, issuer_name %s",
|
||||
event_user->out_event.event_code,
|
||||
event_user->out_event.issuer_name);
|
||||
#endif
|
||||
if (event_user->out_event.payload_len != 0)
|
||||
TRACE_BUFFER("payload", event_user->out_event.payload,
|
||||
event_user->out_event.payload_len);
|
||||
|
||||
if (event_user->out_event.event_code == SCST_EVENT_STPG_USER_INVOKE) {
|
||||
c_pid = fork();
|
||||
if (c_pid == -1)
|
||||
PRINT_ERROR("Failed to fork: %d", c_pid);
|
||||
else if (c_pid == 0) {
|
||||
struct scst_event_notify_done d;
|
||||
|
||||
signal(SIGCHLD, SIG_DFL);
|
||||
|
||||
status = handle_stpg_received(event_user);
|
||||
|
||||
memset(&d, 0, sizeof(d));
|
||||
d.event_id = event_user->out_event.event_id;
|
||||
d.status = status;
|
||||
res = ioctl(event_fd, SCST_EVENT_NOTIFY_DONE, &d);
|
||||
if (res != 0) {
|
||||
res = -errno;
|
||||
PRINT_ERROR("SCST_EVENT_NOTIFY_DONE "
|
||||
"failed: %s (res %d)",
|
||||
strerror(-res), res);
|
||||
} else
|
||||
PRINT_INFO("STPG event completed with status %d", status);
|
||||
exit(res);
|
||||
}
|
||||
} else if (event_user->out_event.event_code == SCST_EVENT_TM_FN_RECEIVED)
|
||||
stpg_handle_tm_received(event_user);
|
||||
else
|
||||
PRINT_ERROR("Unknown event %d received", event_user->out_event.event_code);
|
||||
}
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
void sig_chld(int signal)
|
||||
{
|
||||
/* Check just in case */
|
||||
if (signal == SIGCHLD) {
|
||||
TRACE_DBG("Cleanup zombie (pid %d)", getpid());
|
||||
wait(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int res = 0, ch, longindex;
|
||||
pid_t pid;
|
||||
struct sigaction sa;
|
||||
|
||||
setlinebuf(stdout);
|
||||
|
||||
openlog(argv[0], LOG_PID, LOG_USER);
|
||||
|
||||
res = pipe(stpg_init_report_pipe);
|
||||
if (res == -1) {
|
||||
res = -errno;
|
||||
PRINT_ERROR("Pipe failed: %d (%s)", res, strerror(-res));
|
||||
goto out;
|
||||
}
|
||||
|
||||
sa.sa_handler = &sig_chld;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
|
||||
if (sigaction(SIGCHLD, &sa, 0) == -1) {
|
||||
PRINT_ERROR("sigaction() failed: %d/%s", errno, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise we could die in some later write() during the event_loop()
|
||||
* instead of getting EPIPE!
|
||||
*/
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
res = debug_init();
|
||||
if (res != 0)
|
||||
goto out;
|
||||
|
||||
app_name = argv[0];
|
||||
|
||||
while ((ch = getopt_long(argc, argv, "+d:fp:t:hv",
|
||||
long_options, &longindex)) >= 0) {
|
||||
switch (ch) {
|
||||
case 'p':
|
||||
stpg_path = optarg;
|
||||
break;
|
||||
#if defined(DEBUG) || defined(TRACING)
|
||||
case 'd':
|
||||
trace_flag = strtol(optarg, (char **)NULL, 0);
|
||||
break;
|
||||
#endif
|
||||
case 'v':
|
||||
printf("%s version %s\n", app_name, VERSION_STR);
|
||||
goto out_done;
|
||||
case 'f':
|
||||
log_daemon = false;
|
||||
break;
|
||||
case 't':
|
||||
transition_timeout = strtol(optarg, (char **)NULL, 0);
|
||||
if (transition_timeout < 0) {
|
||||
printf("Invalid timeout %d\n", transition_timeout);
|
||||
res = -EINVAL;
|
||||
goto out_done;
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
usage(0);
|
||||
goto out_done;
|
||||
default:
|
||||
goto out_usage;
|
||||
}
|
||||
}
|
||||
|
||||
if (!stpg_path)
|
||||
stpg_path = "/usr/local/bin/scst/scst_on_stpg";
|
||||
|
||||
if (access(stpg_path, X_OK) == -1) {
|
||||
PRINT_ERROR("Script file \" %s \"does not exist or not "
|
||||
"executable", stpg_path);
|
||||
res = -1;
|
||||
goto out_done;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
PRINT_INFO("trace_flag %lx", trace_flag);
|
||||
#endif
|
||||
if (log_daemon) {
|
||||
trace_flag &= ~TRACE_TIME;
|
||||
trace_flag &= ~TRACE_PID;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
PRINT_ERROR("starting daemon failed(%d)", pid);
|
||||
res = pid;
|
||||
goto out_done;
|
||||
} else if (pid) {
|
||||
int res1 = -1;
|
||||
|
||||
close(stpg_init_report_pipe[1]);
|
||||
if ((unsigned)read(stpg_init_report_pipe[0], &res1, sizeof(res1)) < sizeof(res1)) {
|
||||
res = -1;
|
||||
goto out_done;
|
||||
} else {
|
||||
res = res1;
|
||||
goto out_done;
|
||||
}
|
||||
}
|
||||
|
||||
close(0);
|
||||
open("/dev/null", O_RDWR);
|
||||
dup2(0, 1);
|
||||
dup2(0, 2);
|
||||
setsid();
|
||||
}
|
||||
|
||||
res = stpg_event_loop();
|
||||
|
||||
out_done:
|
||||
debug_done();
|
||||
|
||||
out:
|
||||
closelog();
|
||||
return res;
|
||||
|
||||
out_usage:
|
||||
usage(1);
|
||||
goto out_done;
|
||||
}
|
||||
Reference in New Issue
Block a user