4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
22 * Copyright 2020, DataDirect Networks Storage.
24 * This file is part of Lustre, http://www.lustre.org/
26 * Author: John L. Hammond <jhammond@whamcloud.com>
28 * lustre/utils/ofd_access_log_reader.c
30 * Sample utility to discover and read Lustre (ofd) access logs.
32 * This demonstrates the discovery and reading of Lustre access logs
33 * (see linux/lustre/lustre_access_log.h and
34 * lustre/ofd/ofd_access_log.c.). By default it opens the control
35 * device, discovers and opens all access log devices, and consumes
36 * all access log entries. If invoked with the --list option then it
37 * prints information about all available devices to stdout and exits.
39 * Structured trace points (when --trace is used) are added to permit
40 * testing of the access log functionality (see test_165* in
41 * lustre/tests/sanity.sh).
58 #include <sys/epoll.h>
59 #include <sys/ioctl.h>
60 #include <sys/signalfd.h>
62 #include <sys/sysmacros.h>
63 #include <sys/timerfd.h>
64 #include <sys/types.h>
65 #include <linux/types.h>
66 #include <linux/lustre/lustre_user.h>
67 #include <linux/lustre/lustre_access_log.h>
68 #include "ofd_access_batch.h"
71 /* TODO fsname filter */
73 static FILE *debug_file;
74 static FILE *trace_file;
76 #define DEBUG(fmt, args...) \
78 if (debug_file != NULL) \
79 fprintf(debug_file, "DEBUG %s:%d: "fmt, __func__, __LINE__, ##args); \
82 #define TRACE(fmt, args...) \
84 if (trace_file != NULL) \
85 fprintf(trace_file, "TRACE "fmt, ##args); \
88 #define DEBUG_D(x) DEBUG("%s = %"PRIdMAX"\n", #x, (intmax_t)x)
89 #define DEBUG_P(x) DEBUG("%s = %p\n", #x, x)
90 #define DEBUG_S(x) DEBUG("%s = '%s'\n", #x, x)
91 #define DEBUG_U(x) DEBUG("%s = %"PRIuMAX"\n", #x, (uintmax_t)x)
93 #define ERROR(fmt, args...) \
94 fprintf(stderr, "%s: "fmt, program_invocation_short_name, ##args)
96 #define FATAL(fmt, args...) \
98 ERROR("FATAL: "fmt, ##args); \
103 ALR_EXIT_SUCCESS = INT_MIN + EXIT_SUCCESS,
104 ALR_EXIT_FAILURE = INT_MIN + EXIT_FAILURE,
112 int (*alr_io)(int /* epoll_fd */, struct alr_dev * /* this */, unsigned int /* mask */);
113 void (*alr_destroy)(struct alr_dev *);
118 struct alr_dev alr_dev;
121 size_t alr_entry_size;
122 size_t alr_read_count;
126 static unsigned int alr_log_count;
127 static struct alr_log *alr_log[1 << 20]; /* 20 == MINORBITS */
128 static int oal_version; /* FIXME ... major version, minor version */
129 static __u32 alr_filter = 0xffffffff; /* no filter by default */
130 static unsigned int oal_log_major;
131 static unsigned int oal_log_minor_max;
132 static struct alr_batch *alr_batch;
133 static FILE *alr_batch_file;
134 static pthread_mutex_t alr_batch_file_mutex = PTHREAD_MUTEX_INITIALIZER;
135 static const char *alr_batch_file_path;
136 static const char *alr_stats_file_path;
137 static int alr_print_fraction = 100;
139 #define D_ALR_DEV "%s %d"
140 #define P_ALR_DEV(ad) \
141 (ad)->alr_name, (ad)->alr_fd
143 #define D_ALR_LOG D_ALR_DEV" %u:%u"
144 #define P_ALR_LOG(al) \
145 P_ALR_DEV(&(al)->alr_dev), major((al)->alr_rdev), minor((al)->alr_rdev)
147 static void alr_dev_free(int epoll_fd, struct alr_dev *ad)
152 TRACE("alr_dev_free %s\n", ad->alr_name);
154 if (!(ad->alr_fd < 0))
155 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, ad->alr_fd, NULL);
157 if (ad->alr_destroy != NULL)
158 (*ad->alr_destroy)(ad);
160 if (!(ad->alr_fd < 0))
167 static struct alr_log **alr_log_lookup(dev_t rdev)
169 assert(major(rdev) == oal_log_major);
171 if (!(minor(rdev) < ARRAY_SIZE(alr_log)))
174 return &alr_log[minor(rdev)];
177 static const char *alr_flags_to_str(unsigned int flags)
179 switch (flags & (OFD_ACCESS_READ | OFD_ACCESS_WRITE)) {
182 case OFD_ACCESS_READ:
184 case OFD_ACCESS_WRITE:
186 case OFD_ACCESS_READ | OFD_ACCESS_WRITE:
191 /* /dev/lustre-access-log/scratch-OST0000 device poll callback: read entries
192 * from log and print. */
193 static int alr_log_io(int epoll_fd, struct alr_dev *ad, unsigned int mask)
195 struct alr_log *al = container_of(ad, struct alr_log, alr_dev);
198 TRACE("alr_log_io %s\n", ad->alr_name);
201 assert(al->alr_entry_size != 0);
202 assert(al->alr_buf_size != 0);
203 assert(al->alr_buf != NULL);
205 count = read(ad->alr_fd, al->alr_buf, al->alr_buf_size);
207 ERROR("cannot read events from '%s': %s\n", ad->alr_name, strerror(errno));
212 TRACE("alr_log_eof %s\n", ad->alr_name);
216 if (count % al->alr_entry_size != 0) {
217 ERROR("invalid read from "D_ALR_LOG": entry_size = %zu, count = %zd\n",
218 P_ALR_LOG(al), al->alr_entry_size, count);
222 DEBUG("read "D_ALR_LOG", count = %zd\n", P_ALR_LOG(al), count);
224 al->alr_read_count += count / al->alr_entry_size;
226 for (i = 0; i < count; i += al->alr_entry_size) {
227 struct ofd_access_entry_v1 *oae =
228 (struct ofd_access_entry_v1 *)&al->alr_buf[i];
230 TRACE("alr_log_entry %s "DFID" %lu %lu %lu %u %u %s\n",
232 PFID(&oae->oae_parent_fid),
233 (unsigned long)oae->oae_begin,
234 (unsigned long)oae->oae_end,
235 (unsigned long)oae->oae_time,
236 (unsigned int)oae->oae_size,
237 (unsigned int)oae->oae_segment_count,
238 alr_flags_to_str(oae->oae_flags));
240 alr_batch_add(alr_batch, ad->alr_name, &oae->oae_parent_fid,
241 oae->oae_time, oae->oae_begin, oae->oae_end,
242 oae->oae_size, oae->oae_segment_count, oae->oae_flags);
248 static void alr_log_destroy(struct alr_dev *ad)
250 struct alr_log *al = container_of(ad, struct alr_log, alr_dev);
251 struct alr_log **pal;
253 TRACE("alr_log_free %s\n", ad->alr_name);
254 assert(major(al->alr_rdev) == oal_log_major);
256 pal = alr_log_lookup(al->alr_rdev);
257 if (pal != NULL && *pal == al)
262 al->alr_buf_size = 0;
266 /* Add an access log (identified by path) to the epoll set. */
267 static int alr_log_add(int epoll_fd, const char *path)
269 struct alr_log **pal, *al = NULL;
276 fd = open(path, O_RDONLY|O_NONBLOCK|O_CLOEXEC);
278 ERROR("cannot open device '%s': %s\n", path, strerror(errno));
279 rc = (errno == ENOENT ? 0 : -1); /* Possible race. */
283 /* Revalidate rdev in case of race. */
286 ERROR("cannot stat '%s': %s\n", path, strerror(errno));
290 if (major(st.st_rdev) != oal_log_major)
293 pal = alr_log_lookup(st.st_rdev);
295 ERROR("no device slot available for '%s' with minor %u\n",
296 path, minor(st.st_rdev));
301 goto out; /* We already have this device. */
303 struct lustre_access_log_info_v1 lali;
305 memset(&lali, 0, sizeof(lali));
307 rc = ioctl(fd, LUSTRE_ACCESS_LOG_IOCTL_INFO, &lali);
309 ERROR("cannot get info for device '%s': %s\n",
310 path, strerror(errno));
314 if (lali.lali_type != LUSTRE_ACCESS_LOG_TYPE_OFD) {
318 rc = ioctl(fd, LUSTRE_ACCESS_LOG_IOCTL_FILTER, alr_filter);
320 ERROR("cannot set filter '%s': %s\n",
321 path, strerror(errno));
325 al = calloc(1, sizeof(*al));
327 FATAL("cannot allocate struct alr_dev of size %zu: %s\n",
328 sizeof(*al), strerror(errno));
331 al->alr_dev.alr_io = &alr_log_io;
332 al->alr_dev.alr_destroy = &alr_log_destroy;
333 al->alr_dev.alr_fd = fd;
336 al->alr_rdev = st.st_rdev;
338 al->alr_dev.alr_name = strdup(lali.lali_name);
339 if (al->alr_dev.alr_name == NULL)
340 FATAL("cannot copy name of size %zu: %s\n",
341 strlen(lali.lali_name), strerror(errno));
343 al->alr_buf_size = lali.lali_log_size;
344 al->alr_entry_size = lali.lali_entry_size;
346 if (al->alr_entry_size == 0) {
347 ERROR("device '%s' has zero entry size\n", path);
352 if (al->alr_buf_size == 0)
353 al->alr_buf_size = 1048576;
355 al->alr_buf_size = roundup(al->alr_buf_size, al->alr_entry_size);
357 al->alr_buf = malloc(al->alr_buf_size);
358 if (al->alr_buf == NULL)
359 FATAL("cannot allocate log buffer for '%s' of size %zu: %s\n",
360 path, al->alr_buf_size, strerror(errno));
362 struct epoll_event ev = {
363 .events = EPOLLIN | EPOLLHUP,
364 .data.ptr = &al->alr_dev,
367 rc = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, al->alr_dev.alr_fd, &ev);
369 ERROR("cannot add device '%s' to epoll set: %s\n",
370 path, strerror(errno));
374 TRACE("alr_log_add %s\n", al->alr_dev.alr_name);
376 if (oal_log_minor_max < minor(al->alr_rdev))
377 oal_log_minor_max = minor(al->alr_rdev);
379 assert(*pal == NULL);
385 alr_dev_free(epoll_fd, &al->alr_dev);
393 /* Call LUSTRE_ACCESS_LOG_IOCTL_INFO to get access log info and print
394 * YAML formatted info to stdout. */
395 static int alr_log_info(struct alr_log *al)
397 struct lustre_access_log_info_v1 lali;
400 rc = ioctl(al->alr_dev.alr_fd, LUSTRE_ACCESS_LOG_IOCTL_INFO, &lali);
402 ERROR("cannot get info for device '%s': %s\n",
403 al->alr_dev.alr_name, strerror(errno));
407 printf("- name: %s\n"
416 lali.lali_entry_size);
421 static int alr_log_stats(FILE *file, struct alr_log *al)
423 struct lustre_access_log_info_v1 lali;
426 rc = ioctl(al->alr_dev.alr_fd, LUSTRE_ACCESS_LOG_IOCTL_INFO, &lali);
428 ERROR("cannot get info for device '%s': %s\n",
429 al->alr_dev.alr_name, strerror(errno));
434 fprintf(file, "STATS %s %s %u\n", lali.lali_name, #m, lali.m)
438 X(_lali_entry_space);
439 X(_lali_entry_count);
444 fprintf(file, "STATS %s %s %zu\n",
445 lali.lali_name, "alr_read_count", al->alr_read_count);
450 static void alr_log_stats_all(void)
455 if (alr_stats_file_path == NULL) {
457 } else if (strcmp(alr_stats_file_path, "-") == 0) {
460 stats_file = fopen(alr_stats_file_path, "a");
461 if (stats_file == NULL) {
462 ERROR("cannot open '%s': %s\n",
463 alr_stats_file_path, strerror(errno));
468 for (m = 0; m <= oal_log_minor_max; m++) {
469 if (alr_log[m] == NULL)
472 alr_log_stats(stats_file, alr_log[m]);
475 if (stats_file == stdout || stats_file == stderr)
481 /* Scan /dev/lustre-access-log/ for new access log devices and add to
483 static int alr_scan(int epoll_fd)
485 const char dir_path[] = "/dev/"LUSTRE_ACCESS_LOG_DIR_NAME;
491 dir = opendir(dir_path);
493 ERROR("cannot open '%s' for scanning: %s\n", dir_path, strerror(errno));
494 return ALR_EXIT_FAILURE;
499 /* Scan /dev for devices with major equal to oal_log_major and add
500 * any new devices. */
501 while ((d = readdir(dir)) != NULL) {
502 char path[6 + PATH_MAX];
503 struct alr_log **pal;
506 if (d->d_type != DT_CHR)
509 rc = fstatat(dir_fd, d->d_name, &st, 0);
511 ERROR("cannot stat '%s/%s' while scanning: %s\n",
512 dir_path, d->d_name, strerror(errno));
516 if (!S_ISCHR(st.st_mode))
519 if (major(st.st_rdev) != oal_log_major)
522 pal = alr_log_lookup(st.st_rdev);
524 ERROR("no device slot available for '%s/%s' with minor %u\n",
525 dir_path, d->d_name, minor(st.st_rdev));
530 continue; /* We already have this device. */
532 snprintf(path, sizeof(path), "%s/%s", dir_path, d->d_name);
534 alr_log_add(epoll_fd, path);
542 /* /dev/lustre-access-log/control device poll callback: call prescan
543 * ioctl and scan /dev/lustre-access-log/ for new access log
545 static int alr_ctl_io(int epoll_fd, struct alr_dev *cd, unsigned int mask)
549 TRACE("%s\n", __func__);
553 return ALR_EXIT_FAILURE;
556 return ALR_EXIT_SUCCESS;
558 rc = ioctl(cd->alr_fd, LUSTRE_ACCESS_LOG_IOCTL_PRESCAN);
560 ERROR("cannot start scanning: %s\n", strerror(errno));
561 return ALR_EXIT_FAILURE;
564 return alr_scan(epoll_fd);
567 /* signalfd epoll callback. Handle SIGINT and SIGTERM by breaking from
568 * the epoll loop and exiting normally.*/
569 static int alr_signal_io(int epoll_fd, struct alr_dev *sd, unsigned int mask)
571 struct signalfd_siginfo ssi;
574 TRACE("%s\n", __func__);
577 rc = read(sd->alr_fd, &ssi, sizeof(ssi));
581 DEBUG_U(ssi.ssi_signo);
582 switch (ssi.ssi_signo) {
585 return ALR_EXIT_SUCCESS;
591 if (debug_file == NULL)
594 if (trace_file == NULL)
603 /* batching timerfd epoll callback. Print batched access entries to
605 static int alr_batch_timer_io(int epoll_fd, struct alr_dev *td, unsigned int mask)
607 time_t now = time(NULL);
608 uint64_t expire_count;
611 TRACE("%s\n", __func__);
615 rc = read(td->alr_fd, &expire_count, sizeof(expire_count));
619 DEBUG_U(expire_count);
621 rc = alr_batch_print(alr_batch, alr_batch_file, &alr_batch_file_mutex,
624 ERROR("cannot write to '%s': %s\n",
625 alr_batch_file_path, strerror(errno));
629 /* Failed writes will leave alr_batch_file (pipe) in a
630 * weird state so make that fatal. */
631 return (rc < 0) ? ALR_EXIT_FAILURE : ALR_OK;
634 /* batch file (stdout) poll callback: detect remote pipe close and exit. */
635 static int alr_batch_file_io(int epoll_fd, struct alr_dev *ad, unsigned int mask)
637 TRACE("%s\n", __func__);
641 return ALR_EXIT_SUCCESS;
644 return ALR_EXIT_FAILURE;
649 static struct alr_dev *alr_dev_create(int epoll_fd, int fd, const char *name,
651 int (*io)(int, struct alr_dev *, unsigned int),
652 void (*destroy)(struct alr_dev *))
657 alr = calloc(1, sizeof(*alr));
661 alr->alr_name = strdup(name);
662 if (alr->alr_name == NULL) {
667 alr->alr_destroy = destroy;
670 struct epoll_event event = {
675 rc = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, alr->alr_fd, &event);
686 printf("Usage: %s: [OPTION]...\n"
687 "Discover, read, batch, and write Lustre access logs\n"
689 "Mandatory arguments to long options are mandatory for short options too.\n"
690 " -f, --batch-file=FILE print batch to file (default stdout)\n"
691 " -F, --batch-fraction=P set batch printing fraction to P/100\n"
692 " -i, --batch-interval=INTERVAL print batch every INTERVAL seconds\n"
693 " -o, --batch-offset=OFFSET print batch at OFFSET seconds\n"
694 " -e, --exit-on-close exit on close of all log devices\n"
695 " -I, --mdt-index-filter=INDEX set log MDT index filter to INDEX\n"
696 " -h, --help display this help and exit\n"
697 " -l, --list print YAML list of available access logs\n"
698 " -d, --debug[=FILE] print debug messages to FILE (stderr)\n"
699 " -s, --stats=FILE print stats messages to FILE (stderr)\n"
700 " -t, --trace[=FILE] print trace messages to FILE (stderr)\n",
701 program_invocation_short_name);
704 int main(int argc, char *argv[])
706 const char ctl_path[] = "/dev/"LUSTRE_ACCESS_LOG_DIR_NAME"/control";
707 struct alr_dev *alr_signal = NULL;
708 struct alr_dev *alr_batch_timer = NULL;
709 struct alr_dev *alr_batch_file_hup = NULL;
710 struct alr_dev *alr_ctl = NULL;
711 int exit_on_close = 0;
712 time_t batch_interval = 0;
713 time_t batch_offset = 0;
721 static struct option options[] = {
722 { .name = "batch-file", .has_arg = required_argument, .val = 'f', },
723 { .name = "batch-fraction", .has_arg = required_argument, .val = 'F', },
724 { .name = "batch-interval", .has_arg = required_argument, .val = 'i', },
725 { .name = "batch-offset", .has_arg = required_argument, .val = 'o', },
726 { .name = "exit-on-close", .has_arg = no_argument, .val = 'e', },
727 { .name = "mdt-index-filter", .has_arg = required_argument, .val = 'I' },
728 { .name = "debug", .has_arg = optional_argument, .val = 'd', },
729 { .name = "help", .has_arg = no_argument, .val = 'h', },
730 { .name = "list", .has_arg = no_argument, .val = 'l', },
731 { .name = "stats", .has_arg = required_argument, .val = 's', },
732 { .name = "trace", .has_arg = optional_argument, .val = 't', },
736 while ((c = getopt_long(argc, argv, "d::ef:F:hi:I:ls:t::", options, NULL)) != -1) {
742 alr_batch_file_path = optarg;
746 batch_interval = strtoll(optarg, NULL, 0);
747 if (batch_interval < 0 || batch_interval >= 1048576 ||
749 FATAL("invalid batch interval '%s'\n", optarg);
753 batch_offset = strtoll(optarg, NULL, 0);
754 if (batch_offset < 0 || batch_offset >= 1048576 ||
756 FATAL("invalid batch offset '%s'\n", optarg);
759 if (optarg == NULL) {
761 } else if (strcmp(optarg, "-") == 0) {
764 debug_file = fopen(optarg, "a");
765 if (debug_file == NULL)
766 FATAL("cannot open debug file '%s': %s\n",
767 optarg, strerror(errno));
775 alr_print_fraction = strtoll(optarg, NULL, 0);
776 if (alr_print_fraction < 1 || alr_print_fraction > 100)
777 FATAL("invalid batch offset '%s'\n", optarg);
780 alr_filter = strtoll(optarg, NULL, 0);
786 alr_stats_file_path = optarg;
789 if (optarg == NULL) {
791 } else if (strcmp(optarg, "-") == 0) {
794 trace_file = fopen(optarg, "a");
795 if (debug_file == NULL)
796 FATAL("cannot open debug file '%s': %s\n",
797 optarg, strerror(errno));
802 fprintf(stderr, "Try '%s --help' for more information.\n",
803 program_invocation_short_name);
808 if (batch_interval > 0) {
809 alr_batch = alr_batch_create(-1);
810 if (alr_batch == NULL)
811 FATAL("cannot create batch struct: %s\n",
815 if (alr_batch_file_path != NULL) {
816 alr_batch_file = fopen(alr_batch_file_path, "w");
817 if (alr_batch_file == NULL)
818 FATAL("cannot open batch file '%s': %s\n",
819 alr_batch_file_path, strerror(errno));
821 alr_batch_file_path = "stdout";
822 alr_batch_file = stdout;
825 epoll_fd = epoll_create1(EPOLL_CLOEXEC);
827 FATAL("cannot create epoll set: %s\n", strerror(errno));
829 /* Setup signal FD and add to epoll set. */
830 sigset_t signal_mask;
831 sigemptyset(&signal_mask);
832 sigaddset(&signal_mask, SIGINT);
833 sigaddset(&signal_mask, SIGTERM);
834 sigaddset(&signal_mask, SIGUSR1);
835 sigaddset(&signal_mask, SIGUSR2);
836 rc = sigprocmask(SIG_BLOCK, &signal_mask, NULL);
838 FATAL("cannot set process signal mask: %s\n", strerror(errno));
840 int signal_fd = signalfd(-1, &signal_mask, SFD_NONBLOCK|SFD_CLOEXEC);
842 FATAL("cannot create signalfd: %s\n", strerror(errno));
844 alr_signal = alr_dev_create(epoll_fd, signal_fd, "signal", EPOLLIN,
845 &alr_signal_io, NULL);
846 if (alr_signal == NULL)
847 FATAL("cannot register signalfd: %s\n", strerror(errno));
851 /* Setup batch timer FD and add to epoll set. */
853 rc = clock_gettime(CLOCK_REALTIME, &now);
855 FATAL("cannot read realtime clock: %s\n", strerror(errno));
857 int timer_fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
859 FATAL("cannot create batch timerfd: %s\n", strerror(errno));
861 struct itimerspec it = {
862 .it_value.tv_sec = (batch_interval > 0) ?
863 roundup(now.tv_sec, batch_interval) +
864 (batch_offset % batch_interval) :
866 .it_interval.tv_sec = batch_interval,
869 DEBUG_D(it.it_value.tv_sec);
871 rc = timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &it, NULL);
873 FATAL("cannot arm timerfd: %s\n", strerror(errno));
875 alr_batch_timer = alr_dev_create(epoll_fd, timer_fd, "batch_timer",
876 EPOLLIN, &alr_batch_timer_io, NULL);
877 if (alr_batch_timer == NULL)
878 FATAL("cannot register batch timerfd: %s\n", strerror(errno));
882 int batch_fd = dup(fileno(alr_batch_file));
884 FATAL("cannot duplicate batch file descriptor: %s\n",
887 /* We pass events = 0 since we only care about EPOLLHUP. */
888 alr_batch_file_hup = alr_dev_create(epoll_fd, batch_fd, "batch_file", 0,
889 &alr_batch_file_io, NULL);
890 if (alr_batch_file_hup == NULL)
891 FATAL("cannot register batch file HUP: %s\n", strerror(errno));
895 /* Open control device. */
896 int ctl_fd = open(ctl_path, O_RDONLY|O_NONBLOCK|O_CLOEXEC);
898 /* If no OSTs are mounted then the ofd module may not
899 * be loaded and hence the control device may not be
900 * present. Handle this in the same way that we handle
901 * no OSTs and exit_on_close below. */
902 if (errno == ENOENT && exit_on_close) {
903 DEBUG("no control device, exiting\n");
904 exit_status = EXIT_SUCCESS;
908 FATAL("cannot open '%s': %s\n", ctl_path, strerror(errno));
911 /* Get and print interface version. */
912 oal_version = ioctl(ctl_fd, LUSTRE_ACCESS_LOG_IOCTL_VERSION);
914 FATAL("cannot get ofd access log interface version: %s\n", strerror(errno));
916 DEBUG_D(oal_version);
918 /* Get and print device major used for access log devices. */
919 oal_log_major = ioctl(ctl_fd, LUSTRE_ACCESS_LOG_IOCTL_MAJOR);
920 if (oal_log_major < 0)
921 FATAL("cannot get ofd access log major: %s\n", strerror(errno));
923 DEBUG_D(oal_log_major);
925 /* Add control device to epoll set. */
926 alr_ctl = alr_dev_create(epoll_fd, ctl_fd, "control", EPOLLIN,
929 FATAL("cannot register control device: %s\n", strerror(errno));
934 struct epoll_event ev[32];
935 int timeout = (list_info ? 0 : -1);
938 ev_count = epoll_wait(epoll_fd, ev, ARRAY_SIZE(ev), timeout);
940 if (errno == EINTR) /* Signal or timeout. */
943 ERROR("cannot wait on epoll set: %s\n", strerror(errno));
944 exit_status = EXIT_FAILURE;
950 for (i = 0; i < ev_count; i++) {
951 struct alr_dev *ad = ev[i].data.ptr;
952 unsigned int mask = ev[i].events;
954 rc = (*ad->alr_io)(epoll_fd, ad, mask);
956 case ALR_EXIT_FAILURE:
957 exit_status = EXIT_FAILURE;
959 case ALR_EXIT_SUCCESS:
960 exit_status = EXIT_SUCCESS;
964 alr_dev_free(epoll_fd, ad);
972 if (exit_on_close && alr_log_count == 0) {
973 DEBUG("no open logs devices, exiting\n");
974 exit_status = EXIT_SUCCESS;
977 } while (!list_info);
979 exit_status = EXIT_SUCCESS;
981 assert(oal_log_minor_max < ARRAY_SIZE(alr_log));
983 for (m = 0; m <= oal_log_minor_max; m++) {
984 if (alr_log[m] == NULL)
988 rc = alr_log_info(alr_log[m]);
990 exit_status = EXIT_FAILURE;
993 alr_dev_free(epoll_fd, &alr_log[m]->alr_dev);
996 alr_dev_free(epoll_fd, alr_ctl);
997 alr_dev_free(epoll_fd, alr_signal);
998 alr_dev_free(epoll_fd, alr_batch_timer);
999 alr_dev_free(epoll_fd, alr_batch_file_hup);
1002 alr_batch_destroy(alr_batch);
1004 DEBUG_D(exit_status);