The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/openzfs/cmd/zed/zed.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * This file is part of the ZFS Event Daemon (ZED).
    3  *
    4  * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
    5  * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
    6  * Refer to the OpenZFS git commit log for authoritative copyright attribution.
    7  *
    8  * The contents of this file are subject to the terms of the
    9  * Common Development and Distribution License Version 1.0 (CDDL-1.0).
   10  * You can obtain a copy of the license from the top-level file
   11  * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
   12  * You may not use this file except in compliance with the license.
   13  */
   14 
   15 #include <errno.h>
   16 #include <fcntl.h>
   17 #include <signal.h>
   18 #include <stdio.h>
   19 #include <stdlib.h>
   20 #include <string.h>
   21 #include <sys/mman.h>
   22 #include <sys/stat.h>
   23 #include <unistd.h>
   24 #include "zed.h"
   25 #include "zed_conf.h"
   26 #include "zed_event.h"
   27 #include "zed_file.h"
   28 #include "zed_log.h"
   29 
   30 static volatile sig_atomic_t _got_exit = 0;
   31 static volatile sig_atomic_t _got_hup = 0;
   32 
   33 /*
   34  * Signal handler for SIGINT & SIGTERM.
   35  */
   36 static void
   37 _exit_handler(int signum)
   38 {
   39         (void) signum;
   40         _got_exit = 1;
   41 }
   42 
   43 /*
   44  * Signal handler for SIGHUP.
   45  */
   46 static void
   47 _hup_handler(int signum)
   48 {
   49         (void) signum;
   50         _got_hup = 1;
   51 }
   52 
   53 /*
   54  * Register signal handlers.
   55  */
   56 static void
   57 _setup_sig_handlers(void)
   58 {
   59         struct sigaction sa;
   60 
   61         if (sigemptyset(&sa.sa_mask) < 0)
   62                 zed_log_die("Failed to initialize sigset");
   63 
   64         sa.sa_flags = SA_RESTART;
   65 
   66         sa.sa_handler = SIG_IGN;
   67         if (sigaction(SIGPIPE, &sa, NULL) < 0)
   68                 zed_log_die("Failed to ignore SIGPIPE");
   69 
   70         sa.sa_handler = _exit_handler;
   71         if (sigaction(SIGINT, &sa, NULL) < 0)
   72                 zed_log_die("Failed to register SIGINT handler");
   73 
   74         if (sigaction(SIGTERM, &sa, NULL) < 0)
   75                 zed_log_die("Failed to register SIGTERM handler");
   76 
   77         sa.sa_handler = _hup_handler;
   78         if (sigaction(SIGHUP, &sa, NULL) < 0)
   79                 zed_log_die("Failed to register SIGHUP handler");
   80 
   81         (void) sigaddset(&sa.sa_mask, SIGCHLD);
   82         if (pthread_sigmask(SIG_BLOCK, &sa.sa_mask, NULL) < 0)
   83                 zed_log_die("Failed to block SIGCHLD");
   84 }
   85 
   86 /*
   87  * Lock all current and future pages in the virtual memory address space.
   88  * Access to locked pages will never be delayed by a page fault.
   89  *
   90  * EAGAIN is tested up to max_tries in case this is a transient error.
   91  *
   92  * Note that memory locks are not inherited by a child created via fork()
   93  * and are automatically removed during an execve().  As such, this must
   94  * be called after the daemon fork()s (when running in the background).
   95  */
   96 static void
   97 _lock_memory(void)
   98 {
   99 #if HAVE_MLOCKALL
  100         int i = 0;
  101         const int max_tries = 10;
  102 
  103         for (i = 0; i < max_tries; i++) {
  104                 if (mlockall(MCL_CURRENT | MCL_FUTURE) == 0) {
  105                         zed_log_msg(LOG_INFO, "Locked all pages in memory");
  106                         return;
  107                 }
  108                 if (errno != EAGAIN)
  109                         break;
  110         }
  111         zed_log_die("Failed to lock memory pages: %s", strerror(errno));
  112 
  113 #else /* HAVE_MLOCKALL */
  114         zed_log_die("Failed to lock memory pages: mlockall() not supported");
  115 #endif /* HAVE_MLOCKALL */
  116 }
  117 
  118 /*
  119  * Start daemonization of the process including the double fork().
  120  *
  121  * The parent process will block here until _finish_daemonize() is called
  122  * (in the grandchild process), at which point the parent process will exit.
  123  * This prevents the parent process from exiting until initialization is
  124  * complete.
  125  */
  126 static void
  127 _start_daemonize(void)
  128 {
  129         pid_t pid;
  130         struct sigaction sa;
  131 
  132         /* Create pipe for communicating with child during daemonization. */
  133         zed_log_pipe_open();
  134 
  135         /* Background process and ensure child is not process group leader. */
  136         pid = fork();
  137         if (pid < 0) {
  138                 zed_log_die("Failed to create child process: %s",
  139                     strerror(errno));
  140         } else if (pid > 0) {
  141 
  142                 /* Close writes since parent will only read from pipe. */
  143                 zed_log_pipe_close_writes();
  144 
  145                 /* Wait for notification that daemonization is complete. */
  146                 zed_log_pipe_wait();
  147 
  148                 zed_log_pipe_close_reads();
  149                 _exit(EXIT_SUCCESS);
  150         }
  151 
  152         /* Close reads since child will only write to pipe. */
  153         zed_log_pipe_close_reads();
  154 
  155         /* Create independent session and detach from terminal. */
  156         if (setsid() < 0)
  157                 zed_log_die("Failed to create new session: %s",
  158                     strerror(errno));
  159 
  160         /* Prevent child from terminating on HUP when session leader exits. */
  161         if (sigemptyset(&sa.sa_mask) < 0)
  162                 zed_log_die("Failed to initialize sigset");
  163 
  164         sa.sa_flags = 0;
  165         sa.sa_handler = SIG_IGN;
  166 
  167         if (sigaction(SIGHUP, &sa, NULL) < 0)
  168                 zed_log_die("Failed to ignore SIGHUP");
  169 
  170         /* Ensure process cannot re-acquire terminal. */
  171         pid = fork();
  172         if (pid < 0) {
  173                 zed_log_die("Failed to create grandchild process: %s",
  174                     strerror(errno));
  175         } else if (pid > 0) {
  176                 _exit(EXIT_SUCCESS);
  177         }
  178 }
  179 
  180 /*
  181  * Finish daemonization of the process by closing stdin/stdout/stderr.
  182  *
  183  * This must be called at the end of initialization after all external
  184  * communication channels are established and accessible.
  185  */
  186 static void
  187 _finish_daemonize(void)
  188 {
  189         int devnull;
  190 
  191         /* Preserve fd 0/1/2, but discard data to/from stdin/stdout/stderr. */
  192         devnull = open("/dev/null", O_RDWR);
  193         if (devnull < 0)
  194                 zed_log_die("Failed to open /dev/null: %s", strerror(errno));
  195 
  196         if (dup2(devnull, STDIN_FILENO) < 0)
  197                 zed_log_die("Failed to dup /dev/null onto stdin: %s",
  198                     strerror(errno));
  199 
  200         if (dup2(devnull, STDOUT_FILENO) < 0)
  201                 zed_log_die("Failed to dup /dev/null onto stdout: %s",
  202                     strerror(errno));
  203 
  204         if (dup2(devnull, STDERR_FILENO) < 0)
  205                 zed_log_die("Failed to dup /dev/null onto stderr: %s",
  206                     strerror(errno));
  207 
  208         if ((devnull > STDERR_FILENO) && (close(devnull) < 0))
  209                 zed_log_die("Failed to close /dev/null: %s", strerror(errno));
  210 
  211         /* Notify parent that daemonization is complete. */
  212         zed_log_pipe_close_writes();
  213 }
  214 
  215 /*
  216  * ZFS Event Daemon (ZED).
  217  */
  218 int
  219 main(int argc, char *argv[])
  220 {
  221         struct zed_conf zcp;
  222         uint64_t saved_eid;
  223         int64_t saved_etime[2];
  224 
  225         zed_log_init(argv[0]);
  226         zed_log_stderr_open(LOG_NOTICE);
  227         zed_conf_init(&zcp);
  228         zed_conf_parse_opts(&zcp, argc, argv);
  229         if (zcp.do_verbose)
  230                 zed_log_stderr_open(LOG_INFO);
  231 
  232         if (geteuid() != 0)
  233                 zed_log_die("Must be run as root");
  234 
  235         zed_file_close_from(STDERR_FILENO + 1);
  236 
  237         (void) umask(0);
  238 
  239         if (chdir("/") < 0)
  240                 zed_log_die("Failed to change to root directory");
  241 
  242         if (zed_conf_scan_dir(&zcp) < 0)
  243                 exit(EXIT_FAILURE);
  244 
  245         if (!zcp.do_foreground) {
  246                 _start_daemonize();
  247                 zed_log_syslog_open(LOG_DAEMON);
  248         }
  249         _setup_sig_handlers();
  250 
  251         if (zcp.do_memlock)
  252                 _lock_memory();
  253 
  254         if ((zed_conf_write_pid(&zcp) < 0) && (!zcp.do_force))
  255                 exit(EXIT_FAILURE);
  256 
  257         if (!zcp.do_foreground)
  258                 _finish_daemonize();
  259 
  260         zed_log_msg(LOG_NOTICE,
  261             "ZFS Event Daemon %s-%s (PID %d)",
  262             ZFS_META_VERSION, ZFS_META_RELEASE, (int)getpid());
  263 
  264         if (zed_conf_open_state(&zcp) < 0)
  265                 exit(EXIT_FAILURE);
  266 
  267         if (zed_conf_read_state(&zcp, &saved_eid, saved_etime) < 0)
  268                 exit(EXIT_FAILURE);
  269 
  270 idle:
  271         /*
  272          * If -I is specified, attempt to open /dev/zfs repeatedly until
  273          * successful.
  274          */
  275         do {
  276                 if (!zed_event_init(&zcp))
  277                         break;
  278                 /* Wait for some time and try again. tunable? */
  279                 sleep(30);
  280         } while (!_got_exit && zcp.do_idle);
  281 
  282         if (_got_exit)
  283                 goto out;
  284 
  285         zed_event_seek(&zcp, saved_eid, saved_etime);
  286 
  287         while (!_got_exit) {
  288                 int rv;
  289                 if (_got_hup) {
  290                         _got_hup = 0;
  291                         (void) zed_conf_scan_dir(&zcp);
  292                 }
  293                 rv = zed_event_service(&zcp);
  294 
  295                 /* ENODEV: When kernel module is unloaded (osx) */
  296                 if (rv != 0)
  297                         break;
  298         }
  299 
  300         zed_log_msg(LOG_NOTICE, "Exiting");
  301         zed_event_fini(&zcp);
  302 
  303         if (zcp.do_idle && !_got_exit)
  304                 goto idle;
  305 
  306 out:
  307         zed_conf_destroy(&zcp);
  308         zed_log_fini();
  309         exit(EXIT_SUCCESS);
  310 }

Cache object: 2c834c53151f0c848c843271540ec8d0


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.