Add iscsi_set_fd_dup_cb
libiscsi is widely used by poll driven, include libiscsi itself,
QEMU. Using poll works fine after iscsi reconnect, but it does not work
in epoll, because the epoll event has been removed during duplicating
file descriptor in kernel.
Add a new function iscsi_set_fd_dup_cb to set callback, then uplayer
gets notified after duplicating. The following codes reproduce this
issue, and test this patch by compiling flags -DISCSI_FD_DUP_CB.
static void iscsi_epoll_event(struct iscsi_context *iscsi, int epollfd, bool new)
{
static int epoll_event;
struct epoll_event ev = { 0 };
int pevent = iscsi_which_events(iscsi);
int event = 0;
if (pevent & POLLIN)
event |= EPOLLIN;
if (pevent & POLLOUT)
event |= EPOLLOUT;
ev.events = event;
ev.data.fd = iscsi_get_fd(iscsi);
if (new)
epoll_ctl(epollfd, EPOLL_CTL_ADD, ev.data.fd, &ev);
else if (epoll_event != event) {
epoll_ctl(epollfd, EPOLL_CTL_MOD, ev.data.fd, &ev);
}
epoll_event = event;
}
static void iscsi_tsk_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data)
{
printf("iscsi_tsk_cb status %d\n", status);
exit(0);
}
static void iscsi_fd_dup_cb(struct iscsi_context *iscsi, void *opaque)
{
int epollfd = *(int *)opaque;
iscsi_epoll_event(iscsi, epollfd, true);
}
static void iscsi_on_pollout(struct iscsi_context *iscsi, struct iscsi_url *iscsi_url, int epollfd)
{
static struct scsi_task *tsk = NULL;
iscsi_service(iscsi, POLLOUT);
if (!tsk) {
tsk = iscsi_readcapacity16_task(iscsi, iscsi_url->lun, iscsi_tsk_cb, NULL);
assert(tsk);
}
}
int main(int argc, char *argv[])
{
struct iscsi_context *iscsi;
struct iscsi_url *iscsi_url;
struct epoll_event ev, revent;
int epollfd;
iscsi = iscsi_create_context("dummy");
assert(iscsi);
iscsi_url = iscsi_parse_full_url(iscsi, argv[1]);
assert(iscsi_url);
iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL);
iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
assert(!iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun));
epollfd = epoll_create1(0);
iscsi_epoll_event(iscsi, epollfd, true);
iscsi_set_fd_dup_cb(iscsi, iscsi_fd_dup_cb, &epollfd);
iscsi_reconnect(iscsi);
while (epoll_wait(epollfd, &revent, 1, 100) >= 0) {
if (revent.events & EPOLLIN)
iscsi_service(iscsi, POLLIN);
if (revent.events & EPOLLOUT)
iscsi_on_pollout(iscsi, iscsi_url, epollfd);
iscsi_epoll_event(iscsi, epollfd, false);
}
return 0;
}
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>