2 * Copyright (c) 2005 Hannes Reinecke, Suse
12 #include <sys/ioctl.h>
19 #include "../libmultipath/debug.h"
21 #define MSG_DIRECTIO_UNKNOWN "directio checker is not available"
22 #define MSG_DIRECTIO_UP "directio checker reports path is up"
23 #define MSG_DIRECTIO_DOWN "directio checker reports path is down"
24 #define MSG_DIRECTIO_PENDING "directio checker is waiting on aio"
26 #define LOG(prio, fmt, args...) condlog(prio, "directio: " fmt, ##args)
28 struct directio_context {
39 int libcheck_init (struct checker * c)
41 unsigned long pgsize = getpagesize();
42 struct directio_context * ct;
45 ct = malloc(sizeof(struct directio_context));
48 memset(ct, 0, sizeof(struct directio_context));
50 if (io_setup(1, &ct->ioctx) != 0) {
51 condlog(1, "io_setup failed");
56 if (ioctl(c->fd, BLKBSZGET, &ct->blksize) < 0) {
57 MSG(c, "cannot get blocksize, set default");
60 if (ct->blksize > 4096) {
62 * Sanity check for DASD; BSZGET is broken
68 ct->buf = (unsigned char *)malloc(ct->blksize + pgsize);
72 flags = fcntl(c->fd, F_GETFL);
75 if (!(flags & O_DIRECT)) {
77 if (fcntl(c->fd, F_SETFL, flags) < 0)
82 ct->ptr = (unsigned char *) (((unsigned long)ct->buf + pgsize - 1) &
85 /* Successfully initialized, return the context. */
86 c->context = (void *) ct;
92 io_destroy(ct->ioctx);
97 void libcheck_free (struct checker * c)
99 struct directio_context * ct = (struct directio_context *)c->context;
105 if (ct->reset_flags) {
106 if ((flags = fcntl(c->fd, F_GETFL)) >= 0) {
107 int ret __attribute__ ((unused));
110 /* No point in checking for errors */
111 ret = fcntl(c->fd, F_SETFL, flags);
117 io_destroy(ct->ioctx);
121 void libcheck_repair (struct checker * c)
127 check_state(int fd, struct directio_context *ct, int sync, int timeout_secs)
129 struct timespec timeout = { .tv_nsec = 5 };
130 struct io_event event;
132 int rc = PATH_UNCHECKED;
135 if (fstat(fd, &sb) == 0) {
136 LOG(4, "called for %x", (unsigned) sb.st_rdev);
139 LOG(4, "called in synchronous mode");
140 timeout.tv_sec = timeout_secs;
145 struct iocb *ios[1] = { &ct->io };
147 LOG(3, "starting new request");
148 memset(&ct->io, 0, sizeof(struct iocb));
149 io_prep_pread(&ct->io, fd, ct->ptr, ct->blksize, 0);
150 if (io_submit(ct->ioctx, 1, ios) != 1) {
151 LOG(3, "io_submit error %i", errno);
152 return PATH_UNCHECKED;
158 r = io_getevents(ct->ioctx, 1L, 1L, &event, &timeout);
161 LOG(3, "async io getevents returned %li (errno=%s)", r,
166 if (ct->running > timeout_secs || sync) {
167 struct iocb *ios[1] = { &ct->io };
169 LOG(3, "abort check on timeout");
170 r = io_cancel(ct->ioctx, ios[0], &event);
172 * Only reset ct->running if we really
173 * could abort the pending I/O
176 LOG(3, "io_cancel error %i", errno);
181 LOG(3, "async io pending");
185 LOG(3, "io finished %lu/%lu", event.res, event.res2);
187 rc = (event.res == ct->blksize) ? PATH_UP : PATH_DOWN;
193 int libcheck_check (struct checker * c)
196 struct directio_context * ct = (struct directio_context *)c->context;
199 return PATH_UNCHECKED;
201 ret = check_state(c->fd, ct, c->sync, c->timeout);
206 MSG(c, MSG_DIRECTIO_UNKNOWN);
209 MSG(c, MSG_DIRECTIO_DOWN);
212 MSG(c, MSG_DIRECTIO_UP);
215 MSG(c, MSG_DIRECTIO_PENDING);