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/byteorder.h> 46 #include <sys/param.h> 47 #include <sys/fs/zfs.h> 48 49 #include <err.h> 50 #include <fcntl.h> 51 #include <libgeom.h> 52 #include <libutil.h> 53 #include <poll.h> 54 #include <syslog.h> 55 56 #include <libzfs.h> 57 58 #include <list> 59 #include <map> 60 #include <string> 61 62 #include <devdctl/guid.h> 63 #include <devdctl/event.h> 64 #include <devdctl/event_factory.h> 65 #include <devdctl/exception.h> 66 #include <devdctl/consumer.h> 67 68 #include "callout.h" 69 #include "vdev_iterator.h" 70 #include "zfsd_event.h" 71 #include "case_file.h" 72 #include "vdev.h" 73 #include "vdev_iterator.h" 74 #include "zfsd.h" 75 #include "zfsd_exception.h" 76 #include "zpool_list.h" 77 /*================================== Macros ==================================*/ 78 #define NUM_ELEMENTS(x) (sizeof(x) / sizeof(*x)) 79 80 /*============================ Namespace Control =============================*/ 81 using DevdCtl::Event; 82 using DevdCtl::EventFactory; 83 using DevdCtl::EventList; 84 85 /*================================ Global Data ===============================*/ 86 int g_debug = 0; 87 libzfs_handle_t *g_zfsHandle; 88 89 /*--------------------------------- ZfsDaemon --------------------------------*/ 90 //- ZfsDaemon Static Private Data ---------------------------------------------- 91 ZfsDaemon *ZfsDaemon::s_theZfsDaemon; 92 bool ZfsDaemon::s_logCaseFiles; 93 bool ZfsDaemon::s_terminateEventLoop; 94 char ZfsDaemon::s_pidFilePath[] = "/var/run/zfsd.pid"; 95 pidfh *ZfsDaemon::s_pidFH; 96 int ZfsDaemon::s_signalPipeFD[2]; 97 bool ZfsDaemon::s_systemRescanRequested(false); 98 EventFactory::Record ZfsDaemon::s_registryEntries[] = 99 { 100 { Event::NOTIFY, "GEOM", &GeomEvent::Builder }, 101 { Event::NOTIFY, "ZFS", &ZfsEvent::Builder } 102 }; 103 104 //- ZfsDaemon Static Public Methods -------------------------------------------- 105 ZfsDaemon & 106 ZfsDaemon::Get() 107 { 108 return (*s_theZfsDaemon); 109 } 110 111 void 112 ZfsDaemon::WakeEventLoop() 113 { 114 write(s_signalPipeFD[1], "+", 1); 115 } 116 117 void 118 ZfsDaemon::RequestSystemRescan() 119 { 120 s_systemRescanRequested = true; 121 ZfsDaemon::WakeEventLoop(); 122 } 123 124 void 125 ZfsDaemon::Run() 126 { 127 ZfsDaemon daemon; 128 129 while (s_terminateEventLoop == false) { 130 131 try { 132 daemon.DisconnectFromDevd(); 133 134 if (daemon.ConnectToDevd() == false) { 135 sleep(30); 136 continue; 137 } 138 139 daemon.DetectMissedEvents(); 140 141 daemon.EventLoop(); 142 143 } catch (const DevdCtl::Exception &exp) { 144 exp.Log(); 145 } 146 } 147 148 daemon.DisconnectFromDevd(); 149 } 150 151 //- ZfsDaemon Private Methods -------------------------------------------------- 152 ZfsDaemon::ZfsDaemon() 153 : Consumer(/*defBuilder*/NULL, s_registryEntries, 154 NUM_ELEMENTS(s_registryEntries)) 155 { 156 if (s_theZfsDaemon != NULL) 157 errx(1, "Multiple ZfsDaemon instances created. Exiting"); 158 159 s_theZfsDaemon = this; 160 161 if (pipe(s_signalPipeFD) != 0) 162 errx(1, "Unable to allocate signal pipe. Exiting"); 163 164 if (fcntl(s_signalPipeFD[0], F_SETFL, O_NONBLOCK) == -1) 165 errx(1, "Unable to set pipe as non-blocking. Exiting"); 166 167 if (fcntl(s_signalPipeFD[1], F_SETFL, O_NONBLOCK) == -1) 168 errx(1, "Unable to set pipe as non-blocking. Exiting"); 169 170 signal(SIGHUP, ZfsDaemon::RescanSignalHandler); 171 signal(SIGINFO, ZfsDaemon::InfoSignalHandler); 172 signal(SIGINT, ZfsDaemon::QuitSignalHandler); 173 signal(SIGTERM, ZfsDaemon::QuitSignalHandler); 174 signal(SIGUSR1, ZfsDaemon::RescanSignalHandler); 175 176 g_zfsHandle = libzfs_init(); 177 if (g_zfsHandle == NULL) 178 errx(1, "Unable to initialize ZFS library. Exiting"); 179 180 Callout::Init(); 181 InitializeSyslog(); 182 OpenPIDFile(); 183 184 if (g_debug == 0) 185 daemon(0, 0); 186 187 UpdatePIDFile(); 188 } 189 190 ZfsDaemon::~ZfsDaemon() 191 { 192 PurgeCaseFiles(); 193 ClosePIDFile(); 194 } 195 196 void 197 ZfsDaemon::PurgeCaseFiles() 198 { 199 CaseFile::PurgeAll(); 200 } 201 202 bool 203 ZfsDaemon::VdevAddCaseFile(Vdev &vdev, void *cbArg) 204 { 205 if (vdev.State() != VDEV_STATE_HEALTHY) 206 CaseFile::Create(vdev); 207 208 return (/*break early*/false); 209 } 210 211 void 212 ZfsDaemon::BuildCaseFiles() 213 { 214 ZpoolList zpl; 215 ZpoolList::iterator pool; 216 217 /* Add CaseFiles for vdevs with issues. */ 218 for (pool = zpl.begin(); pool != zpl.end(); pool++) 219 VdevIterator(*pool).Each(VdevAddCaseFile, NULL); 220 221 /* De-serialize any saved cases. */ 222 CaseFile::DeSerialize(); 223 224 /* Simulate config_sync events to force CaseFile reevaluation */ 225 for (pool = zpl.begin(); pool != zpl.end(); pool++) { 226 char evString[160]; 227 Event *event; 228 nvlist_t *config; 229 uint64_t poolGUID; 230 const char *poolname; 231 232 poolname = zpool_get_name(*pool); 233 config = zpool_get_config(*pool, NULL); 234 if (config == NULL) { 235 syslog(LOG_ERR, "ZFSDaemon::BuildCaseFiles: Could not " 236 "find pool config for pool %s", poolname); 237 continue; 238 } 239 if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 240 &poolGUID) != 0) { 241 syslog(LOG_ERR, "ZFSDaemon::BuildCaseFiles: Could not " 242 "find pool guid for pool %s", poolname); 243 continue; 244 } 245 246 247 snprintf(evString, 160, "!system=ZFS subsystem=ZFS " 248 "type=sysevent.fs.zfs.config_sync sub_type=synthesized " 249 "pool_name=%s pool_guid=%" PRIu64 "\n", poolname, poolGUID); 250 event = Event::CreateEvent(GetFactory(), string(evString)); 251 if (event != NULL) { 252 event->Process(); 253 delete event; 254 } 255 } 256 } 257 258 void 259 ZfsDaemon::RescanSystem() 260 { 261 struct gmesh mesh; 262 struct gclass *mp; 263 struct ggeom *gp; 264 struct gprovider *pp; 265 int result; 266 267 /* 268 * The devdctl system doesn't replay events for new consumers 269 * of the interface. Emit manufactured DEVFS arrival events 270 * for any devices that already before we started or during 271 * periods where we've lost our connection to devd. 272 */ 273 result = geom_gettree(&mesh); 274 if (result != 0) { 275 syslog(LOG_ERR, "ZfsDaemon::RescanSystem: " 276 "geom_gettree failed with error %d\n", result); 277 return; 278 } 279 280 const string evStart("!system=DEVFS subsystem=CDEV type=CREATE " 281 "sub_type=synthesized cdev="); 282 LIST_FOREACH(mp, &mesh.lg_class, lg_class) { 283 LIST_FOREACH(gp, &mp->lg_geom, lg_geom) { 284 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 285 Event *event; 286 287 string evString(evStart + pp->lg_name + "\n"); 288 event = Event::CreateEvent(GetFactory(), 289 evString); 290 if (event != NULL) { 291 if (event->Process()) 292 SaveEvent(*event); 293 delete event; 294 } 295 } 296 } 297 } 298 geom_deletetree(&mesh); 299 } 300 301 void 302 ZfsDaemon::DetectMissedEvents() 303 { 304 do { 305 PurgeCaseFiles(); 306 307 /* 308 * Discard any events waiting for us. We don't know 309 * if they still apply to the current state of the 310 * system. 311 */ 312 FlushEvents(); 313 314 BuildCaseFiles(); 315 316 /* 317 * If the system state has changed during our 318 * interrogation, start over. 319 */ 320 } while (s_terminateEventLoop == false && EventsPending()); 321 322 RescanSystem(); 323 } 324 325 void 326 ZfsDaemon::EventLoop() 327 { 328 while (s_terminateEventLoop == false) { 329 struct pollfd fds[2]; 330 int result; 331 332 if (s_logCaseFiles == true) { 333 EventList::iterator event(m_unconsumedEvents.begin()); 334 s_logCaseFiles = false; 335 CaseFile::LogAll(); 336 while (event != m_unconsumedEvents.end()) 337 (*event++)->Log(LOG_INFO); 338 } 339 340 Callout::ExpireCallouts(); 341 342 /* Wait for data. */ 343 fds[0].fd = m_devdSockFD; 344 fds[0].events = POLLIN; 345 fds[0].revents = 0; 346 fds[1].fd = s_signalPipeFD[0]; 347 fds[1].events = POLLIN; 348 fds[1].revents = 0; 349 result = poll(fds, NUM_ELEMENTS(fds), /*timeout*/INFTIM); 350 if (result == -1) { 351 if (errno == EINTR) 352 continue; 353 else 354 err(1, "Polling for devd events failed"); 355 } else if (result == 0) { 356 errx(1, "Unexpected result of 0 from poll. Exiting"); 357 } 358 359 if ((fds[0].revents & POLLIN) != 0) 360 ProcessEvents(); 361 362 if ((fds[1].revents & POLLIN) != 0) { 363 static char discardBuf[128]; 364 365 /* 366 * This pipe exists just to close the signal 367 * race. Its contents are of no interest to 368 * us, but we must ensure that future signals 369 * have space in the pipe to write. 370 */ 371 while (read(s_signalPipeFD[0], discardBuf, 372 sizeof(discardBuf)) > 0) 373 ; 374 } 375 376 if (s_systemRescanRequested == true) { 377 s_systemRescanRequested = false; 378 syslog(LOG_INFO, "System Rescan request processed."); 379 RescanSystem(); 380 } 381 382 if ((fds[0].revents & POLLERR) != 0) { 383 syslog(LOG_INFO, "POLLERROR detected on devd socket."); 384 break; 385 } 386 387 if ((fds[0].revents & POLLHUP) != 0) { 388 syslog(LOG_INFO, "POLLHUP detected on devd socket."); 389 break; 390 } 391 } 392 } 393 //- ZfsDaemon staic Private Methods -------------------------------------------- 394 void 395 ZfsDaemon::InfoSignalHandler(int) 396 { 397 s_logCaseFiles = true; 398 ZfsDaemon::WakeEventLoop(); 399 } 400 401 void 402 ZfsDaemon::RescanSignalHandler(int) 403 { 404 RequestSystemRescan(); 405 } 406 407 void 408 ZfsDaemon::QuitSignalHandler(int) 409 { 410 s_terminateEventLoop = true; 411 ZfsDaemon::WakeEventLoop(); 412 } 413 414 void 415 ZfsDaemon::OpenPIDFile() 416 { 417 pid_t otherPID; 418 419 s_pidFH = pidfile_open(s_pidFilePath, 0600, &otherPID); 420 if (s_pidFH == NULL) { 421 if (errno == EEXIST) 422 errx(1, "already running as PID %d. Exiting", otherPID); 423 warn("cannot open PID file"); 424 } 425 } 426 427 void 428 ZfsDaemon::UpdatePIDFile() 429 { 430 if (s_pidFH != NULL) 431 pidfile_write(s_pidFH); 432 } 433 434 void 435 ZfsDaemon::ClosePIDFile() 436 { 437 if (s_pidFH != NULL) 438 pidfile_remove(s_pidFH); 439 } 440 441 void 442 ZfsDaemon::InitializeSyslog() 443 { 444 openlog("zfsd", LOG_NDELAY, LOG_DAEMON); 445 } 446 447