[stgt] [PATCH] Make the backing-store modules shared objects that are loaded at runtime
ronnie sahlberg
ronniesahlberg at gmail.com
Tue Aug 13 17:10:18 CEST 2013
Tomo ?
On Sat, Aug 10, 2013 at 2:37 AM, ronnie sahlberg
<ronniesahlberg at gmail.com> wrote:
> On Fri, Aug 9, 2013 at 11:09 PM, Dan Mick <dan.mick at inktank.com> wrote:
>> I can confirm that, with all instances of 'rdb' changed to 'rbd', and the
>> obvious change to bs_rbd.c, this works for bs_rbd as well. If I'd been more
>> intelligent I'd have committed your patch locally before hacking on it.
>> It's late. :)
>
> Thanks. I have updated the patch.
>>
>> +1 on the idea and overall structure; it would be interesting in particular
>> to hear others' opinions about the choice of /usr/lib/tgtd/backing-store,
>> although it seems fine to me.
>
> I have no strong feelings about where to store the modules so if
> anyone has a better suggestion for the directory, please let me know
> and I'll change it.
>
>
>>
>> Ceph users would benefit greatly from the ability for the official released
>> packages (assuming the package maintainers will do it) to contain the rbd
>> backend without requiring compilation.
>
> Yes. It would also be really neat if at a later stage one could
> unload/reload a bs module at runtime. This I think would greatly
> improve the experience for people that are developing and testing
> backends.
>
>>
>>
>> On 08/09/2013 10:47 PM, Dan Mick wrote:
>>>
>>> This would be super-cool, as it would allow building and distributing
>>> rbd support without requiring users of the package to install Ceph just
>>> to use stgt without Ceph.
>>>
>>> Some initial comments below:
>>>
>>> On 08/09/2013 04:02 PM, Ronnie Sahlberg wrote:
>>>>
>>>> Turn most of TGTD into a shared library libtgt.so and install it under
>>>> $(PREFIX)/lib/tgtd
>>>>
>>>> Change the six backing stores bs_aio/null/rdb/rdwr/sg/ssc into shared
>>>> objects
>>>> and install them under $(PREFIX)/lib/tgtd/backing-store
>>>>
>>>> When tgtd is starting, have it traverse the directory for backing
>>>> stores and
>>>> automatically load and initialize all backing stores files that are
>>>> found.
>>>>
>>>> This allows for example to distribute bs_aio.so as a separate package
>>>> since it has additional dependencies (libaio) that tgtd itself does
>>>> not have
>>>> Similarly for bs_rdb.so.
>>>> This means that core TGTD can be distributed with minimal dependencies
>>>> and backends that add additional dependencies can be distributed
>>>> separately.
>>>>
>>>> Once we have this basics for a modularized TGTD later patches can
>>>> build ontop
>>>> of this and add features such as :
>>>> * list all modules and which luns are using them
>>>> * unload module if unused
>>>> * re-load module
>>>> But that can come in later patches. Lets get the basics in first.
>>>>
>>>> Signed-off-by: Ronnie Sahlberg <ronniesahlberg at gmail.com>
>>>> ---
>>>> usr/Makefile | 42 ++++++---
>>>> usr/bs.c | 46 +++++++++
>>>> usr/bs_aio.c | 2 +-
>>>> usr/bs_null.c | 2 +-
>>>> usr/bs_rdwr.c | 2 +-
>>>> usr/bs_sg.c | 2 +-
>>>> usr/bs_ssc.c | 2 +-
>>>
>>>
>>> No 2-line change to bs_rbd.c?
>>>
>>>> usr/target.c | 285
>>>> +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>>>> usr/tgtd.c | 276
>>>> +-------------------------------------------------------
>>>> usr/tgtd.h | 2 +
>>>> 10 files changed, 360 insertions(+), 301 deletions(-)
>>>>
>>>> diff --git a/usr/Makefile b/usr/Makefile
>>>> index 453eb1a..5c76f43 100644
>>>> --- a/usr/Makefile
>>>> +++ b/usr/Makefile
>>>> @@ -1,4 +1,5 @@
>>>> sbindir ?= $(PREFIX)/sbin
>>>> +libdir ?= $(PREFIX)/lib/tgtd
>>>>
>>>> ifneq ($(shell test -e /usr/include/linux/signalfd.h && echo 1),)
>>>> CFLAGS += -DUSE_SIGNALFD
>>>> @@ -11,17 +12,14 @@ endif
>>>> TGTD_OBJS += $(addprefix iscsi/, conn.o param.o session.o \
>>>> iscsid.o target.o chap.o sha1.o md5.o transport.o iscsi_tcp.o \
>>>> isns.o)
>>>> -TGTD_OBJS += bs_rdwr.o
>>>>
>>>> ifneq ($(CEPH_RBD),)
>>>> -TGTD_OBJS += bs_rbd.o
>>>> -LIBS += -lrados -lrbd
>>>> +BS_OBJS += bs_rdb.so
>>>
>>>
>>> bs_rbd.so, not rdb
>>>
>>> It may seem weird to compile, but it *should* be enough to add package
>>> 'librbd1' (which will also pull in librados2) to allow the build with
>>> CEPH_RBD enabled. If Tomo agrees this patch is worthwhile, I'd sure
>>> like to see it go in with all bsdrvs supported.
>>>
>>>> endif
>>>>
>>>> ifneq ($(shell test -e /usr/include/sys/eventfd.h && test -e
>>>> /usr/include/libaio.h && echo 1),)
>>>> CFLAGS += -DUSE_EVENTFD
>>>> -TGTD_OBJS += bs_aio.o
>>>> -LIBS += -laio
>>>> +BS_OBJS += bs_aio.so
>>>> endif
>>>>
>>>> ifneq ($(ISCSI_RDMA),)
>>>> @@ -40,25 +38,32 @@ CFLAGS += -g -O2 -fno-strict-aliasing
>>>> endif
>>>> CFLAGS += -Wall -Wstrict-prototypes -fPIC
>>>> CFLAGS += -DTGT_VERSION=\"$(VERSION)$(EXTRAVERSION)\"
>>>> +CFLAGS += -DBSDIR=\"$(DESTDIR)$(libdir)/backing-store\"
>>>>
>>>> LIBS += -lpthread
>>>>
>>>> PROGRAMS += tgtd tgtadm tgtimg
>>>> -TGTD_OBJS += tgtd.o mgmt.o target.o scsi.o log.o driver.o util.o
>>>> work.o \
>>>> - concat_buf.o parser.o spc.o sbc.o mmc.o osd.o scc.o smc.o \
>>>> - ssc.o bs_ssc.o libssc.o \
>>>> - bs_null.o bs_sg.o bs.o libcrc32c.o
>>>> +TGTD_OBJS += tgtd.o
>>>> +LIBTGT_OBJS = bs.o \
>>>> + concat_buf.o driver.o libcrc32c.o libssc.o log.o mgmt.o mmc.o \
>>>> + osd.o parser.o sbc.o scc.o scsi.o smc.o spc.o ssc.o \
>>>> + target.o util.o work.o
>>>> +
>>>> +BS_OBJS += bs_null.so bs_rdwr.so bs_sg.so bs_ssc.so
>>>>
>>>> TGTD_DEP = $(TGTD_OBJS:.o=.d)
>>>>
>>>> .PHONY:all
>>>> -all: $(PROGRAMS)
>>>> +all: libtgt.so $(PROGRAMS) $(BS_OBJS)
>>>>
>>>> tgtd: $(TGTD_OBJS)
>>>> - $(CC) $^ -o $@ $(LIBS)
>>>> + $(CC) $^ -o $@ $(LIBS) libtgt.so
>>>>
>>>> -include $(TGTD_DEP)
>>>>
>>>> +libtgt.so: $(LIBTGT_OBJS)
>>>> + $(CC) -shared -fPIC -DPIC $^ -o $@ -ldl
>>>> +
>>>> TGTADM_OBJS = tgtadm.o concat_buf.o
>>>> TGTADM_DEP = $(TGTADM_OBJS:.o=.d)
>>>>
>>>> @@ -79,11 +84,24 @@ tgtimg: $(TGTIMG_OBJS)
>>>> $(CC) -c $(CFLAGS) $*.c -o $*.o
>>>> @$(CC) -MM $(CFLAGS) -MF $*.d -MT $*.o $*.c
>>>>
>>>> +%.so: %.c
>>>> + $(CC) -shared $(CFLAGS) $*.c -o $*.so
>>>> +
>>>> +bs_aio.so: bs_aio.c
>>>> + $(CC) -shared $(CFLAGS) bs_aio.c -o bs_aio.so -laio
>>>> +
>>>> +bs_rdb.so: bs_rdb.c
>>>> + $(CC) -shared $(CFLAGS) bs_rdb.c -o bs_rdb.so -lrados -lrbd
>>>> +
>>>> .PHONY: install
>>>> install: $(PROGRAMS)
>>>> install -d -m 755 $(DESTDIR)$(sbindir)
>>>> install -m 755 $(PROGRAMS) $(DESTDIR)$(sbindir)
>>>> + install -d -m 755 $(DESTDIR)$(libdir)/backing-store
>>>> + install -m 755 $(BS_OBJS) $(DESTDIR)$(libdir)/backing-store
>>>> + install -m 755 libtgt.so $(DESTDIR)$(libdir)
>>>> + ldconfig $(DESTDIR)$(libdir)
>>>>
>>>> .PHONY: clean
>>>> clean:
>>>> - rm -f *.[od] $(PROGRAMS) iscsi/*.[od] ibmvio/*.[od] fc/*.[od]
>>>> + rm -f *.[od] *.so $(PROGRAMS) iscsi/*.[od] ibmvio/*.[od] fc/*.[od]
>>>> diff --git a/usr/bs.c b/usr/bs.c
>>>> index 65c332e..7974e3a 100644
>>>> --- a/usr/bs.c
>>>> +++ b/usr/bs.c
>>>> @@ -19,6 +19,8 @@
>>>> * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
>>>> * 02110-1301 USA
>>>> */
>>>> +#include <dirent.h>
>>>> +#include <dlfcn.h>
>>>> #include <errno.h>
>>>> #include <string.h>
>>>> #include <inttypes.h>
>>>> @@ -307,10 +309,54 @@ destroy_cond_mutex:
>>>> return 1;
>>>> }
>>>>
>>>> +void update_lbppbe(struct scsi_lu *lu, int blksize)
>>>> +{
>>>> + lu->attrs.lbppbe = 0;
>>>> + while (blksize > (1U << lu->blk_shift)) {
>>>> + lu->attrs.lbppbe++;
>>>> + blksize >>= 1;
>>>> + }
>>>> +}
>>>> +
>>>> int bs_init(void)
>>>> {
>>>> + DIR *dir;
>>>> int ret;
>>>>
>>>> + dir = opendir(BSDIR);
>>>> + if (dir == NULL) {
>>>> + eprintf("could not open backing-store module directory %s\n",
>>>> + BSDIR);
>>>> + } else {
>>>> + struct dirent *dirent;
>>>> + void *handle;
>>>> + while ((dirent = readdir(dir))) {
>>>> + char *soname;
>>>> + void (*register_bs_module)(void);
>>>> +
>>>> + if (dirent->d_name[0] == '.') {
>>>> + continue;
>>>> + }
>>>> +
>>>> + asprintf(&soname, "%s/%s", BSDIR, dirent->d_name);
>>>> + handle = dlopen(soname, RTLD_NOW|RTLD_LOCAL);
>>>> + if (handle == NULL) {
>>>> + eprintf("failed to dlopen backing-store "
>>>> + "module %s error %s \n",
>>>> + soname, dlerror());
>>>> + continue;
>>>> + }
>>>> + register_bs_module = dlsym(handle, "register_bs_module");
>>>> + if (register_bs_module == NULL) {
>>>> + eprintf("could not find register_bs_module "
>>>> + "symbol in module %s\n",
>>>> + soname);
>>>> + continue;
>>>> + }
>>>> + register_bs_module();
>>>> + }
>>>> + closedir(dir);
>>>> + }
>>>> ret = bs_init_signalfd();
>>>> if (!ret) {
>>>> eprintf("use signalfd notification\n");
>>>> diff --git a/usr/bs_aio.c b/usr/bs_aio.c
>>>> index c0cbadd..cc59cf6 100644
>>>> --- a/usr/bs_aio.c
>>>> +++ b/usr/bs_aio.c
>>>> @@ -414,7 +414,7 @@ static struct backingstore_template aio_bst = {
>>>> .bs_cmd_submit = bs_aio_cmd_submit,
>>>> };
>>>>
>>>> -__attribute__((constructor)) static void bs_rdwr_constructor(void)
>>>> +void register_bs_module(void)
>>>> {
>>>> register_backingstore_template(&aio_bst);
>>>> }
>>>> diff --git a/usr/bs_null.c b/usr/bs_null.c
>>>> index d463f18..4dbe144 100644
>>>> --- a/usr/bs_null.c
>>>> +++ b/usr/bs_null.c
>>>> @@ -56,7 +56,7 @@ static struct backingstore_template null_bst = {
>>>> .bs_cmd_submit = bs_null_cmd_submit,
>>>> };
>>>>
>>>> -__attribute__((constructor)) static void bs_null_constructor(void)
>>>> +void register_bs_module(void)
>>>> {
>>>> register_backingstore_template(&null_bst);
>>>> }
>>>> diff --git a/usr/bs_rdwr.c b/usr/bs_rdwr.c
>>>> index 47d2d99..82807d1 100644
>>>> --- a/usr/bs_rdwr.c
>>>> +++ b/usr/bs_rdwr.c
>>>> @@ -423,7 +423,7 @@ static struct backingstore_template rdwr_bst = {
>>>> .bs_oflags_supported = O_SYNC | O_DIRECT,
>>>> };
>>>>
>>>> -__attribute__((constructor)) static void bs_rdwr_constructor(void)
>>>> +void register_bs_module(void)
>>>> {
>>>> register_backingstore_template(&rdwr_bst);
>>>> }
>>>> diff --git a/usr/bs_sg.c b/usr/bs_sg.c
>>>> index 5f1e687..43dc5f3 100644
>>>> --- a/usr/bs_sg.c
>>>> +++ b/usr/bs_sg.c
>>>> @@ -517,7 +517,7 @@ static struct device_type_template sg_template = {
>>>> .cmd_passthrough = bs_sg_rw,
>>>> };
>>>>
>>>> -__attribute__((constructor)) static void bs_sg_constructor(void)
>>>> +void register_bs_module(void)
>>>> {
>>>> register_backingstore_template(&sg_bst);
>>>> register_backingstore_template(&bsg_bst);
>>>> diff --git a/usr/bs_ssc.c b/usr/bs_ssc.c
>>>> index 117e274..98b84b5 100644
>>>> --- a/usr/bs_ssc.c
>>>> +++ b/usr/bs_ssc.c
>>>> @@ -702,7 +702,7 @@ static struct backingstore_template ssc_bst = {
>>>> .bs_cmd_submit = bs_thread_cmd_submit,
>>>> };
>>>>
>>>> -__attribute__((constructor)) static void bs_ssc_constructor(void)
>>>> +void register_bs_module(void)
>>>> {
>>>> register_backingstore_template(&ssc_bst);
>>>> }
>>>> diff --git a/usr/target.c b/usr/target.c
>>>> index b1729b3..b7872fb 100644
>>>> --- a/usr/target.c
>>>> +++ b/usr/target.c
>>>> @@ -19,6 +19,7 @@
>>>> * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
>>>> * 02110-1301 USA
>>>> */
>>>> +#include <ctype.h>
>>>> #include <errno.h>
>>>> #include <fcntl.h>
>>>> #include <inttypes.h>
>>>> @@ -27,8 +28,10 @@
>>>> #include <string.h>
>>>> #include <time.h>
>>>> #include <unistd.h>
>>>> +#include <sys/epoll.h>
>>>> #include <sys/socket.h>
>>>> #include <sys/time.h>
>>>> +#include <sys/wait.h>
>>>>
>>>> #include "list.h"
>>>> #include "util.h"
>>>> @@ -42,8 +45,11 @@
>>>> #include "spc.h"
>>>>
>>>> static LIST_HEAD(device_type_list);
>>>> +static LIST_HEAD(tgt_events_list);
>>>> +static LIST_HEAD(tgt_sched_events_list);
>>>>
>>>> static struct target global_target;
>>>> +int ep_fd;
>>>>
>>>> int device_type_register(struct device_type_template *t)
>>>> {
>>>> @@ -2411,15 +2417,6 @@ tgtadm_err lld_show(struct concat_buf *b)
>>>> return TGTADM_SUCCESS;
>>>> }
>>>>
>>>> -void update_lbppbe(struct scsi_lu *lu, int blksize)
>>>> -{
>>>> - lu->attrs.lbppbe = 0;
>>>> - while (blksize > (1U << lu->blk_shift)) {
>>>> - lu->attrs.lbppbe++;
>>>> - blksize >>= 1;
>>>> - }
>>>> -}
>>>> -
>>>> int is_system_available(void)
>>>> {
>>>> return (sys_state == TGT_SYSTEM_READY);
>>>> @@ -2430,6 +2427,276 @@ int is_system_inactive(void)
>>>> return list_empty(&target_list);
>>>> }
>>>>
>>>> +int tgt_event_add(int fd, int events, event_handler_t handler, void
>>>> *data)
>>>> +{
>>>> + struct epoll_event ev;
>>>> + struct event_data *tev;
>>>> + int err;
>>>> +
>>>> + tev = zalloc(sizeof(*tev));
>>>> + if (!tev)
>>>> + return -ENOMEM;
>>>> +
>>>> + tev->data = data;
>>>> + tev->handler = handler;
>>>> + tev->fd = fd;
>>>> +
>>>> + memset(&ev, 0, sizeof(ev));
>>>> + ev.events = events;
>>>> + ev.data.ptr = tev;
>>>> + err = epoll_ctl(ep_fd, EPOLL_CTL_ADD, fd, &ev);
>>>> + if (err) {
>>>> + eprintf("Cannot add fd, %m\n");
>>>> + free(tev);
>>>> + } else
>>>> + list_add(&tev->e_list, &tgt_events_list);
>>>> +
>>>> + return err;
>>>> +}
>>>> +
>>>> +static struct event_data *tgt_event_lookup(int fd)
>>>> +{
>>>> + struct event_data *tev;
>>>> +
>>>> + list_for_each_entry(tev, &tgt_events_list, e_list) {
>>>> + if (tev->fd == fd)
>>>> + return tev;
>>>> + }
>>>> + return NULL;
>>>> +}
>>>> +
>>>> +void tgt_event_del(int fd)
>>>> +{
>>>> + struct event_data *tev;
>>>> + int ret;
>>>> +
>>>> + tev = tgt_event_lookup(fd);
>>>> + if (!tev) {
>>>> + eprintf("Cannot find event %d\n", fd);
>>>> + return;
>>>> + }
>>>> +
>>>> + ret = epoll_ctl(ep_fd, EPOLL_CTL_DEL, fd, NULL);
>>>> + if (ret < 0)
>>>> + eprintf("fail to remove epoll event, %s\n", strerror(errno));
>>>> +
>>>> + list_del(&tev->e_list);
>>>> + free(tev);
>>>> +}
>>>> +
>>>> +int tgt_event_modify(int fd, int events)
>>>> +{
>>>> + struct epoll_event ev;
>>>> + struct event_data *tev;
>>>> +
>>>> + tev = tgt_event_lookup(fd);
>>>> + if (!tev) {
>>>> + eprintf("Cannot find event %d\n", fd);
>>>> + return -EINVAL;
>>>> + }
>>>> +
>>>> + memset(&ev, 0, sizeof(ev));
>>>> + ev.events = events;
>>>> + ev.data.ptr = tev;
>>>> +
>>>> + return epoll_ctl(ep_fd, EPOLL_CTL_MOD, fd, &ev);
>>>> +}
>>>> +
>>>> +void tgt_init_sched_event(struct event_data *evt,
>>>> + sched_event_handler_t sched_handler, void *data)
>>>> +{
>>>> + evt->sched_handler = sched_handler;
>>>> + evt->scheduled = 0;
>>>> + evt->data = data;
>>>> + INIT_LIST_HEAD(&evt->e_list);
>>>> +}
>>>> +
>>>> +void tgt_add_sched_event(struct event_data *evt)
>>>> +{
>>>> + if (!evt->scheduled) {
>>>> + evt->scheduled = 1;
>>>> + list_add_tail(&evt->e_list, &tgt_sched_events_list);
>>>> + }
>>>> +}
>>>> +
>>>> +void tgt_remove_sched_event(struct event_data *evt)
>>>> +{
>>>> + if (evt->scheduled) {
>>>> + evt->scheduled = 0;
>>>> + list_del_init(&evt->e_list);
>>>> + }
>>>> +}
>>>> +
>>>> +int tgt_exec_scheduled(void)
>>>> +{
>>>> + struct list_head *last_sched;
>>>> + struct event_data *tev, *tevn;
>>>> + int work_remains = 0;
>>>> +
>>>> + if (!list_empty(&tgt_sched_events_list)) {
>>>> + /* execute only work scheduled till now */
>>>> + last_sched = tgt_sched_events_list.prev;
>>>> + list_for_each_entry_safe(tev, tevn, &tgt_sched_events_list,
>>>> + e_list) {
>>>> + tgt_remove_sched_event(tev);
>>>> + tev->sched_handler(tev);
>>>> + if (&tev->e_list == last_sched)
>>>> + break;
>>>> + }
>>>> + if (!list_empty(&tgt_sched_events_list))
>>>> + work_remains = 1;
>>>> + }
>>>> + return work_remains;
>>>> +}
>>>> +
>>>> +/* strcpy, while eating multiple white spaces */
>>>> +static void str_spacecpy(char **dest, const char *src)
>>>> +{
>>>> + const char *s = src;
>>>> + char *d = *dest;
>>>> +
>>>> + while (*s) {
>>>> + if (isspace(*s)) {
>>>> + if (!*(s+1))
>>>> + break;
>>>> + if (isspace(*(s+1))) {
>>>> + s++;
>>>> + continue;
>>>> + }
>>>> + }
>>>> + *d++ = *s++;
>>>> + }
>>>> + *d = '\0';
>>>> +}
>>>> +
>>>> +int call_program(const char *cmd, void (*callback)(void *data, int
>>>> result),
>>>> + void *data, char *output, int op_len, int flags)
>>>> +{
>>>> + pid_t pid;
>>>> + int fds[2], ret, i;
>>>> + char *pos, arg[256];
>>>> + char *argv[sizeof(arg) / 2];
>>>> +
>>>> + i = 0;
>>>> + pos = arg;
>>>> + str_spacecpy(&pos, cmd);
>>>> + if (strchr(cmd, ' ')) {
>>>> + while (pos != '\0')
>>>> + argv[i++] = strsep(&pos, " ");
>>>> + } else
>>>> + argv[i++] = arg;
>>>> + argv[i] = NULL;
>>>> +
>>>> + ret = pipe(fds);
>>>> + if (ret < 0) {
>>>> + eprintf("pipe create failed for %s, %m\n", cmd);
>>>> + return ret;
>>>> + }
>>>> +
>>>> + dprintf("%s, pipe: %d %d\n", cmd, fds[0], fds[1]);
>>>> +
>>>> + pid = fork();
>>>> + if (pid < 0) {
>>>> + eprintf("fork failed for: %s, %m\n", cmd);
>>>> + close(fds[0]);
>>>> + close(fds[1]);
>>>> + return pid;
>>>> + }
>>>> +
>>>> + if (!pid) {
>>>> + close(1);
>>>> + ret = dup(fds[1]);
>>>> + if (ret < 0) {
>>>> + eprintf("dup failed for: %s, %m\n", cmd);
>>>> + exit(-1);
>>>> + }
>>>> + close(fds[0]);
>>>> + execv(argv[0], argv);
>>>> +
>>>> + eprintf("execv failed for: %s, %m\n", cmd);
>>>> + exit(-1);
>>>> + } else {
>>>> + struct timeval tv;
>>>> + fd_set rfds;
>>>> + int ret_sel;
>>>> +
>>>> + close(fds[1]);
>>>> + /* 0.1 second is okay, as the initiator will retry anyway */
>>>> + do {
>>>> + FD_ZERO(&rfds);
>>>> + FD_SET(fds[0], &rfds);
>>>> + tv.tv_sec = 0;
>>>> + tv.tv_usec = 100000;
>>>> + ret_sel = select(fds[0]+1, &rfds, NULL, NULL, &tv);
>>>> + } while (ret_sel < 0 && errno == EINTR);
>>>> + if (ret_sel <= 0) { /* error or timeout */
>>>> + eprintf("timeout on redirect callback, terminating "
>>>> + "child pid %d\n", pid);
>>>> + kill(pid, SIGTERM);
>>>> + }
>>>> + do {
>>>> + ret = waitpid(pid, &i, 0);
>>>> + } while (ret < 0 && errno == EINTR);
>>>> + if (ret < 0) {
>>>> + eprintf("waitpid failed for: %s, %m\n", cmd);
>>>> + close(fds[0]);
>>>> + return ret;
>>>> + }
>>>> + if (ret_sel > 0) {
>>>> + ret = read(fds[0], output, op_len);
>>>> + if (ret < 0) {
>>>> + eprintf("failed to get output from: %s\n", cmd);
>>>> + close(fds[0]);
>>>> + return ret;
>>>> + }
>>>> + }
>>>> +
>>>> + if (callback)
>>>> + callback(data, WEXITSTATUS(i));
>>>> + close(fds[0]);
>>>> + }
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +struct tgt_param {
>>>> + int (*parse_func)(char *);
>>>> + char *name;
>>>> +};
>>>> +
>>>> +static struct tgt_param params[64];
>>>> +
>>>> +int setup_param(char *name, int (*parser)(char *))
>>>> +{
>>>> + int i;
>>>> +
>>>> + for (i = 0; i < ARRAY_SIZE(params); i++)
>>>> + if (!params[i].name)
>>>> + break;
>>>> +
>>>> + if (i < ARRAY_SIZE(params)) {
>>>> + params[i].name = name;
>>>> + params[i].parse_func = parser;
>>>> +
>>>> + return 0;
>>>> + } else
>>>> + return -1;
>>>> +}
>>>> +
>>>> +int parse_params(char *name, char *p)
>>>> +{
>>>> + int i;
>>>> +
>>>> + for (i = 0; i < ARRAY_SIZE(params) && params[i].name; i++) {
>>>> + if (!strcmp(name, params[i].name))
>>>> + return params[i].parse_func(p);
>>>> + }
>>>> +
>>>> + fprintf(stderr, "'%s' is an unknown option\n", name);
>>>> +
>>>> + return -1;
>>>> +}
>>>> +
>>>> static void __attribute__((constructor)) target_constructor(void)
>>>> {
>>>> static int global_target_aids[DEFAULT_NR_ACCOUNT];
>>>> diff --git a/usr/tgtd.c b/usr/tgtd.c
>>>> index f985510..3ef7220 100644
>>>> --- a/usr/tgtd.c
>>>> +++ b/usr/tgtd.c
>>>> @@ -30,11 +30,9 @@
>>>> #include <stdlib.h>
>>>> #include <string.h>
>>>> #include <unistd.h>
>>>> -#include <ctype.h>
>>>> #include <sys/resource.h>
>>>> #include <sys/epoll.h>
>>>> #include <sys/types.h>
>>>> -#include <sys/wait.h>
>>>> #include <sys/stat.h>
>>>>
>>>> #include "list.h"
>>>> @@ -44,12 +42,10 @@
>>>> #include "util.h"
>>>>
>>>> unsigned long pagesize, pageshift;
>>>> +extern int ep_fd;
>>>>
>>>> int system_active = 1;
>>>> -static int ep_fd;
>>>> static char program_name[] = "tgtd";
>>>> -static LIST_HEAD(tgt_events_list);
>>>> -static LIST_HEAD(tgt_sched_events_list);
>>>>
>>>> static struct option const long_options[] = {
>>>> {"foreground", no_argument, 0, 'f'},
>>>> @@ -174,238 +170,6 @@ set_rlimit:
>>>> return 0;
>>>> }
>>>>
>>>> -int tgt_event_add(int fd, int events, event_handler_t handler, void
>>>> *data)
>>>> -{
>>>> - struct epoll_event ev;
>>>> - struct event_data *tev;
>>>> - int err;
>>>> -
>>>> - tev = zalloc(sizeof(*tev));
>>>> - if (!tev)
>>>> - return -ENOMEM;
>>>> -
>>>> - tev->data = data;
>>>> - tev->handler = handler;
>>>> - tev->fd = fd;
>>>> -
>>>> - memset(&ev, 0, sizeof(ev));
>>>> - ev.events = events;
>>>> - ev.data.ptr = tev;
>>>> - err = epoll_ctl(ep_fd, EPOLL_CTL_ADD, fd, &ev);
>>>> - if (err) {
>>>> - eprintf("Cannot add fd, %m\n");
>>>> - free(tev);
>>>> - } else
>>>> - list_add(&tev->e_list, &tgt_events_list);
>>>> -
>>>> - return err;
>>>> -}
>>>> -
>>>> -static struct event_data *tgt_event_lookup(int fd)
>>>> -{
>>>> - struct event_data *tev;
>>>> -
>>>> - list_for_each_entry(tev, &tgt_events_list, e_list) {
>>>> - if (tev->fd == fd)
>>>> - return tev;
>>>> - }
>>>> - return NULL;
>>>> -}
>>>> -
>>>> -void tgt_event_del(int fd)
>>>> -{
>>>> - struct event_data *tev;
>>>> - int ret;
>>>> -
>>>> - tev = tgt_event_lookup(fd);
>>>> - if (!tev) {
>>>> - eprintf("Cannot find event %d\n", fd);
>>>> - return;
>>>> - }
>>>> -
>>>> - ret = epoll_ctl(ep_fd, EPOLL_CTL_DEL, fd, NULL);
>>>> - if (ret < 0)
>>>> - eprintf("fail to remove epoll event, %s\n", strerror(errno));
>>>> -
>>>> - list_del(&tev->e_list);
>>>> - free(tev);
>>>> -}
>>>> -
>>>> -int tgt_event_modify(int fd, int events)
>>>> -{
>>>> - struct epoll_event ev;
>>>> - struct event_data *tev;
>>>> -
>>>> - tev = tgt_event_lookup(fd);
>>>> - if (!tev) {
>>>> - eprintf("Cannot find event %d\n", fd);
>>>> - return -EINVAL;
>>>> - }
>>>> -
>>>> - memset(&ev, 0, sizeof(ev));
>>>> - ev.events = events;
>>>> - ev.data.ptr = tev;
>>>> -
>>>> - return epoll_ctl(ep_fd, EPOLL_CTL_MOD, fd, &ev);
>>>> -}
>>>> -
>>>> -void tgt_init_sched_event(struct event_data *evt,
>>>> - sched_event_handler_t sched_handler, void *data)
>>>> -{
>>>> - evt->sched_handler = sched_handler;
>>>> - evt->scheduled = 0;
>>>> - evt->data = data;
>>>> - INIT_LIST_HEAD(&evt->e_list);
>>>> -}
>>>> -
>>>> -void tgt_add_sched_event(struct event_data *evt)
>>>> -{
>>>> - if (!evt->scheduled) {
>>>> - evt->scheduled = 1;
>>>> - list_add_tail(&evt->e_list, &tgt_sched_events_list);
>>>> - }
>>>> -}
>>>> -
>>>> -void tgt_remove_sched_event(struct event_data *evt)
>>>> -{
>>>> - if (evt->scheduled) {
>>>> - evt->scheduled = 0;
>>>> - list_del_init(&evt->e_list);
>>>> - }
>>>> -}
>>>> -
>>>> -/* strcpy, while eating multiple white spaces */
>>>> -void str_spacecpy(char **dest, const char *src)
>>>> -{
>>>> - const char *s = src;
>>>> - char *d = *dest;
>>>> -
>>>> - while (*s) {
>>>> - if (isspace(*s)) {
>>>> - if (!*(s+1))
>>>> - break;
>>>> - if (isspace(*(s+1))) {
>>>> - s++;
>>>> - continue;
>>>> - }
>>>> - }
>>>> - *d++ = *s++;
>>>> - }
>>>> - *d = '\0';
>>>> -}
>>>> -
>>>> -int call_program(const char *cmd, void (*callback)(void *data, int
>>>> result),
>>>> - void *data, char *output, int op_len, int flags)
>>>> -{
>>>> - pid_t pid;
>>>> - int fds[2], ret, i;
>>>> - char *pos, arg[256];
>>>> - char *argv[sizeof(arg) / 2];
>>>> -
>>>> - i = 0;
>>>> - pos = arg;
>>>> - str_spacecpy(&pos, cmd);
>>>> - if (strchr(cmd, ' ')) {
>>>> - while (pos != '\0')
>>>> - argv[i++] = strsep(&pos, " ");
>>>> - } else
>>>> - argv[i++] = arg;
>>>> - argv[i] = NULL;
>>>> -
>>>> - ret = pipe(fds);
>>>> - if (ret < 0) {
>>>> - eprintf("pipe create failed for %s, %m\n", cmd);
>>>> - return ret;
>>>> - }
>>>> -
>>>> - dprintf("%s, pipe: %d %d\n", cmd, fds[0], fds[1]);
>>>> -
>>>> - pid = fork();
>>>> - if (pid < 0) {
>>>> - eprintf("fork failed for: %s, %m\n", cmd);
>>>> - close(fds[0]);
>>>> - close(fds[1]);
>>>> - return pid;
>>>> - }
>>>> -
>>>> - if (!pid) {
>>>> - close(1);
>>>> - ret = dup(fds[1]);
>>>> - if (ret < 0) {
>>>> - eprintf("dup failed for: %s, %m\n", cmd);
>>>> - exit(-1);
>>>> - }
>>>> - close(fds[0]);
>>>> - execv(argv[0], argv);
>>>> -
>>>> - eprintf("execv failed for: %s, %m\n", cmd);
>>>> - exit(-1);
>>>> - } else {
>>>> - struct timeval tv;
>>>> - fd_set rfds;
>>>> - int ret_sel;
>>>> -
>>>> - close(fds[1]);
>>>> - /* 0.1 second is okay, as the initiator will retry anyway */
>>>> - do {
>>>> - FD_ZERO(&rfds);
>>>> - FD_SET(fds[0], &rfds);
>>>> - tv.tv_sec = 0;
>>>> - tv.tv_usec = 100000;
>>>> - ret_sel = select(fds[0]+1, &rfds, NULL, NULL, &tv);
>>>> - } while (ret_sel < 0 && errno == EINTR);
>>>> - if (ret_sel <= 0) { /* error or timeout */
>>>> - eprintf("timeout on redirect callback, terminating "
>>>> - "child pid %d\n", pid);
>>>> - kill(pid, SIGTERM);
>>>> - }
>>>> - do {
>>>> - ret = waitpid(pid, &i, 0);
>>>> - } while (ret < 0 && errno == EINTR);
>>>> - if (ret < 0) {
>>>> - eprintf("waitpid failed for: %s, %m\n", cmd);
>>>> - close(fds[0]);
>>>> - return ret;
>>>> - }
>>>> - if (ret_sel > 0) {
>>>> - ret = read(fds[0], output, op_len);
>>>> - if (ret < 0) {
>>>> - eprintf("failed to get output from: %s\n", cmd);
>>>> - close(fds[0]);
>>>> - return ret;
>>>> - }
>>>> - }
>>>> -
>>>> - if (callback)
>>>> - callback(data, WEXITSTATUS(i));
>>>> - close(fds[0]);
>>>> - }
>>>> -
>>>> - return 0;
>>>> -}
>>>> -
>>>> -static int tgt_exec_scheduled(void)
>>>> -{
>>>> - struct list_head *last_sched;
>>>> - struct event_data *tev, *tevn;
>>>> - int work_remains = 0;
>>>> -
>>>> - if (!list_empty(&tgt_sched_events_list)) {
>>>> - /* execute only work scheduled till now */
>>>> - last_sched = tgt_sched_events_list.prev;
>>>> - list_for_each_entry_safe(tev, tevn, &tgt_sched_events_list,
>>>> - e_list) {
>>>> - tgt_remove_sched_event(tev);
>>>> - tev->sched_handler(tev);
>>>> - if (&tev->e_list == last_sched)
>>>> - break;
>>>> - }
>>>> - if (!list_empty(&tgt_sched_events_list))
>>>> - work_remains = 1;
>>>> - }
>>>> - return work_remains;
>>>> -}
>>>> -
>>>> static void event_loop(void)
>>>> {
>>>> int nevent, i, sched_remains, timeout;
>>>> @@ -471,44 +235,6 @@ static void lld_exit(void)
>>>> }
>>>> }
>>>>
>>>> -struct tgt_param {
>>>> - int (*parse_func)(char *);
>>>> - char *name;
>>>> -};
>>>> -
>>>> -static struct tgt_param params[64];
>>>> -
>>>> -int setup_param(char *name, int (*parser)(char *))
>>>> -{
>>>> - int i;
>>>> -
>>>> - for (i = 0; i < ARRAY_SIZE(params); i++)
>>>> - if (!params[i].name)
>>>> - break;
>>>> -
>>>> - if (i < ARRAY_SIZE(params)) {
>>>> - params[i].name = name;
>>>> - params[i].parse_func = parser;
>>>> -
>>>> - return 0;
>>>> - } else
>>>> - return -1;
>>>> -}
>>>> -
>>>> -static int parse_params(char *name, char *p)
>>>> -{
>>>> - int i;
>>>> -
>>>> - for (i = 0; i < ARRAY_SIZE(params) && params[i].name; i++) {
>>>> - if (!strcmp(name, params[i].name))
>>>> - return params[i].parse_func(p);
>>>> - }
>>>> -
>>>> - fprintf(stderr, "'%s' is an unknown option\n", name);
>>>> -
>>>> - return -1;
>>>> -}
>>>> -
>>>> int main(int argc, char **argv)
>>>> {
>>>> struct sigaction sa_old;
>>>> diff --git a/usr/tgtd.h b/usr/tgtd.h
>>>> index 484e6e9..0d4c6ae 100644
>>>> --- a/usr/tgtd.h
>>>> +++ b/usr/tgtd.h
>>>> @@ -295,6 +295,7 @@ extern void tgt_event_del(int fd);
>>>>
>>>> extern void tgt_add_sched_event(struct event_data *evt);
>>>> extern void tgt_remove_sched_event(struct event_data *evt);
>>>> +extern int tgt_exec_scheduled(void);
>>>>
>>>> extern int tgt_event_modify(int fd, int events);
>>>> extern int target_cmd_queue(int tid, struct scsi_cmd *cmd);
>>>> @@ -373,6 +374,7 @@ extern struct backingstore_template
>>>> *get_backingstore_template(const char *name)
>>>> extern int lld_init_one(int lld_index);
>>>>
>>>> extern int setup_param(char *name, int (*parser)(char *));
>>>> +extern int parse_params(char *name, char *p);
>>>>
>>>> extern int bs_init(void);
>>>>
>>>>
>>
--
To unsubscribe from this list: send the line "unsubscribe stgt" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
More information about the stgt
mailing list