Fix error
[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 "debug.h"
19 #include "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         int rc;
74
75         aio_grp = malloc(sizeof(struct aio_group));
76         if (!aio_grp)
77                 return NULL;
78         memset(aio_grp, 0, sizeof(struct aio_group));
79         INIT_LIST_HEAD(&aio_grp->orphans);
80
81         if ((rc = io_setup(AIO_GROUP_SIZE, &aio_grp->ioctx)) != 0) {
82                 LOG(1, "io_setup failed");
83                 if (rc == -EAGAIN)
84                         LOG(1, "global number of io events too small. Increase fs.aio-max-nr with sysctl");
85                 free(aio_grp);
86                 return NULL;
87         }
88         list_add(&aio_grp->node, &aio_grp_list);
89         return aio_grp;
90 }
91
92 static int
93 set_aio_group(struct directio_context *ct)
94 {
95         struct aio_group *aio_grp = NULL;
96
97         list_for_each_entry(aio_grp, &aio_grp_list, node)
98                 if (aio_grp->holders < AIO_GROUP_SIZE)
99                         goto found;
100         aio_grp = add_aio_group();
101         if (!aio_grp) {
102                 ct->aio_grp = NULL;
103                 return -1;
104         }
105 found:
106         aio_grp->holders++;
107         ct->aio_grp = aio_grp;
108         return 0;
109 }
110
111 static void
112 remove_aio_group(struct aio_group *aio_grp)
113 {
114         struct async_req *req, *tmp;
115
116         io_destroy(aio_grp->ioctx);
117         list_for_each_entry_safe(req, tmp, &aio_grp->orphans, node) {
118                 list_del(&req->node);
119                 free(req->buf);
120                 free(req);
121         }
122         list_del(&aio_grp->node);
123         free(aio_grp);
124 }
125
126 /* If an aio_group is completely full of orphans, then no checkers can
127  * use it, which means that no checkers can clear out the orphans. To
128  * avoid keeping the useless group around, simply remove the
129  * group */
130 static void
131 check_orphaned_group(struct aio_group *aio_grp)
132 {
133         int count = 0;
134         struct list_head *item;
135
136         if (aio_grp->holders < AIO_GROUP_SIZE)
137                 return;
138         list_for_each(item, &aio_grp->orphans)
139                 count++;
140         if (count >= AIO_GROUP_SIZE)
141                 remove_aio_group(aio_grp);
142 }
143
144 void libcheck_reset (void)
145 {
146         struct aio_group *aio_grp, *tmp;
147
148         list_for_each_entry_safe(aio_grp, tmp, &aio_grp_list, node)
149                 remove_aio_group(aio_grp);
150 }
151
152 int libcheck_init (struct checker * c)
153 {
154         unsigned long pgsize = getpagesize();
155         struct directio_context * ct;
156         struct async_req *req = NULL;
157         long flags;
158
159         ct = malloc(sizeof(struct directio_context));
160         if (!ct)
161                 return 1;
162         memset(ct, 0, sizeof(struct directio_context));
163
164         if (set_aio_group(ct) < 0)
165                 goto out;
166
167         req = malloc(sizeof(struct async_req));
168         if (!req) {
169                 goto out;
170         }
171         memset(req, 0, sizeof(struct async_req));
172         INIT_LIST_HEAD(&req->node);
173
174         if (ioctl(c->fd, BLKBSZGET, &req->blksize) < 0) {
175                 c->msgid = MSG_DIRECTIO_BLOCKSIZE;
176                 req->blksize = 4096;
177         }
178         if (req->blksize > 4096) {
179                 /*
180                  * Sanity check for DASD; BSZGET is broken
181                  */
182                 req->blksize = 4096;
183         }
184         if (!req->blksize)
185                 goto out;
186
187         if (posix_memalign((void **)&req->buf, pgsize, req->blksize) != 0)
188                 goto out;
189
190         flags = fcntl(c->fd, F_GETFL);
191         if (flags < 0)
192                 goto out;
193         if (!(flags & O_DIRECT)) {
194                 flags |= O_DIRECT;
195                 if (fcntl(c->fd, F_SETFL, flags) < 0)
196                         goto out;
197                 ct->reset_flags = 1;
198         }
199
200         /* Successfully initialized, return the context. */
201         ct->req = req;
202         c->context = (void *) ct;
203         return 0;
204
205 out:
206         if (req) {
207                 if (req->buf)
208                         free(req->buf);
209                 free(req);
210         }
211         if (ct->aio_grp)
212                 ct->aio_grp->holders--;
213         free(ct);
214         return 1;
215 }
216
217 void libcheck_free (struct checker * c)
218 {
219         struct directio_context * ct = (struct directio_context *)c->context;
220         struct io_event event;
221         long flags;
222
223         if (!ct)
224                 return;
225
226         if (ct->reset_flags) {
227                 if ((flags = fcntl(c->fd, F_GETFL)) >= 0) {
228                         int ret __attribute__ ((unused));
229
230                         flags &= ~O_DIRECT;
231                         /* No point in checking for errors */
232                         ret = fcntl(c->fd, F_SETFL, flags);
233                 }
234         }
235
236         if (ct->running && ct->req->state != PATH_PENDING)
237                 ct->running = 0;
238         if (!ct->running) {
239                 free(ct->req->buf);
240                 free(ct->req);
241                 ct->aio_grp->holders--;
242         } else {
243                 /* Currently a no-op */
244                 io_cancel(ct->aio_grp->ioctx, &ct->req->io, &event);
245                 ct->req->state = PATH_REMOVED;
246                 list_add(&ct->req->node, &ct->aio_grp->orphans);
247                 check_orphaned_group(ct->aio_grp);
248         }
249
250         free(ct);
251         c->context = NULL;
252 }
253
254 static int
255 get_events(struct aio_group *aio_grp, struct timespec *timeout)
256 {
257         struct io_event events[128];
258         int i, nr, got_events = 0;
259         struct timespec zero_timeout = { .tv_sec = 0, };
260         struct timespec *timep = timeout;
261
262         do {
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(4, "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(4, "async io getevents returned %s", strerror(-nr));
287
288         return got_events;
289 }
290
291 static int
292 check_state(int fd, struct directio_context *ct, int sync, int timeout_secs)
293 {
294         struct timespec timeout = { .tv_nsec = 1000 };
295         struct stat     sb;
296         int             rc;
297         long            r;
298         struct timespec currtime, endtime;
299
300         if (fstat(fd, &sb) == 0) {
301                 LOG(4, "called for %x", (unsigned) sb.st_rdev);
302         }
303         if (sync > 0) {
304                 LOG(4, "called in synchronous mode");
305                 timeout.tv_sec  = timeout_secs;
306                 timeout.tv_nsec = 0;
307         }
308
309         if (ct->running) {
310                 if (ct->req->state != PATH_PENDING) {
311                         ct->running = 0;
312                         return ct->req->state;
313                 }
314         } else {
315                 struct iocb *ios[1] = { &ct->req->io };
316
317                 LOG(4, "starting new request");
318                 memset(&ct->req->io, 0, sizeof(struct iocb));
319                 io_prep_pread(&ct->req->io, fd, ct->req->buf,
320                               ct->req->blksize, 0);
321                 ct->req->state = PATH_PENDING;
322                 if ((rc = io_submit(ct->aio_grp->ioctx, 1, ios)) != 1) {
323                         LOG(3, "io_submit error %i", -rc);
324                         return PATH_UNCHECKED;
325                 }
326         }
327         ct->running++;
328
329         get_monotonic_time(&endtime);
330         endtime.tv_sec += timeout.tv_sec;
331         endtime.tv_nsec += timeout.tv_nsec;
332         normalize_timespec(&endtime);
333         while(1) {
334                 r = get_events(ct->aio_grp, &timeout);
335
336                 if (ct->req->state != PATH_PENDING) {
337                         ct->running = 0;
338                         return ct->req->state;
339                 } else if (r == 0 ||
340                            (timeout.tv_sec == 0 && timeout.tv_nsec == 0))
341                         break;
342
343                 get_monotonic_time(&currtime);
344                 timespecsub(&endtime, &currtime, &timeout);
345                 if (timeout.tv_sec < 0)
346                         timeout.tv_sec = timeout.tv_nsec = 0;
347         }
348         if (ct->running > timeout_secs || sync) {
349                 struct io_event event;
350
351                 LOG(3, "abort check on timeout");
352
353                 io_cancel(ct->aio_grp->ioctx, &ct->req->io, &event);
354                 rc = PATH_DOWN;
355         } else {
356                 LOG(4, "async io pending");
357                 rc = PATH_PENDING;
358         }
359
360         return rc;
361 }
362
363 int libcheck_check (struct checker * c)
364 {
365         int ret;
366         struct directio_context * ct = (struct directio_context *)c->context;
367
368         if (!ct)
369                 return PATH_UNCHECKED;
370
371         ret = check_state(c->fd, ct, checker_is_sync(c), c->timeout);
372
373         switch (ret)
374         {
375         case PATH_UNCHECKED:
376                 c->msgid = MSG_DIRECTIO_UNKNOWN;
377                 break;
378         case PATH_DOWN:
379                 c->msgid = CHECKER_MSGID_DOWN;
380                 break;
381         case PATH_UP:
382                 c->msgid = CHECKER_MSGID_UP;
383                 break;
384         case PATH_PENDING:
385                 c->msgid = MSG_DIRECTIO_PENDING;
386                 break;
387         default:
388                 break;
389         }
390         return ret;
391 }