MFP4 zfsd-related changes

Convert libdevctl to use devd's new SEQPACKET socket.
	lib/libdevctl/consumer.cc
	lib/libdevctl/event_buffer.cc
	lib/libdevctl/event_buffer.h
	lib/libdevctl/reader.cc
	lib/libdevctl/reader.h
		Read from the new /var/run/devd.seqpacket.pipe instead of
		/var/run/devd.pipe.  Since it preserves record boundaries,
		we can eliminate all the repacketization code in
		EventBuffer::ExtractEvent as well as much supporting code
		from the Reader class.

	lib/libdevctl/consumer.cc
		Make the pipe nonblocking.  Previously, we avoided blocking
		by using the FIONREAD ioctl, but this is simpler.

	cddl/sbin/zfsd/case_file.cc
	cddl/sbin/zfsd/tests/zfsd_unittest.cc
	cddl/sbin/zfsd/vdev.cc
	cddl/sbin/zfsd/zfsd.cc
	cddl/sbin/zfsd/zfsd.h
	cddl/sbin/zfsd/zfsd_event.cc
		Update zfsd according to the libdevctl changes.  The only
		nontrivial change is to CaseFile::DeSerialize, which
		elimintes the use of IStreamReader.

	cddl/sbin/zfsd/case_file.cc
		For an unknown reason, sometimes the std::ios::failbit
		will get set on caseStream.  Instead of checking for
		!eof(), check for good().  That method checks the
		eofbit, errorbit, and failbit.

livdevctl cleanup (from gibbs)
	lib/libdevctl/event.cc:
	lib/libdevctl/event.h:
		Remove the event class's name from its Builder method.  It's
		perfectly clear that DevfsEvent::Builder() is the DevfsEvent
		class's Builder function.

	cddl/sbin/zfsd/zfsd.cc:
	cddl/sbin/zfsd/zfsd_event.cc:
	cddl/sbin/zfsd/zfsd_event.h:
		Conform to new libdevct Builder naming convention.

Fix autoreplace by physical path when a hotspare is present
	cddl/sbin/zfsd/case_file.cc
		Fix logic error in CaseFile::Replace regarding whether the
		replacement device is a spare or not.

Reviewed by:	gibbs
Sponsored by:	Spectra Logic
This commit is contained in:
Alan Somers 2014-05-23 23:13:34 +00:00
parent 9102691e9c
commit 6c96553e8a
17 changed files with 167 additions and 140 deletions

View File

