f73cbe38ec427dfc535c463f1b2f756edce92745
[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 <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         struct list_head node;
42         int state; /* PATH_REMOVED means this is an orphan */
43 };
44
45 static LIST_HEAD(aio_grp_list);
46
47 enum {
48         MSG_DIRECTIO_UNKNOWN = CHECKER_FIRST_MSGID,
49         MSG_DIRECTIO_PENDING,
50         MSG_DIRECTIO_BLOCKSIZE,
51 };
52
53 #define _IDX(x) (MSG_DIRECTIO_##x - CHECKER_FIRST_MSGID)
54 const char *libcheck_msgtable[] = {
55         [_IDX(UNKNOWN)] = " is not available",
56         [_IDX(PENDING)] = " is waiting on aio",
57         [_IDX(BLOCKSIZE)] = " cannot get blocksize, set default",
58         NULL,
59 };
60
61 #define LOG(prio, fmt, args...) condlog(prio, "directio: " fmt, ##args)
62
63 struct directio_context {
64         int             running;
65         int             reset_flags;
66         struct aio_group *aio_grp;
67         struct async_req *req;
68 };
69
70 static struct aio_group *
71 add_aio_group(void)
72 {
73         struct aio_group *aio_grp;
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 (io_setup(AIO_GROUP_SIZE, &aio_grp->ioctx) != 0) {
82                 LOG(1, "io_setup failed");
83                 if (errno == 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 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 &&
237             (ct->req->state != PATH_PENDING ||
238              io_cancel(ct->aio_grp->ioctx, &ct->req->io, &event) == 0))
239                 ct->running = 0;
240         if (!ct->running) {
241                 free(ct->req->buf);
242                 free(ct->req);
243                 ct->aio_grp->holders--;
244         } else {
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                 errno = 0;
264                 nr = io_getevents(aio_grp->ioctx, 1, 128, events, timep);
265                 got_events |= (nr > 0);
266
267                 for (i = 0; i < nr; i++) {
268                         struct async_req *req = container_of(events[i].obj, struct async_req, io);
269
270                         LOG(3, "io finished %lu/%lu", events[i].res,
271                             events[i].res2);
272
273                         /* got an orphaned request */
274                         if (req->state == PATH_REMOVED) {
275                                 list_del(&req->node);
276                                 free(req->buf);
277                                 free(req);
278                                 aio_grp->holders--;
279                         } else
280                                 req->state = (events[i].res == req->blksize) ?
281                                               PATH_UP : PATH_DOWN;
282                 }
283                 timep = &zero_timeout;
284         } while (nr == 128); /* assume there are more events and try again */
285
286         if (nr < 0)
287                 LOG(3, "async io getevents returned %i (errno=%s)",
288                     nr, strerror(errno));
289
290         return got_events;
291 }
292
293 static int
294 check_state(int fd, struct directio_context *ct, int sync, int timeout_secs)
295 {
296         struct timespec timeout = { .tv_nsec = 1000 };
297         struct stat     sb;
298         int             rc;
299         long            r;
300         struct timespec currtime, endtime;
301
302         if (fstat(fd, &sb) == 0) {
303                 LOG(4, "called for %x", (unsigned) sb.st_rdev);
304         }
305         if (sync > 0) {
306                 LOG(4, "called in synchronous mode");
307                 timeout.tv_sec  = timeout_secs;
308                 timeout.tv_nsec = 0;
309         }
310
311         if (ct->running) {
312                 if (ct->req->state != PATH_PENDING) {
313                         ct->running = 0;
314                         return ct->req->state;
315                 }
316         } else {
317                 struct iocb *ios[1] = { &ct->req->io };
318
319                 LOG(3, "starting new request");
320                 memset(&ct->req->io, 0, sizeof(struct iocb));
321                 io_prep_pread(&ct->req->io, fd, ct->req->buf,
322                               ct->req->blksize, 0);
323                 ct->req->state = PATH_PENDING;
324                 if (io_submit(ct->aio_grp->ioctx, 1, ios) != 1) {
325                         LOG(3, "io_submit error %i", errno);
326                         return PATH_UNCHECKED;
327                 }
328         }
329         ct->running++;
330
331         get_monotonic_time(&endtime);
332         endtime.tv_sec += timeout.tv_sec;
333         endtime.tv_nsec += timeout.tv_nsec;
334         normalize_timespec(&endtime);
335         while(1) {
336                 r = get_events(ct->aio_grp, &timeout);
337
338                 if (ct->req->state != PATH_PENDING) {
339                         ct->running = 0;
340                         return ct->req->state;
341                 } else if (r == 0 ||
342                            (timeout.tv_sec == 0 && timeout.tv_nsec == 0))
343                         break;
344
345                 get_monotonic_time(&currtime);
346                 timespecsub(&endtime, &currtime, &timeout);
347                 if (timeout.tv_sec < 0)
348                         timeout.tv_sec = timeout.tv_nsec = 0;
349         }
350         if (ct->running > timeout_secs || sync) {
351                 struct io_event event;
352
353                 LOG(3, "abort check on timeout");
354
355                 r = io_cancel(ct->aio_grp->ioctx, &ct->req->io, &event);
356                 /*
357                  * Only reset ct->running if we really
358                  * could abort the pending I/O
359                  */
360                 if (!r)
361                         ct->running = 0;
362                 rc = PATH_DOWN;
363         } else {
364                 LOG(3, "async io pending");
365                 rc = PATH_PENDING;
366         }
367
368         return rc;
369 }
370
371 int libcheck_check (struct checker * c)
372 {
373         int ret;
374         struct directio_context * ct = (struct directio_context *)c->context;
375
376         if (!ct)
377                 return PATH_UNCHECKED;
378
379         ret = check_state(c->fd, ct, checker_is_sync(c), c->timeout);
380
381         switch (ret)
382         {
383         case PATH_UNCHECKED:
384                 c->msgid = MSG_DIRECTIO_UNKNOWN;
385                 break;
386         case PATH_DOWN:
387                 c->msgid = CHECKER_MSGID_DOWN;
388                 break;
389         case PATH_UP:
390                 c->msgid = CHECKER_MSGID_UP;
391                 break;
392         case PATH_PENDING:
393                 c->msgid = MSG_DIRECTIO_PENDING;
394                 break;
395         default:
396                 break;
397         }
398         return ret;
399 }