libmultipath: change directio get_events() timeout handling
[multipath-tools/.git] / libmultipath / checkers / directio.c
1 /*
2  * Copyright (c) 2005 Hannes Reinecke, Suse
3  */
4 #define _GNU_SOURCE
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <unistd.h>
11 #include <fcntl.h>
12 #include <sys/ioctl.h>
13 #include <linux/fs.h>
14 #include <errno.h>
15 #include <unistd.h>
16 #include <libaio.h>
17
18 #include "checkers.h"
19 #include "../libmultipath/debug.h"
20 #include "../libmultipath/time-util.h"
21
22 #define AIO_GROUP_SIZE 1024
23
24 /* Note: This checker type relies on the fact that only one checker can be run
25  * at a time, since multiple checkers share the same aio_group, and must be
26  * able to modify other checker's async_reqs. If multple checkers become able
27  * to be run at the same time, this checker will need to add locking, and
28  * probably polling on event fds, to deal with that */
29
30 struct aio_group {
31         struct list_head node;
32         int holders;
33         io_context_t ioctx;
34         struct list_head orphans;
35 };
36
37 struct async_req {
38         struct iocb io;
39         unsigned int blksize;
40         unsigned char * buf;
41         unsigned char * ptr;
42         struct list_head node;
43         int state; /* PATH_REMOVED means this is an orphan */
44 };
45
46 static LIST_HEAD(aio_grp_list);
47
48 enum {
49         MSG_DIRECTIO_UNKNOWN = CHECKER_FIRST_MSGID,
50         MSG_DIRECTIO_PENDING,
51         MSG_DIRECTIO_BLOCKSIZE,
52 };
53
54 #define _IDX(x) (MSG_DIRECTIO_##x - CHECKER_FIRST_MSGID)
55 const char *libcheck_msgtable[] = {
56         [_IDX(UNKNOWN)] = " is not available",
57         [_IDX(PENDING)] = " is waiting on aio",
58         [_IDX(BLOCKSIZE)] = " cannot get blocksize, set default",
59         NULL,
60 };
61
62 #define LOG(prio, fmt, args...) condlog(prio, "directio: " fmt, ##args)
63
64 struct directio_context {
65         int             running;
66         int             reset_flags;
67         struct aio_group *aio_grp;
68         struct async_req *req;
69 };
70
71 static struct aio_group *
72 add_aio_group(void)
73 {
74         struct aio_group *aio_grp;
75
76         aio_grp = malloc(sizeof(struct aio_group));
77         if (!aio_grp)
78                 return NULL;
79         memset(aio_grp, 0, sizeof(struct aio_group));
80         INIT_LIST_HEAD(&aio_grp->orphans);
81
82         if (io_setup(AIO_GROUP_SIZE, &aio_grp->ioctx) != 0) {
83                 LOG(1, "io_setup failed");
84                 if (errno == EAGAIN)
85                         LOG(1, "global number of io events too small. Increase fs.aio-max-nr with sysctl");
86                 free(aio_grp);
87                 return NULL;
88         }
89         list_add(&aio_grp->node, &aio_grp_list);
90         return aio_grp;
91 }
92
93 static int
94 set_aio_group(struct directio_context *ct)
95 {
96         struct aio_group *aio_grp = NULL;
97
98         list_for_each_entry(aio_grp, &aio_grp_list, node)
99                 if (aio_grp->holders < AIO_GROUP_SIZE)
100                         goto found;
101         aio_grp = add_aio_group();
102         if (!aio_grp) {
103                 ct->aio_grp = NULL;
104                 return -1;
105         }
106 found:
107         aio_grp->holders++;
108         ct->aio_grp = aio_grp;
109         return 0;
110 }
111
112 static void
113 remove_aio_group(struct aio_group *aio_grp)
114 {
115         struct async_req *req, *tmp;
116
117         io_destroy(aio_grp->ioctx);
118         list_for_each_entry_safe(req, tmp, &aio_grp->orphans, node) {
119                 list_del(&req->node);
120                 free(req->buf);
121                 free(req);
122         }
123         list_del(&aio_grp->node);
124         free(aio_grp);
125 }
126
127 /* If an aio_group is completely full of orphans, then no checkers can
128  * use it, which means that no checkers can clear out the orphans. To
129  * avoid keeping the useless group around, simply remove remove the
130  * group */
131 static void
132 check_orphaned_group(struct aio_group *aio_grp)
133 {
134         int count = 0;
135         struct list_head *item;
136
137         if (aio_grp->holders < AIO_GROUP_SIZE)
138                 return;
139         list_for_each(item, &aio_grp->orphans)
140                 count++;
141         if (count >= AIO_GROUP_SIZE)
142                 remove_aio_group(aio_grp);
143 }
144
145 void libcheck_reset (void)
146 {
147         struct aio_group *aio_grp, *tmp;
148
149         list_for_each_entry_safe(aio_grp, tmp, &aio_grp_list, node)
150                 remove_aio_group(aio_grp);
151 }
152
153 int libcheck_init (struct checker * c)
154 {
155         unsigned long pgsize = getpagesize();
156         struct directio_context * ct;
157         struct async_req *req = NULL;
158         long flags;
159
160         ct = malloc(sizeof(struct directio_context));
161         if (!ct)
162                 return 1;
163         memset(ct, 0, sizeof(struct directio_context));
164
165         if (set_aio_group(ct) < 0)
166                 goto out;
167
168         req = malloc(sizeof(struct async_req));
169         if (!req) {
170                 goto out;
171         }
172         memset(req, 0, sizeof(struct async_req));
173         INIT_LIST_HEAD(&req->node);
174
175         if (ioctl(c->fd, BLKBSZGET, &req->blksize) < 0) {
176                 c->msgid = MSG_DIRECTIO_BLOCKSIZE;
177                 req->blksize = 512;
178         }
179         if (req->blksize > 4096) {
180                 /*
181                  * Sanity check for DASD; BSZGET is broken
182                  */
183                 req->blksize = 4096;
184         }
185         if (!req->blksize)
186                 goto out;
187
188         req->buf = (unsigned char *)malloc(req->blksize + pgsize);
189         if (!req->buf)
190                 goto out;
191
192         flags = fcntl(c->fd, F_GETFL);
193         if (flags < 0)
194                 goto out;
195         if (!(flags & O_DIRECT)) {
196                 flags |= O_DIRECT;
197                 if (fcntl(c->fd, F_SETFL, flags) < 0)
198                         goto out;
199                 ct->reset_flags = 1;
200         }
201
202         req->ptr = (unsigned char *) (((unsigned long)req->buf + pgsize - 1) &
203                   (~(pgsize - 1)));
204
205         /* Successfully initialized, return the context. */
206         ct->req = req;
207         c->context = (void *) ct;
208         return 0;
209
210 out:
211         if (req) {
212                 if (req->buf)
213                         free(req->buf);
214                 free(req);
215         }
216         if (ct->aio_grp)
217                 ct->aio_grp->holders--;
218         free(ct);
219         return 1;
220 }
221
222 void libcheck_free (struct checker * c)
223 {
224         struct directio_context * ct = (struct directio_context *)c->context;
225         struct io_event event;
226         long flags;
227
228         if (!ct)
229                 return;
230
231         if (ct->reset_flags) {
232                 if ((flags = fcntl(c->fd, F_GETFL)) >= 0) {
233                         int ret __attribute__ ((unused));
234
235                         flags &= ~O_DIRECT;
236                         /* No point in checking for errors */
237                         ret = fcntl(c->fd, F_SETFL, flags);
238                 }
239         }
240
241         if (ct->running &&
242             (ct->req->state != PATH_PENDING ||
243              io_cancel(ct->aio_grp->ioctx, &ct->req->io, &event) == 0))
244                 ct->running = 0;
245         if (!ct->running) {
246                 free(ct->req->buf);
247                 free(ct->req);
248                 ct->aio_grp->holders--;
249         } else {
250                 ct->req->state = PATH_REMOVED;
251                 list_add(&ct->req->node, &ct->aio_grp->orphans);
252                 check_orphaned_group(ct->aio_grp);
253         }
254
255         free(ct);
256         c->context = NULL;
257 }
258
259 static int
260 get_events(struct aio_group *aio_grp, struct timespec *timeout)
261 {
262         struct io_event events[128];
263         int i, nr, got_events = 0;
264         struct timespec zero_timeout = {0};
265         struct timespec *timep = timeout;
266
267         do {
268                 errno = 0;
269                 nr = io_getevents(aio_grp->ioctx, 1, 128, events, timep);
270                 got_events |= (nr > 0);
271
272                 for (i = 0; i < nr; i++) {
273                         struct async_req *req = container_of(events[i].obj, struct async_req, io);
274
275                         LOG(3, "io finished %lu/%lu", events[i].res,
276                             events[i].res2);
277
278                         /* got an orphaned request */
279                         if (req->state == PATH_REMOVED) {
280                                 list_del(&req->node);
281                                 free(req->buf);
282                                 free(req);
283                                 aio_grp->holders--;
284                         } else
285                                 req->state = (events[i].res == req->blksize) ?
286                                               PATH_UP : PATH_DOWN;
287                 }
288                 timep = &zero_timeout;
289         } while (nr == 128); /* assume there are more events and try again */
290
291         if (nr < 0)
292                 LOG(3, "async io getevents returned %i (errno=%s)",
293                     nr, strerror(errno));
294
295         return got_events;
296 }
297
298 static int
299 check_state(int fd, struct directio_context *ct, int sync, int timeout_secs)
300 {
301         struct timespec timeout = { .tv_nsec = 5 };
302         struct stat     sb;
303         int             rc;
304         long            r;
305         struct timespec currtime, endtime;
306
307         if (fstat(fd, &sb) == 0) {
308                 LOG(4, "called for %x", (unsigned) sb.st_rdev);
309         }
310         if (sync > 0) {
311                 LOG(4, "called in synchronous mode");
312                 timeout.tv_sec  = timeout_secs;
313                 timeout.tv_nsec = 0;
314         }
315
316         if (ct->running) {
317                 if (ct->req->state != PATH_PENDING) {
318                         ct->running = 0;
319                         return ct->req->state;
320                 }
321         } else {
322                 struct iocb *ios[1] = { &ct->req->io };
323
324                 LOG(3, "starting new request");
325                 memset(&ct->req->io, 0, sizeof(struct iocb));
326                 io_prep_pread(&ct->req->io, fd, ct->req->ptr,
327                               ct->req->blksize, 0);
328                 ct->req->state = PATH_PENDING;
329                 if (io_submit(ct->aio_grp->ioctx, 1, ios) != 1) {
330                         LOG(3, "io_submit error %i", errno);
331                         return PATH_UNCHECKED;
332                 }
333         }
334         ct->running++;
335
336         get_monotonic_time(&endtime);
337         endtime.tv_sec += timeout.tv_sec;
338         endtime.tv_nsec += timeout.tv_nsec;
339         normalize_timespec(&endtime);
340         while(1) {
341                 r = get_events(ct->aio_grp, &timeout);
342
343                 if (ct->req->state != PATH_PENDING) {
344                         ct->running = 0;
345                         return ct->req->state;
346                 } else if (r == 0 ||
347                            (timeout.tv_sec == 0 && timeout.tv_nsec == 0))
348                         break;
349
350                 get_monotonic_time(&currtime);
351                 timespecsub(&endtime, &currtime, &timeout);
352                 if (timeout.tv_sec < 0)
353                         timeout.tv_sec = timeout.tv_nsec = 0;
354         }
355         if (ct->running > timeout_secs || sync) {
356                 struct io_event event;
357
358                 LOG(3, "abort check on timeout");
359
360                 r = io_cancel(ct->aio_grp->ioctx, &ct->req->io, &event);
361                 /*
362                  * Only reset ct->running if we really
363                  * could abort the pending I/O
364                  */
365                 if (!r)
366                         ct->running = 0;
367                 rc = PATH_DOWN;
368         } else {
369                 LOG(3, "async io pending");
370                 rc = PATH_PENDING;
371         }
372
373         return rc;
374 }
375
376 int libcheck_check (struct checker * c)
377 {
378         int ret;
379         struct directio_context * ct = (struct directio_context *)c->context;
380
381         if (!ct)
382                 return PATH_UNCHECKED;
383
384         ret = check_state(c->fd, ct, checker_is_sync(c), c->timeout);
385
386         switch (ret)
387         {
388         case PATH_UNCHECKED:
389                 c->msgid = MSG_DIRECTIO_UNKNOWN;
390                 break;
391         case PATH_DOWN:
392                 c->msgid = CHECKER_MSGID_DOWN;
393                 break;
394         case PATH_UP:
395                 c->msgid = CHECKER_MSGID_UP;
396                 break;
397         case PATH_PENDING:
398                 c->msgid = MSG_DIRECTIO_PENDING;
399                 break;
400         default:
401                 break;
402         }
403         return ret;
404 }