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