On Fri, Aug 9, 2013 at 11:09 PM, Dan Mick <dan.mick@xxxxxxxxxxx> 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@xxxxxxxxx> >>> --- >>> 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@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html