On Wed, Feb 24, 2021 at 08:03:21PM -0500, Ashton Fagg wrote:
> Ashton Fagg <[email protected]> writes:
>
> > Attached is my first attempt at a "proper" solution. I haven't tested it
> > beyond building as I can't take my machine down for testing right now...
> >
> > But, I'd appreciate a sanity check that I'm on the right track.
>
> Sorry for the noise. I think my mail client mangled the attachment, so
> trying again.
>
> diff --git a/usr.sbin/iscsictl/iscsictl.c b/usr.sbin/iscsictl/iscsictl.c
> index 77f9c74abde..5fc326acca6 100644
> --- a/usr.sbin/iscsictl/iscsictl.c
> +++ b/usr.sbin/iscsictl/iscsictl.c
> @@ -40,6 +40,8 @@ struct pdu *ctl_getpdu(char *, size_t);
> int ctl_sendpdu(int, struct pdu *);
> void show_config(struct ctrlmsghdr *, struct pdu *);
> void show_vscsi_stats(struct ctrlmsghdr *, struct pdu *);
> +void poll_and_wait(void);
> +void register_poll(struct ctrlmsghdr *, struct pdu *);
>
> char cbuf[CONTROL_READ_SIZE];
>
> @@ -48,6 +50,14 @@ struct control {
> int fd;
> } control;
>
> +struct poll_result {
> + u_int8_t result;
> + int attempts;
> +} pr;
> +
> +#define POLL_DELAY 1
> +#define POLL_ATTEMPTS 10
> +
> __dead void
> usage(void)
> {
> @@ -68,7 +78,7 @@ main (int argc, char* argv[])
> char *sockname = ISCSID_CONTROL;
> struct session_ctlcfg *s;
> struct iscsi_config *cf;
> - int ch, val = 0;
> + int ch, poll = 0, val = 0;
>
> /* check flags */
> while ((ch = getopt(argc, argv, "f:s:")) != -1) {
> @@ -135,6 +145,9 @@ main (int argc, char* argv[])
> &cf->initiator, sizeof(cf->initiator)) == -1)
> err(1, "control_compose");
> }
> +
> + /* Reloading, so poll afterwards. */
> + poll = 1;
> SIMPLEQ_FOREACH(s, &cf->sessions, entry) {
> struct ctrldata cdv[3];
> bzero(cdv, sizeof(cdv));
> @@ -174,6 +187,12 @@ main (int argc, char* argv[])
>
> run();
>
> + /* If we've reloaded, we probably should wait in case any new
> connections
> + need to come up (or fail). */
> + if (poll) {
> + poll_and_wait();
> + }
> +
> close(control.fd);
>
> return (0);
> @@ -229,6 +248,10 @@ run_command(struct pdu *pdu)
> case CTRL_INPROGRESS:
> printf("command in progress...\n");
> break;
> + case CTRL_SESS_POLL:
> + done = 1;
> + register_poll(cmh, pdu);
> + break;
> case CTRL_INITIATOR_CONFIG:
> case CTRL_SESSION_CONFIG:
> show_config(cmh, pdu);
> @@ -383,3 +406,43 @@ show_vscsi_stats(struct ctrlmsghdr *cmh, struct pdu *pdu)
> vs->cnt_t2i_status[1],
> vs->cnt_t2i_status[2]);
> }
> +
> +void
> +poll_and_wait(void)
> +{
> + pr.result = (u_int8_t) 0;
> + printf("polling...");
> +
> + for (pr.attempts = 1; pr.attempts <= POLL_ATTEMPTS; ++pr.attempts) {
> + if (control_compose(NULL, CTRL_SESS_POLL, NULL, 0) == -1)
> + err(1, "control_compose");
> +
> + struct pdu *pdu;
> + while ((pdu = TAILQ_FIRST(&control.channel)) != NULL) {
> + run_command(pdu);
> + }
> +
> + /* Poll says we are good to go. */
> + if (pr.result != 0) {
> + printf("ok!\n");
> + return;
> + }
> +
> + /* Poll says we should wait... */
> + printf("%d, ", pr.attempts);
> + sleep(POLL_DELAY);
> + }
> +
> + printf("..,timer exceeded.\n");
> +}
> +
> +void
> +register_poll(struct ctrlmsghdr *cmh, struct pdu *pdu)
> +{
> + u_int8_t *r = &pr.result;
> +
> + if (cmh->len[0] != sizeof(u_int8_t))
> + errx(1, "poll: bad size of response");
> +
> + r = pdu_getbuf(pdu, NULL, 1);
> +}
> diff --git a/usr.sbin/iscsid/Makefile b/usr.sbin/iscsid/Makefile
> index 7a62024e68b..bac59d934f8 100644
> --- a/usr.sbin/iscsid/Makefile
> +++ b/usr.sbin/iscsid/Makefile
> @@ -2,7 +2,7 @@
>
> PROG= iscsid
> SRCS= connection.c control.c initiator.c iscsid.c log.c logmsg.c
> pdu.c \
> - session.c task.c util.c vscsi.c
> + poll.c session.c task.c util.c vscsi.c
>
> MAN= iscsid.8
>
> diff --git a/usr.sbin/iscsid/iscsid.c b/usr.sbin/iscsid/iscsid.c
> index d3526e96363..61f831c3b24 100644
> --- a/usr.sbin/iscsid/iscsid.c
> +++ b/usr.sbin/iscsid/iscsid.c
> @@ -211,6 +211,7 @@ iscsid_ctrl_dispatch(void *ch, struct pdu *pdu)
> struct initiator_config *ic;
> struct session_config *sc;
> struct session *s;
> + struct session_poll *p;
> int *valp;
>
> cmh = pdu_getbuf(pdu, NULL, 0);
> @@ -304,6 +305,20 @@ iscsid_ctrl_dispatch(void *ch, struct pdu *pdu)
>
> control_compose(ch, CTRL_SUCCESS, NULL, 0);
> break;
> + case CTRL_SESS_POLL:
> + p = poll_alloc();
> +
> + TAILQ_FOREACH(s, &initiator->sessions, entry) {
> + poll_session(p, s);
> + }
> +
> + poll_finalize(p);
> +
> + control_compose(ch, CTRL_SESS_POLL,
> + (void *) &(p->status), sizeof(u_int8_t));
No need to type-cast, no need for the () around &(p->status). I prefer to
use sizeof(p->status) since that will adapt properly.
> +
> + poll_dealloc(p);
I think you could just use a stack variable for p here instead of using
alloc and dealloc. The struct is small.
> + break;
> default:
> log_warnx("unknown control message type %d", cmh->type);
> control_compose(ch, CTRL_FAILURE, NULL, 0);
> diff --git a/usr.sbin/iscsid/iscsid.h b/usr.sbin/iscsid/iscsid.h
> index b43fb5dcd99..08d5f251a39 100644
> --- a/usr.sbin/iscsid/iscsid.h
> +++ b/usr.sbin/iscsid/iscsid.h
> @@ -67,7 +67,7 @@ struct ctrldata {
> #define CTRL_LOG_VERBOSE 6
> #define CTRL_VSCSI_STATS 7
> #define CTRL_SHOW_SUM 8
> -
> +#define CTRL_SESS_POLL 9
>
> TAILQ_HEAD(session_head, session);
> TAILQ_HEAD(connection_head, connection);
> @@ -251,6 +251,13 @@ struct session {
> int action;
> };
>
> +struct session_poll {
> + u_int16_t session_count; /* Total number of configured sessions*/
> + u_int16_t init_count; /* Number of sessions in init state */
> + u_int16_t running_count; /* Number of sessions in running state */
> + u_int8_t status; /* Status flag */
> +};
> +
I would just use int for all the variables here. Just keep it simple.
> struct connection {
> struct event ev;
> struct event wev;
> @@ -391,6 +398,12 @@ void vscsi_status(int, int, void *, size_t);
> void vscsi_event(unsigned long, u_int, u_int);
> struct vscsi_stats *vscsi_stats(void);
>
> +/* Session polling */
> +struct session_poll *poll_alloc(void);
> +void poll_dealloc(struct session_poll *);
> +void poll_session(struct session_poll *, struct session *);
> +void poll_finalize(struct session_poll *);
> +
> /* logmsg.c */
> void log_hexdump(void *, size_t);
> void log_pdu(struct pdu *, int);
> diff --git a/usr.sbin/iscsid/poll.c b/usr.sbin/iscsid/poll.c
> new file mode 100644
> index 00000000000..d3c79985d71
> --- /dev/null
> +++ b/usr.sbin/iscsid/poll.c
> @@ -0,0 +1,80 @@
> +/*
> + * Copyright (c) 2021 Dr Ashton Fagg <[email protected]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/types.h>
> +#include <sys/socket.h>
> +
> +#include <event.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +
> +#include "iscsid.h"
> +#include "log.h"
> +
> +struct session_poll
> +*poll_alloc(void)
> +{
> + struct session_poll *p;
> +
> + if (!(p = calloc(1, sizeof(*p))))
> + fatal("poll_alloc failed.");
> +
Calloc already sets all memory to 0. So the code below is not needed.
> + p->session_count = (u_int16_t) 0;
> + p->init_count = (u_int16_t) 0;
> + p->running_count = (u_int16_t) 0;
Also there is no need to typecast here. In general try to avoid typecasts
since they can hide hard to find bugs.
> +
> + return p;
> +}
> +
> +
> +void
> +poll_dealloc(struct session_poll *p)
> +{
> + free(p);
> +}
As mentioned above I would just use a stack variable
struct session_poll p = { 0 };
instead of dynamically allocate this.
> +void
> +poll_session(struct session_poll *p, struct session *s)
> +{
> + if (!s)
> + fatal("poll_session failed: invalid session");
> +
> + ++(p->session_count);
No need for the ()
> +
> + /* If SESS_RUNNING, this determines the session has either
> + been brought up successfully, or has failed. Either way,
> + we aren't waiting on it. */
> + if (s->state & SESS_RUNNING)
> + ++(p->running_count);
> + /* Otherwise, it is in SESS_INIT. These need to be waited on. */
> + else if (s->state & SESS_RUNNING)
> + ++(p->init_count);
The two if statements are the same. I guess you want SESS_INIT in the
second.
> + else
> + fatal("poll_session: unknown state.");
> +}
> +
> +void
> +poll_finalize(struct session_poll *p)
> +{
> + /* Perform final book keeping to determine status.
> + *
> + * status will be non-zero if the number of sessions that are
> + * in states other than SESS_INIT is equal to the total number
> + * of configured sessions. This indicates to the poller that
> + * we are not waiting for something to complete. */
Indents are strange here. Guess tab vs spaces.
> + p->status = (u_int8_t) (p->session_count == p->running_count);
> +}
I actually wonder if this code should just return the various counts to
iscsictl so it could display the status (if requested).
I think this is moving in the right direction.
--
:wq Claudio