@ -59,11 +59,9 @@
#include <devctl/guid.h>
#include <devctl/event.h>
#include <devctl/event_buffer.h>
#include <devctl/event_factory.h>
#include <devctl/exception.h>
#include <devctl/consumer.h>
#include <devctl/reader.h>
#include "callout.h"
#include "vdev_iterator.h"
@ -89,7 +87,6 @@ using DevCtl::EventBuffer;
using DevCtl::EventFactory;
using DevCtl::EventList;
using DevCtl::Guid;
using DevCtl::IstreamReader;
using DevCtl::ParseException;
/*-------------------------- File-scoped classes ----------------------------*/
@ -840,26 +837,28 @@ CaseFile::Serialize()
close(fd);
}
/*
* XXX: This method assumes that events may not contain embedded newlines. If
* ever events can contain embedded newlines, then CaseFile must switch
* serialization formats
*/
void
CaseFile::DeSerialize(ifstream &caseStream)
{
stringstream fakeDevdSocket(stringstream::in|stringstream::out);
IstreamReader caseReader(&fakeDevdSocket);
EventBuffer eventBuffer(caseReader);
string evString;
const EventFactory &factory(ZfsDaemon::Get().GetFactory());
caseStream >> std::noskipws >> std::ws;
while (!caseStream.eof()) {
while (caseStream.good()) {
/*
* Outline:
* read the beginning of a line and check it for
* "tentative". If found, discard "tentative".
* Shove into fakeDevdSocket.
* call ExtractEvent
* Create a new event
* continue
*/
EventList* destEvents;
string tentFlag("tentative ");
const string tentFlag("tentative ");
string line;
std::stringbuf lineBuf;
@ -867,20 +866,16 @@ CaseFile::DeSerialize(ifstream &caseStream)
caseStream.ignore(); /*discard the newline character*/
line = lineBuf.str();
if (line.compare(0, tentFlag.size(), tentFlag) == 0) {
/* Discard "tentative" */
line.erase(0, tentFlag.size());
destEvents = &m_tentativeEvents;
} else {
destEvents = &m_events;
}
fakeDevdSocket << line;
fakeDevdSocket << '\n';
const EventFactory &factory(ZfsDaemon::Get().GetFactory());
while (eventBuffer.ExtractEvent(evString)) {
Event *event(Event::CreateEvent(factory, evString));
if (event != NULL) {
destEvents->push_back(event);
RegisterCallout(*event);
}
Event *event(Event::CreateEvent(factory, line));
if (event != NULL) {
destEvents->push_back(event);
RegisterCallout(*event);
}
}
}
@ -1032,7 +1027,7 @@ CaseFile::Replace(const char* vdev_type, const char* path, bool isspare) {
Vdev vd(zhp, CaseVdev(zhp));
Vdev replaced(BeingReplacedBy(zhp));
if (!vd.IsSpare() && !replaced.DoesNotExist()) {
if (isspare && !vd.IsSpare() && !replaced.DoesNotExist()) {
/* If we are already being replaced by a working spare, pass. */
if (replaced.IsResilvering()
|| replaced.State() == VDEV_STATE_HEALTHY) {
@ -1044,12 +1039,10 @@ CaseFile::Replace(const char* vdev_type, const char* path, bool isspare) {
* If we have already been replaced by a spare, but that spare
* is broken, we must spare the spare, not the original device.
*/
if (isspare) {
oldstr = replaced.GUIDString();
syslog(LOG_INFO, "CaseFile::Replace(%s->%s): sparing "
"broken spare %s instead", VdevGUIDString().c_str(),
path, oldstr.c_str());
}
oldstr = replaced.GUIDString();
syslog(LOG_INFO, "CaseFile::Replace(%s->%s): sparing "
"broken spare %s instead", VdevGUIDString().c_str(),
path, oldstr.c_str());
}
/*

View File

@ -7,8 +7,6 @@ SRCDIR=${.CURDIR}/../../../..
PROG_CXX= zfsd_unittest
SRCS:= ${SRCS:Nzfsd_main.cc}
SRCS+= libmocks.c zfsd_unittest.cc
CLEANFILES+= *.gcno *.gcda *.info
CLEANDIRS+= lcov-report
# Use #include <zfsd/xxx.h> in test programs.
INCFLAGS+= -I ${.CURDIR}/../..
@ -26,9 +24,6 @@ LIBRARY_PATH=
.endif
ZFSD_UNITTEST= env LD_LIBRARY_PATH=${LIBRARY_PATH} ./zfsd_unittest
# Extra tools
LCOV= lcov
# Googletest options
LOCALBASE?= /usr/local
INCFLAGS+= -I ${LOCALBASE}/include -D_THREAD_SAFE -pthread
@ -42,42 +37,12 @@ LDADD+= ${LOCALBASE}/lib/libgmock.a ${LOCALBASE}/lib/libgmock_main.a
# https://groups.google.com/forum/#!msg/googletestframework/h8ixEPCFm0o/amwfu4xGJb0J
CFLAGS+= -DGTEST_HAS_PTHREAD
# GCOV options
CFLAGS+= -fprofile-arcs -ftest-coverage
LDADD+= -lgcov
all: tests
# Install the tests
TESTSBASE?= /usr/tests
TESTSDIR= ${TESTSBASE}/zfsd
TESTSDIR= ${TESTSBASE}/cddl/sbin/zfsd
# TODO: Convert from an ATF SH test to a Kyua plain test
# Long term TODO: Convert to a Kyua googletest test
TESTS_SH+= zfsd_test
ATF_TESTS_SH+= zfsd_test
BINDIR= ${TESTSDIR}
# Install the gcov annotation files too
FILESDIR= ${TESTSDIR}
GCNOS= ${SRCS:C/.c+$/.gcno/}
${GCNOS}: ${SRCS:C/.c+$/.o/}
FILES= ${GCNOS}
# Run the tests and produce the coverage report
EXCLUDE_PATTERNS='/usr/include/*' '${LOCALBASE}/include/*'
EXCLUDE_PATTERNS+= '*/cddl/compat/opensolaris/include/*'
EXCLUDE_PATTERNS+= '*/tools/regression/zfsd/*'
.PHONY: tests
tests: zfsd_unittest
${ZFSD_UNITTEST} --gmock_verbose=error
.PHONY: lcov
lcov: zfsd_unittest
${LCOV} -z -d . -f && \
${ZFSD_UNITTEST} --gmock_verbose=error
${LCOV} -f -d . -c -o default.info && \
${LCOV} -r default.info $(EXCLUDE_PATTERNS) -o trimmed.info && \
mkdir -p lcov-report && \
genhtml -o lcov-report trimmed.info
.include <atf.test.mk>
.include <bsd.test.mk>

View File

@ -43,7 +43,26 @@ zfsd_unittest_head()
zfsd_unittest_body()
{
atf_check -s exit:0 -o ignore -e ignore $(atf_get_srcdir)/zfsd_unittest
TESTPROG=$(atf_get_srcdir)/zfsd_unittest
if atf_config_has coverage_dir; then
# If coverage_dir is defined, then we want to save the .gcda
# and .gcno files for future analysis. Put them in a directory
# tree that resembles /usr/src, but is anchored at
# coverage_dir.
export GCOV_PREFIX=`atf_config_get coverage_dir`
# Examine zfsd_unittest to calculate the GCOV_PREFIX_STRIP
# The outer echo command is needed to strip off whitespace
# printed by wc
OLDGCDADIR=`strings $TESTPROG | grep 'zfsd.gcda'`
export GCOV_PREFIX_STRIP=$( echo $( echo $OLDGCDADIR | \
sed -e 's:/cddl/sbin/zfsd.*::' -e 's:/: :g' | \
wc -w ) )
NEWGCDADIR=$GCOV_PREFIX/`dirname $OLDGCDADIR | \
sed -e 's:.*\(cddl/sbin/zfsd\):\1:'`
mkdir -p $NEWGCDADIR
cp $(atf_get_srcdir)/*.gcno $NEWGCDADIR
fi
atf_check -s exit:0 -o ignore -e ignore $TESTPROG
}
atf_init_test_cases()

View File

@ -47,11 +47,9 @@
#include <devctl/guid.h>
#include <devctl/event.h>
#include <devctl/event_buffer.h>
#include <devctl/event_factory.h>
#include <devctl/exception.h>
#include <devctl/consumer.h>
#include <devctl/reader.h>
#include <zfsd/callout.h>
#include <zfsd/vdev_iterator.h>
@ -365,17 +363,12 @@ TEST_F(VdevTest, AvailSpareState) {
/* Test the Vdev::IsSpare method */
TEST_F(VdevTest, IsSpare) {
Vdev* vdev;
vdev = new Vdev(m_poolConfig, m_vdevConfig);
EXPECT_EQ(false, vdev->IsSpare());
delete vdev;
Vdev notSpare(m_poolConfig, m_vdevConfig);
EXPECT_EQ(false, notSpare.IsSpare());
ASSERT_EQ(0, nvlist_add_uint64(m_vdevConfig, ZPOOL_CONFIG_IS_SPARE, 1));
vdev = new Vdev(m_poolConfig, m_vdevConfig);
EXPECT_EQ(true, vdev->IsSpare());
delete vdev;
Vdev isSpare(m_poolConfig, m_vdevConfig);
EXPECT_EQ(true, isSpare.IsSpare());
}
/*

View File

@ -50,7 +50,6 @@
#include <devctl/guid.h>
#include <devctl/event.h>
#include <devctl/event_buffer.h>
#include <devctl/event_factory.h>
#include <devctl/exception.h>
#include <devctl/consumer.h>

View File

@ -59,11 +59,9 @@
#include <devctl/guid.h>
#include <devctl/event.h>
#include <devctl/event_buffer.h>
#include <devctl/event_factory.h>
#include <devctl/exception.h>
#include <devctl/consumer.h>
#include <devctl/reader.h>
#include "callout.h"
#include "vdev_iterator.h"
@ -82,11 +80,8 @@ __FBSDID("$FreeBSD$");
/*============================ Namespace Control =============================*/
using DevCtl::Event;
using DevCtl::EventBuffer;
using DevCtl::EventFactory;
using DevCtl::EventList;
using DevCtl::Guid;
using DevCtl::NVPairMap;
/*================================ Global Data ===============================*/
int g_debug = 0;
@ -103,8 +98,8 @@ int ZfsDaemon::s_signalPipeFD[2];
bool ZfsDaemon::s_systemRescanRequested(false);
EventFactory::Record ZfsDaemon::s_registryEntries[] =
{
{ Event::NOTIFY, "DEVFS", &DevfsEvent::DevfsEventBuilder },
{ Event::NOTIFY, "ZFS", &ZfsEvent::ZfsEventBuilder }
{ Event::NOTIFY, "DEVFS", &DevfsEvent::Builder },
{ Event::NOTIFY, "ZFS", &ZfsEvent::Builder }
};
//- ZfsDaemon Static Public Methods --------------------------------------------

View File

@ -52,7 +52,6 @@
* #include <devctl/event.h>
* #include <devctl/event_factory.h>
* #include <devctl/consumer.h>
* #include <devctl/reader.h>
*
* #include "vdev_iterator.h"
*/

View File

@ -51,7 +51,6 @@
#include <devctl/event_factory.h>
#include <devctl/exception.h>
#include <devctl/consumer.h>
#include <devctl/reader.h>
#include "callout.h"
#include "vdev_iterator.h"
@ -75,9 +74,9 @@ using std::stringstream;
//- DevfsEvent Static Public Methods -------------------------------------------
Event *
DevfsEvent::DevfsEventBuilder(Event::Type type,
NVPairMap &nvPairs,
const string &eventString)
DevfsEvent::Builder(Event::Type type,
NVPairMap &nvPairs,
const string &eventString)
{
return (new DevfsEvent(type, nvPairs, eventString));
}
@ -230,8 +229,8 @@ DevfsEvent::DevfsEvent(const DevfsEvent &src)
/*--------------------------------- ZfsEvent ---------------------------------*/
//- ZfsEvent Static Public Methods ---------------------------------------------
DevCtl::Event *
ZfsEvent::ZfsEventBuilder(Event::Type type, NVPairMap &nvpairs,
const string &eventString)
ZfsEvent::Builder(Event::Type type, NVPairMap &nvpairs,
const string &eventString)
{
return (new ZfsEvent(type, nvpairs, eventString));
}

View File

@ -66,7 +66,7 @@ class DevfsEvent : public DevCtl::DevfsEvent
{
public:
/** Specialized DevCtlEvent object factory for Devfs events. */
static BuildMethod DevfsEventBuilder;
static BuildMethod Builder;
virtual DevCtl::Event *DeepCopy() const;
@ -122,7 +122,7 @@ class ZfsEvent : public DevCtl::ZfsEvent
{
public:
/** Specialized DevCtlEvent object factory for ZFS events. */
static BuildMethod ZfsEventBuilder;
static BuildMethod Builder;
virtual DevCtl::Event *DeepCopy() const;

View File

@ -54,6 +54,8 @@
lib
..
sbin
zfsd
..
..
usr.bin
..

View File

@ -3,18 +3,14 @@
LIB= devctl
INCS= consumer.h \
event.h \
event_buffer.h \
event_factory.h \
exception.h \
guid.h \
reader.h
guid.h
SRCS= consumer.cc \
event.cc \
event_buffer.cc \
event_factory.cc \
exception.cc \
guid.cc \
reader.cc
guid.cc
INCSDIR= ${INCLUDEDIR}/devctl

View File

@ -37,24 +37,24 @@
#include <sys/cdefs.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/un.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <syslog.h>
#include <unistd.h>
#include <cstdarg>
#include <cstring>
#include <list>
#include <map>
#include <string>
#include "guid.h"
#include "event.h"
#include "event_buffer.h"
#include "event_factory.h"
#include "exception.h"
#include "reader.h"
#include "consumer.h"
@ -71,15 +71,13 @@ namespace DevCtl
/*============================= Class Definitions ============================*/
/*----------------------------- DevCtl::Consumer -----------------------------*/
//- Consumer Static Private Data -----------------------------------------------
const char Consumer::s_devdSockPath[] = "/var/run/devd.pipe";
const char Consumer::s_devdSockPath[] = "/var/run/devd.seqpacket.pipe";
//- Consumer Public Methods ----------------------------------------------------
Consumer::Consumer(Event::BuildMethod *defBuilder,
EventFactory::Record *regEntries,
size_t numEntries)
: m_devdSockFD(-1),
m_reader(NULL),
m_eventBuffer(NULL),
m_eventFactory(defBuilder),
m_replayingEvents(false)
{
@ -89,8 +87,6 @@ Consumer::Consumer(Event::BuildMethod *defBuilder,
Consumer::~Consumer()
{
DisconnectFromDevd();
delete m_reader;
m_reader = NULL;
}
bool
@ -112,9 +108,11 @@ Consumer::ConnectToDevd()
strlcpy(devdAddr.sun_path, s_devdSockPath, sizeof(devdAddr.sun_path));
sLen = SUN_LEN(&devdAddr);
m_devdSockFD = socket(AF_UNIX, SOCK_STREAM, 0);
m_devdSockFD = socket(AF_UNIX, SOCK_SEQPACKET, 0);
if (m_devdSockFD == -1)
err(1, "Unable to create socket");
if (fcntl(m_devdSockFD, F_SETFL, O_NONBLOCK) < 0)
err(1, "fcntl");
result = connect(m_devdSockFD,
reinterpret_cast<sockaddr *>(&devdAddr),
sLen);
@ -124,9 +122,6 @@ Consumer::ConnectToDevd()
return (false);
}
/* Connect the stream to the file descriptor */
m_reader = new FDReader(m_devdSockFD);
m_eventBuffer = new EventBuffer(*m_reader);
syslog(LOG_INFO, "Connection to devd successful");
return (true);
}
@ -137,14 +132,26 @@ Consumer::DisconnectFromDevd()
if (m_devdSockFD != -1)
syslog(LOG_INFO, "Disconnecting from devd.");
delete m_eventBuffer;
m_eventBuffer = NULL;
delete m_reader;
m_reader = NULL;
close(m_devdSockFD);
m_devdSockFD = -1;
}
std::string
Consumer::ReadEvent()
{
char buf[MAX_EVENT_SIZE + 1];
ssize_t len;
len = ::recv(m_devdSockFD, buf, MAX_EVENT_SIZE, MSG_WAITALL);
if (len == -1)
return (std::string(""));
else {
/* NULL-terminate the result */
buf[len] = '\0';
return (std::string(buf));
}
}
void
Consumer::ReplayUnconsumedEvents(bool discardUnconsumed)
{
@ -178,20 +185,20 @@ Consumer::SaveEvent(const Event &event)
}
Event *
Consumer::NextEvent(EventBuffer *eventBuffer)
Consumer::NextEvent()
{
if (!Connected())
return(NULL);
if (eventBuffer == NULL)
eventBuffer = m_eventBuffer;
Event *event(NULL);
try {
string evString;
if (eventBuffer->ExtractEvent(evString))
evString = ReadEvent();
if (! evString.empty()) {
Event::TimestampEventString(evString);
event = Event::CreateEvent(m_eventFactory, evString);
}
} catch (const Exception &exp) {
exp.Log();
DisconnectFromDevd();
@ -201,10 +208,10 @@ Consumer::NextEvent(EventBuffer *eventBuffer)
/* Capture and process buffered events. */
void
Consumer::ProcessEvents(EventBuffer *eventBuffer)
Consumer::ProcessEvents()
{
Event *event;
while ((event = NextEvent(eventBuffer)) != NULL) {
while ((event = NextEvent()) != NULL) {
if (event->Process())
SaveEvent(*event);
delete event;
@ -214,10 +221,11 @@ Consumer::ProcessEvents(EventBuffer *eventBuffer)
void
Consumer::FlushEvents()
{
char discardBuf[256];
std::string s;
while (m_reader->in_avail() > 0)
m_reader->read(discardBuf, sizeof(discardBuf));
do
s = ReadEvent();
while (! s.empty()) ;
}
bool

View File

@ -81,14 +81,13 @@ public:
*/
void ReplayUnconsumedEvents(bool discardUnconsumed);
/** Return an event, if available, from the provided EventBuffer. */
Event *NextEvent(EventBuffer *eventBuffer = NULL);
/** Return an event, if one is available. */
Event *NextEvent();
/**
* Extract events from the provided eventBuffer and invoke
* each event's Process method.
* Extract events and invoke each event's Process method.
*/
void ProcessEvents(EventBuffer *eventBuffer = NULL);
void ProcessEvents();
/** Discard all data pending in m_devdSockFD. */
void FlushEvents();
@ -116,6 +115,22 @@ public:
EventFactory GetFactory();
protected:
/**
* \brief Reads the most recent record
*
* On error, "" is returned, and errno will be set by the OS
*
* \returns A string containing the record
*/
std::string ReadEvent();
enum {
/*
* The maximum event size supported by libdevctl.
*/
MAX_EVENT_SIZE = 8192,
};
static const char s_devdSockPath[];
/**

View File

@ -40,12 +40,18 @@
#include <sys/disk.h>
#include <sys/filio.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <err.h>
#include <fcntl.h>
#include <paths.h>
#include <stdlib.h>
#include <syslog.h>
#include <unistd.h>
#include <cstdarg>
#include <cstring>
#include <iostream>
#include <list>
#include <map>
@ -86,8 +92,8 @@ Event::EventTypeRecord Event::s_typeTable[] =
//- Event Static Public Methods ------------------------------------------------
Event *
Event::EventBuilder(Event::Type type, NVPairMap &nvPairs,
const string &eventString)
Event::Builder(Event::Type type, NVPairMap &nvPairs,
const string &eventString)
{
return (new Event(type, nvPairs, eventString));
}
@ -325,11 +331,35 @@ Event::ParseEventString(Event::Type type,
}
}
void
Event::TimestampEventString(std::string &eventString)
{
if (eventString.size() > 0) {
/*
* Add a timestamp as the final field of the event if it is
* not already present.
*/
if (eventString.find("timestamp=") == string::npos) {
const size_t bufsize = 32; // Long enough for a 64-bit int
timeval now;
struct tm* time_s;
char timebuf[bufsize];
size_t eventEnd(eventString.find_last_not_of('\n') + 1);
if (gettimeofday(&now, NULL) != 0)
err(1, "gettimeofday");
time_s = gmtime(&now.tv_sec);
strftime(timebuf, bufsize, " timestamp=%s", time_s);
eventString.insert(eventEnd, timebuf);
}
}
}
/*-------------------------------- DevfsEvent --------------------------------*/
//- DevfsEvent Static Public Methods -------------------------------------------
Event *
DevfsEvent::DevfsEventBuilder(Event::Type type, NVPairMap &nvPairs,
const string &eventString)
DevfsEvent::Builder(Event::Type type, NVPairMap &nvPairs,
const string &eventString)
{
return (new DevfsEvent(type, nvPairs, eventString));
}
@ -495,8 +525,8 @@ DevfsEvent::DevfsEvent(const DevfsEvent &src)
/*--------------------------------- ZfsEvent ---------------------------------*/
//- ZfsEvent Static Public Methods ---------------------------------------------
Event *
ZfsEvent::ZfsEventBuilder(Event::Type type, NVPairMap &nvpairs,
const string &eventString)
ZfsEvent::Builder(Event::Type type, NVPairMap &nvpairs,
const string &eventString)
{
return (new ZfsEvent(type, nvpairs, eventString));
}

View File

@ -95,7 +95,7 @@ public:
typedef Event* (BuildMethod)(Type, NVPairMap &, const std::string &);
/** Generic Event object factory. */
static BuildMethod EventBuilder;
static BuildMethod Builder;
static Event *CreateEvent(const EventFactory &factory,
const std::string &eventString);
@ -189,6 +189,16 @@ public:
*/
timeval GetTimestamp() const;
/**
* Add a timestamp to the event string, if one does not already exist
* TODO: make this an instance method that operates on the std::map
* instead of the string. We must fix zfsd's CaseFile serialization
* routines first, so that they don't need the raw event string.
*
* \param[in,out] eventString The devd event string to modify
*/
static void TimestampEventString(std::string &eventString);
/**
* Access all parsed key => value pairs.
*/
@ -277,7 +287,7 @@ class DevfsEvent : public Event
{
public:
/** Specialized Event object factory for Devfs events. */
static BuildMethod DevfsEventBuilder;
static BuildMethod Builder;
virtual Event *DeepCopy() const;
@ -326,7 +336,7 @@ class ZfsEvent : public Event
{
public:
/** Specialized Event object factory for ZFS events. */
static BuildMethod ZfsEventBuilder;
static BuildMethod Builder;
virtual Event *DeepCopy() const;

View File

@ -88,8 +88,10 @@ EventFactory::Build(Event::Type type, NVPairMap &nvpairs,
if (foundMethod != m_registry.end())
buildMethod = foundMethod->second;
if (buildMethod == NULL)
if (buildMethod == NULL) {
delete &nvpairs;
return (NULL);
}
return (buildMethod(type, nvpairs, eventString));
}

View File

@ -37,6 +37,8 @@
#include <syslog.h>
#include <cstdio>
#include <cstdarg>
#include <sstream>
#include <string>