fixup! libmultipath: make directio checker share io contexts
[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                 if (list_empty(&aio_grp_list))
144                         add_aio_group();
145         }
146 }
147
148 int libcheck_load (void)
149 {
150         if (add_aio_group() == NULL) {
151                 LOG(1, "libcheck_load failed: %s", strerror(errno));
152                 return 1;
153         }
154         return 0;
155 }
156
157 void libcheck_unload (void)
158 {
159         struct aio_group *aio_grp, *tmp;
160
161         list_for_each_entry_safe(aio_grp, tmp, &aio_grp_list, node)
162                 remove_aio_group(aio_grp);
163 }
164
165 int libcheck_reset (void)
166 {
167         struct aio_group *aio_grp, *tmp, *reset_grp = NULL;
168
169         /* If a clean existing aio_group exists, use that. Otherwise add a
170          * new one */
171         list_for_each_entry(aio_grp, &aio_grp_list, node) {
172                 if (aio_grp->holders == 0 &&
173                     list_empty(&aio_grp->orphans)) {
174                         reset_grp = aio_grp;
175                         break;
176                 }
177         }
178         if (!reset_grp)
179                 reset_grp = add_aio_group();
180         if (!reset_grp) {
181                 LOG(1, "checker reset failed");
182                 return 1;
183         }
184
185         list_for_each_entry_safe(aio_grp, tmp, &aio_grp_list, node) {
186                 if (aio_grp != reset_grp)
187                         remove_aio_group(aio_grp);
188         }
189         return 0;
190 }
191
192 int libcheck_init (struct checker * c)
193 {
194         unsigned long pgsize = getpagesize();
195         struct directio_context * ct;
196         struct async_req *req = NULL;
197         long flags;
198
199         ct = malloc(sizeof(struct directio_context));
200         if (!ct)
201                 return 1;
202         memset(ct, 0, sizeof(struct directio_context));
203
204         if (set_aio_group(ct) < 0)
205                 goto out;
206
207         req = malloc(sizeof(struct async_req));
208         if (!req) {
209                 goto out;
210         }
211         memset(req, 0, sizeof(struct async_req));
212         INIT_LIST_HEAD(&req->node);
213
214         if (ioctl(c->fd, BLKBSZGET, &req->blksize) < 0) {
215                 c->msgid = MSG_DIRECTIO_BLOCKSIZE;
216                 req->blksize = 512;
217         }
218         if (req->blksize > 4096) {
219                 /*
220                  * Sanity check for DASD; BSZGET is broken
221                  */
222                 req->blksize = 4096;
223         }
224         if (!req->blksize)
225                 goto out;
226
227         req->buf = (unsigned char *)malloc(req->blksize + pgsize);
228         if (!req->buf)
229                 goto out;
230
231         flags = fcntl(c->fd, F_GETFL);
232         if (flags < 0)
233                 goto out;
234         if (!(flags & O_DIRECT)) {
235                 flags |= O_DIRECT;
236                 if (fcntl(c->fd, F_SETFL, flags) < 0)
237                         goto out;
238                 ct->reset_flags = 1;
239         }
240
241         req->ptr = (unsigned char *) (((unsigned long)req->buf + pgsize - 1) &
242                   (~(pgsize - 1)));
243
244         /* Successfully initialized, return the context. */
245         ct->req = req;
246         c->context = (void *) ct;
247         return 0;
248
249 out:
250         if (req) {
251                 if (req->buf)
252                         free(req->buf);
253                 free(req);
254         }
255         if (ct->aio_grp)
256                 ct->aio_grp->holders--;
257         free(ct);
258         return 1;
259 }
260
261 void libcheck_free (struct checker * c)
262 {
263         struct directio_context * ct = (struct directio_context *)c->context;
264         struct io_event event;
265         long flags;
266
267         if (!ct)
268                 return;
269
270         if (ct->reset_flags) {
271                 if ((flags = fcntl(c->fd, F_GETFL)) >= 0) {
272                         int ret __attribute__ ((unused));
273
274                         flags &= ~O_DIRECT;
275                         /* No point in checking for errors */
276                         ret = fcntl(c->fd, F_SETFL, flags);
277                 }
278         }
279
280         if (ct->running &&
281             (ct->req->state != PATH_PENDING ||
282              io_cancel(ct->aio_grp->ioctx, &ct->req->io, &event) == 0))
283                 ct->running = 0;
284         if (!ct->running) {
285                 free(ct->req->buf);
286                 free(ct->req);
287                 ct->aio_grp->holders--;
288         } else {
289                 ct->req->state = PATH_REMOVED;
290                 list_add(&ct->req->node, &ct->aio_grp->orphans);
291                 check_orphaned_group(ct->aio_grp);
292         }
293
294         free(ct);
295         c->context = NULL;
296 }
297
298 static int
299 get_events(struct aio_group *aio_grp, struct timespec *timeout)
300 {
301         struct io_event events[128];
302         int i, nr, got_events = 0;
303         struct timespec zero_timeout = {0};
304         struct timespec *timep = (timeout)? timeout : &zero_timeout;
305
306         do {
307                 errno = 0;
308                 nr = io_getevents(aio_grp->ioctx, 1, 128, events, timep);
309                 got_events |= (nr > 0);
310
311                 for (i = 0; i < nr; i++) {
312                         struct async_req *req = container_of(events[i].obj, struct async_req, io);
313
314                         LOG(3, "io finished %lu/%lu", events[i].res,
315                             events[i].res2);
316
317                         /* got an orphaned request */
318                         if (req->state == PATH_REMOVED) {
319                                 list_del(&req->node);
320                                 free(req->buf);
321                                 free(req);
322                                 aio_grp->holders--;
323                         } else
324                                 req->state = (events[i].res == req->blksize) ?
325                                               PATH_UP : PATH_DOWN;
326                 }
327                 timep = &zero_timeout;
328         } while (nr == 128); /* assume there are more events and try again */
329
330         if (nr < 0)
331                 LOG(3, "async io getevents returned %i (errno=%s)",
332                     nr, strerror(errno));
333
334         return got_events;
335 }
336
337 static int
338 check_state(int fd, struct directio_context *ct, int sync, int timeout_secs)
339 {
340         struct timespec timeout = { .tv_nsec = 5 };
341         struct stat     sb;
342         int             rc;
343         long            r;
344         struct timespec currtime, endtime;
345         struct timespec *timep = &timeout;
346
347         if (fstat(fd, &sb) == 0) {
348                 LOG(4, "called for %x", (unsigned) sb.st_rdev);
349         }
350         if (sync > 0) {
351                 LOG(4, "called in synchronous mode");
352                 timeout.tv_sec  = timeout_secs;
353                 timeout.tv_nsec = 0;
354         }
355
356         if (ct->running) {
357                 if (ct->req->state != PATH_PENDING) {
358                         ct->running = 0;
359                         return ct->req->state;
360                 }
361         } else {
362                 struct iocb *ios[1] = { &ct->req->io };
363
364                 LOG(3, "starting new request");
365                 memset(&ct->req->io, 0, sizeof(struct iocb));
366                 io_prep_pread(&ct->req->io, fd, ct->req->ptr,
367                               ct->req->blksize, 0);
368                 ct->req->state = PATH_PENDING;
369                 if (io_submit(ct->aio_grp->ioctx, 1, ios) != 1) {
370                         LOG(3, "io_submit error %i", errno);
371                         return PATH_UNCHECKED;
372                 }
373         }
374         ct->running++;
375
376         get_monotonic_time(&endtime);
377         endtime.tv_sec += timeout.tv_sec;
378         endtime.tv_nsec += timeout.tv_nsec;
379         normalize_timespec(&endtime);
380         while(1) {
381                 r = get_events(ct->aio_grp, timep);
382
383                 if (ct->req->state != PATH_PENDING) {
384                         ct->running = 0;
385                         return ct->req->state;
386                 } else if (r == 0 || !timep)
387                         break;
388
389                 get_monotonic_time(&currtime);
390                 timespecsub(&endtime, &currtime, &timeout);
391                 if (timeout.tv_sec < 0)
392                         timep = NULL;
393         }
394         if (ct->running > timeout_secs || sync) {
395                 struct io_event event;
396
397                 LOG(3, "abort check on timeout");
398
399                 r = io_cancel(ct->aio_grp->ioctx, &ct->req->io, &event);
400                 /*
401                  * Only reset ct->running if we really
402                  * could abort the pending I/O
403                  */
404                 if (!r)
405                         ct->running = 0;
406                 rc = PATH_DOWN;
407         } else {
408                 LOG(3, "async io pending");
409                 rc = PATH_PENDING;
410         }
411
412         return rc;
413 }
414
415 int libcheck_check (struct checker * c)
416 {
417         int ret;
418         struct directio_context * ct = (struct directio_context *)c->context;
419
420         if (!ct)
421                 return PATH_UNCHECKED;
422
423         ret = check_state(c->fd, ct, checker_is_sync(c), c->timeout);
424
425         switch (ret)
426         {
427         case PATH_UNCHECKED:
428                 c->msgid = MSG_DIRECTIO_UNKNOWN;
429                 break;
430         case PATH_DOWN:
431                 c->msgid = CHECKER_MSGID_DOWN;
432                 break;
433         case PATH_UP:
434                 c->msgid = CHECKER_MSGID_UP;
435                 break;
436         case PATH_PENDING:
437                 c->msgid = MSG_DIRECTIO_PENDING;
438                 break;
439         default:
440                 break;
441         }
442         return ret;
443 }