1 /*- 2 * Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Spectra Logic Corporation 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions, and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * substantially similar to the "NO WARRANTY" disclaimer below 13 * ("Disclaimer") and any redistribution must be conditioned upon 14 * including a substantially similar Disclaimer requirement for further 15 * binary redistribution. 16 * 17 * NO WARRANTY 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGES. 29 * 30 * Authors: Justin T. Gibbs (Spectra Logic Corporation) 31 */ 32 33 /** 34 * \file zfsd.cc 35 * 36 * The ZFS daemon consumes kernel devdctl(4) event data via devd(8)'s 37 * unix domain socket in order to react to system changes that impact 38 * the function of ZFS storage pools. The goal of this daemon is to 39 * provide similar functionality to the Solaris ZFS Diagnostic Engine 40 * (zfs-diagnosis), the Solaris ZFS fault handler (zfs-retire), and 41 * the Solaris ZFS vdev insertion agent (zfs-mod sysevent handler). 42 */ 43 44 #include <sys/cdefs.h> 45 #include <sys/param.h> 46 #include <sys/fs/zfs.h> 47 48 #include <err.h> 49 #include <libgeom.h> 50 #include <libutil.h> 51 #include <poll.h> 52 #include <syslog.h> 53 54 #include <libzfs.h> 55 56 #include <list> 57 #include <map> 58 #include <string> 59 60 #include <devdctl/guid.h> 61 #include <devdctl/event.h> 62 #include <devdctl/event_factory.h> 63 #include <devdctl/exception.h> 64 #include <devdctl/consumer.h> 65 66 #include "callout.h" 67 #include "vdev_iterator.h" 68 #include "zfsd_event.h" 69 #include "case_file.h" 70 #include "vdev.h" 71 #include "vdev_iterator.h" 72 #include "zfsd.h" 73 #include "zfsd_exception.h" 74 #include "zpool_list.h" 75 76 __FBSDID("$FreeBSD$"); 77 78 /*================================== Macros ==================================*/ 79 #define NUM_ELEMENTS(x) (sizeof(x) / sizeof(*x)) 80 81 /*============================ Namespace Control =============================*/ 82 using DevdCtl::Event; 83 using DevdCtl::EventFactory; 84 using DevdCtl::EventList; 85 86 /*================================ Global Data ===============================*/ 87 int g_debug = 0; 88 libzfs_handle_t *g_zfsHandle; 89 90 /*--------------------------------- ZfsDaemon --------------------------------*/ 91 //- ZfsDaemon Static Private Data ---------------------------------------------- 92 ZfsDaemon *ZfsDaemon::s_theZfsDaemon; 93 bool ZfsDaemon::s_logCaseFiles; 94 bool ZfsDaemon::s_terminateEventLoop; 95 char ZfsDaemon::s_pidFilePath[] = "/var/run/zfsd.pid"; 96 pidfh *ZfsDaemon::s_pidFH; 97 int ZfsDaemon::s_signalPipeFD[2]; 98 bool ZfsDaemon::s_systemRescanRequested(false); 99 EventFactory::Record ZfsDaemon::s_registryEntries[] = 100 { 101 { Event::NOTIFY, "GEOM", &GeomEvent::Builder }, 102 { Event::NOTIFY, "ZFS", &ZfsEvent::Builder } 103 }; 104 105 //- ZfsDaemon Static Public Methods -------------------------------------------- 106 ZfsDaemon & 107 ZfsDaemon::Get() 108 { 109 return (*s_theZfsDaemon); 110 } 111 112 void 113 ZfsDaemon::WakeEventLoop() 114 { 115 write(s_signalPipeFD[1], "+", 1); 116 } 117 118 void 119 ZfsDaemon::RequestSystemRescan() 120 { 121 s_systemRescanRequested = true; 122 ZfsDaemon::WakeEventLoop(); 123 } 124 125 void 126 ZfsDaemon::Run() 127 { 128 ZfsDaemon daemon; 129 130 while (s_terminateEventLoop == false) { 131 132 try { 133 daemon.DisconnectFromDevd(); 134 135 if (daemon.ConnectToDevd() == false) { 136 sleep(30); 137 continue; 138 } 139 140 daemon.DetectMissedEvents(); 141 142 daemon.EventLoop(); 143 144 } catch (const DevdCtl::Exception &exp) { 145 exp.Log(); 146 } 147 } 148 149 daemon.DisconnectFromDevd(); 150 } 151 152 //- ZfsDaemon Private Methods -------------------------------------------------- 153 ZfsDaemon::ZfsDaemon() 154 : Consumer(/*defBuilder*/NULL, s_registryEntries, 155 NUM_ELEMENTS(s_registryEntries)) 156 { 157 if (s_theZfsDaemon != NULL) 158 errx(1, "Multiple ZfsDaemon instances created. Exiting"); 159 160 s_theZfsDaemon = this; 161 162 if (pipe(s_signalPipeFD) != 0) 163 errx(1, "Unable to allocate signal pipe. Exiting"); 164 165 if (fcntl(s_signalPipeFD[0], F_SETFL, O_NONBLOCK) == -1) 166 errx(1, "Unable to set pipe as non-blocking. Exiting"); 167 168 if (fcntl(s_signalPipeFD[1], F_SETFL, O_NONBLOCK) == -1) 169 errx(1, "Unable to set pipe as non-blocking. Exiting"); 170 171 signal(SIGHUP, ZfsDaemon::RescanSignalHandler); 172 signal(SIGINFO, ZfsDaemon::InfoSignalHandler); 173 signal(SIGINT, ZfsDaemon::QuitSignalHandler); 174 signal(SIGTERM, ZfsDaemon::QuitSignalHandler); 175 signal(SIGUSR1, ZfsDaemon::RescanSignalHandler); 176 177 g_zfsHandle = libzfs_init(); 178 if (g_zfsHandle == NULL) 179 errx(1, "Unable to initialize ZFS library. Exiting"); 180 181 Callout::Init(); 182 InitializeSyslog(); 183 OpenPIDFile(); 184 185 if (g_debug == 0) 186 daemon(0, 0); 187 188 UpdatePIDFile(); 189 } 190 191 ZfsDaemon::~ZfsDaemon() 192 { 193 PurgeCaseFiles(); 194 ClosePIDFile(); 195 } 196 197 void 198 ZfsDaemon::PurgeCaseFiles() 199 { 200 CaseFile::PurgeAll(); 201 } 202 203 bool 204 ZfsDaemon::VdevAddCaseFile(Vdev &vdev, void *cbArg) 205 { 206 if (vdev.State() != VDEV_STATE_HEALTHY) 207 CaseFile::Create(vdev); 208 209 return (/*break early*/false); 210 } 211 212 void 213 ZfsDaemon::BuildCaseFiles() 214 { 215 ZpoolList zpl; 216 ZpoolList::iterator pool; 217 218 /* Add CaseFiles for vdevs with issues. */ 219 for (pool = zpl.begin(); pool != zpl.end(); pool++) 220 VdevIterator(*pool).Each(VdevAddCaseFile, NULL); 221 222 /* De-serialize any saved cases. */ 223 CaseFile::DeSerialize(); 224 225 /* Simulate config_sync events to force CaseFile reevaluation */ 226 for (pool = zpl.begin(); pool != zpl.end(); pool++) { 227 char evString[160]; 228 Event *event; 229 nvlist_t *config; 230 uint64_t poolGUID; 231 const char *poolname; 232 233 poolname = zpool_get_name(*pool); 234 config = zpool_get_config(*pool, NULL); 235 if (config == NULL) { 236 syslog(LOG_ERR, "ZFSDaemon::BuildCaseFiles: Could not " 237 "find pool config for pool %s", poolname); 238 continue; 239 } 240 if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 241 &poolGUID) != 0) { 242 syslog(LOG_ERR, "ZFSDaemon::BuildCaseFiles: Could not " 243 "find pool guid for pool %s", poolname); 244 continue; 245 } 246 247 248 snprintf(evString, 160, "!system=ZFS subsystem=ZFS " 249 "type=misc.fs.zfs.config_sync sub_type=synthesized " 250 "pool_name=%s pool_guid=%" PRIu64 "\n", poolname, poolGUID); 251 event = Event::CreateEvent(GetFactory(), string(evString)); 252 if (event != NULL) { 253 event->Process(); 254 delete event; 255 } 256 } 257 } 258 259 void 260 ZfsDaemon::RescanSystem() 261 { 262 struct gmesh mesh; 263 struct gclass *mp; 264 struct ggeom *gp; 265 struct gprovider *pp; 266 int result; 267 268 /* 269 * The devdctl system doesn't replay events for new consumers 270 * of the interface. Emit manufactured DEVFS arrival events 271 * for any devices that already before we started or during 272 * periods where we've lost our connection to devd. 273 */ 274 result = geom_gettree(&mesh); 275 if (result != 0) { 276 syslog(LOG_ERR, "ZfsDaemon::RescanSystem: " 277 "geom_gettree faild with error %d\n", result); 278 return; 279 } 280 281 const string evStart("!system=DEVFS subsystem=CDEV type=CREATE " 282 "sub_type=synthesized cdev="); 283 LIST_FOREACH(mp, &mesh.lg_class, lg_class) { 284 LIST_FOREACH(gp, &mp->lg_geom, lg_geom) { 285 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 286 Event *event; 287 288 string evString(evStart + pp->lg_name + "\n"); 289 event = Event::CreateEvent(GetFactory(), 290 evString); 291 if (event != NULL) { 292 if (event->Process()) 293 SaveEvent(*event); 294 delete event; 295 } 296 } 297 } 298 } 299 geom_deletetree(&mesh); 300 } 301 302 void 303 ZfsDaemon::DetectMissedEvents() 304 { 305 do { 306 PurgeCaseFiles(); 307 308 /* 309 * Discard any events waiting for us. We don't know 310 * if they still apply to the current state of the 311 * system. 312 */ 313 FlushEvents(); 314 315 BuildCaseFiles(); 316 317 /* 318 * If the system state has changed during our 319 * interrogation, start over. 320 */ 321 } while (s_terminateEventLoop == false && EventsPending()); 322 323 RescanSystem(); 324 } 325 326 void 327 ZfsDaemon::EventLoop() 328 { 329 while (s_terminateEventLoop == false) { 330 struct pollfd fds[2]; 331 int result; 332 333 if (s_logCaseFiles == true) { 334 EventList::iterator event(m_unconsumedEvents.begin()); 335 s_logCaseFiles = false; 336 CaseFile::LogAll(); 337 while (event != m_unconsumedEvents.end()) 338 (*event++)->Log(LOG_INFO); 339 } 340 341 Callout::ExpireCallouts(); 342 343 /* Wait for data. */ 344 fds[0].fd = m_devdSockFD; 345 fds[0].events = POLLIN; 346 fds[0].revents = 0; 347 fds[1].fd = s_signalPipeFD[0]; 348 fds[1].events = POLLIN; 349 fds[1].revents = 0; 350 result = poll(fds, NUM_ELEMENTS(fds), /*timeout*/INFTIM); 351 if (result == -1) { 352 if (errno == EINTR) 353 continue; 354 else 355 err(1, "Polling for devd events failed"); 356 } else if (result == 0) { 357 errx(1, "Unexpected result of 0 from poll. Exiting"); 358 } 359 360 if ((fds[0].revents & POLLIN) != 0) 361 ProcessEvents(); 362 363 if ((fds[1].revents & POLLIN) != 0) { 364 static char discardBuf[128]; 365 366 /* 367 * This pipe exists just to close the signal 368 * race. Its contents are of no interest to 369 * us, but we must ensure that future signals 370 * have space in the pipe to write. 371 */ 372 while (read(s_signalPipeFD[0], discardBuf, 373 sizeof(discardBuf)) > 0) 374 ; 375 } 376 377 if (s_systemRescanRequested == true) { 378 s_systemRescanRequested = false; 379 syslog(LOG_INFO, "System Rescan request processed."); 380 RescanSystem(); 381 } 382 383 if ((fds[0].revents & POLLERR) != 0) { 384 syslog(LOG_INFO, "POLLERROR detected on devd socket."); 385 break; 386 } 387 388 if ((fds[0].revents & POLLHUP) != 0) { 389 syslog(LOG_INFO, "POLLHUP detected on devd socket."); 390 break; 391 } 392 } 393 } 394 //- ZfsDaemon staic Private Methods -------------------------------------------- 395 void 396 ZfsDaemon::InfoSignalHandler(int) 397 { 398 s_logCaseFiles = true; 399 ZfsDaemon::WakeEventLoop(); 400 } 401 402 void 403 ZfsDaemon::RescanSignalHandler(int) 404 { 405 RequestSystemRescan(); 406 } 407 408 void 409 ZfsDaemon::QuitSignalHandler(int) 410 { 411 s_terminateEventLoop = true; 412 ZfsDaemon::WakeEventLoop(); 413 } 414 415 void 416 ZfsDaemon::OpenPIDFile() 417 { 418 pid_t otherPID; 419 420 s_pidFH = pidfile_open(s_pidFilePath, 0600, &otherPID); 421 if (s_pidFH == NULL) { 422 if (errno == EEXIST) 423 errx(1, "already running as PID %d. Exiting", otherPID); 424 warn("cannot open PID file"); 425 } 426 } 427 428 void 429 ZfsDaemon::UpdatePIDFile() 430 { 431 if (s_pidFH != NULL) 432 pidfile_write(s_pidFH); 433 } 434 435 void 436 ZfsDaemon::ClosePIDFile() 437 { 438 if (s_pidFH != NULL) 439 pidfile_remove(s_pidFH); 440 } 441 442 void 443 ZfsDaemon::InitializeSyslog() 444 { 445 openlog("zfsd", LOG_NDELAY, LOG_DAEMON); 446 } 447 448