[stgt] [PATCH] Make the backing-store modules shared objects that are loaded at runtime

ronnie sahlberg ronniesahlberg at gmail.com
Sat Aug 17 19:20:30 CEST 2013


Tomo, ping ?

On Tue, Aug 13, 2013 at 8:10 AM, ronnie sahlberg
<ronniesahlberg at gmail.com> wrote:
> 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