Hi, > 1) Start reload_db() in a background thread, resume scanning, and call > back once the new engine is in place; then exchange the pointers > from old to new engine and free the old one.
FWIW, I have implemented this option, and it seems to work just fine. Patch is pasted below. Do you see any problems with this approach? Julius -- >From 56e376e55db86571e50737cf20a33b8716cad291 Mon Sep 17 00:00:00 2001 From: Julius Plenz <[email protected]> Date: Mon, 7 Apr 2014 19:21:44 +0200 Subject: [PATCH] Reload virus definition in separate thread, eliminating delay This implements option #1 of http://lurker.clamav.net/message/20140407.145009.12f41a68.en.html We introduce a daemon-global "reload_engine" pointer, also protected under the reload_mutex. Instead of calling reload_db() syncronously, we dispatch a thread that will eventually write to the reload_engine pointer, signaling that the new engine is fully set up. Then, under protection of the mutex, the current engine is exchanged and the old engine freed. --- clamd/server-th.c | 120 +++++++++++++++++++++++++++++------------------------- clamd/server.h | 7 ++++ 2 files changed, 71 insertions(+), 56 deletions(-) diff --git a/clamd/server-th.c b/clamd/server-th.c index 86a3a48..9afa2b7 100644 --- a/clamd/server-th.c +++ b/clamd/server-th.c @@ -64,6 +64,7 @@ int progexit = 0; pthread_mutex_t exit_mutex = PTHREAD_MUTEX_INITIALIZER; int reload = 0; +struct cl_engine *reload_engine = NULL; time_t reloaded_time = 0; pthread_mutex_t reload_mutex = PTHREAD_MUTEX_INITIALIZER; int sighup = 0; @@ -158,40 +159,27 @@ void sighandler_th(int sig) logg("$Failed to write to syncpipe\n"); } -static struct cl_engine *reload_db(struct cl_engine *engine, unsigned int dboptions, const struct optstruct *opts, int do_check, int *ret) +static void *reload_db(void *argp) { const char *dbdir; int retval; unsigned int sigs = 0; struct cl_settings *settings = NULL; + struct cl_engine *engine = NULL; - *ret = 0; - if(do_check) { - if(!dbstat.entries) { - logg("No stats for Database check - forcing reload\n"); - return engine; - } - - if(cl_statchkdir(&dbstat) == 1) { - logg("SelfCheck: Database modification detected. Forcing reload.\n"); - return engine; - } else { - logg("SelfCheck: Database status OK.\n"); - return NULL; - } - } + struct reload_db_args *args = (struct reload_db_args *)argp; + struct cl_engine *oldengine = args->engine; + unsigned int dboptions = args->dboptions; + const struct optstruct *opts = args->opts; - /* release old structure */ - if(engine) { + if(oldengine) { /* copy current settings */ - settings = cl_engine_settings_copy(engine); + settings = cl_engine_settings_copy(oldengine); if(!settings) logg("^Can't make a copy of the current engine settings\n"); - - thrmgr_setactiveengine(NULL); - cl_engine_free(engine); } + dbdir = optget(opts, "DatabaseDirectory")->strarg; logg("Reading databases from %s\n", dbdir); @@ -201,18 +189,16 @@ static struct cl_engine *reload_db(struct cl_engine *engine, unsigned int dbopti memset(&dbstat, 0, sizeof(struct cl_stat)); if((retval = cl_statinidir(dbdir, &dbstat))) { logg("!cl_statinidir() failed: %s\n", cl_strerror(retval)); - *ret = 1; if(settings) cl_engine_settings_free(settings); - return NULL; + return; } if(!(engine = cl_engine_new())) { logg("!Can't initialize antivirus engine\n"); - *ret = 1; if(settings) cl_engine_settings_free(settings); - return NULL; + return; } if(settings) { @@ -227,20 +213,20 @@ static struct cl_engine *reload_db(struct cl_engine *engine, unsigned int dbopti if((retval = cl_load(dbdir, engine, &sigs, dboptions))) { logg("!reload db failed: %s\n", cl_strerror(retval)); cl_engine_free(engine); - *ret = 1; - return NULL; + return; } if((retval = cl_engine_compile(engine)) != 0) { logg("!Database initialization error: can't compile engine: %s\n", cl_strerror(retval)); cl_engine_free(engine); - *ret = 1; - return NULL; + return; } logg("Database correctly reloaded (%u signatures)\n", sigs); - thrmgr_setactiveengine(engine); - return engine; + pthread_mutex_lock(&reload_mutex); + time(&reloaded_time); + reload_engine = engine; + pthread_mutex_unlock(&reload_mutex); } /* @@ -713,6 +699,7 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi unsigned long long val; size_t i, j, rr_last = 0; pthread_t accept_th; + pthread_t reload_th; pthread_mutex_t fds_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t recvfds_mutex = PTHREAD_MUTEX_INITIALIZER; struct acceptdata acceptdata = ACCEPTDATA_INIT(&fds_mutex, &recvfds_mutex); @@ -1347,10 +1334,20 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi if(selfchk) { time(¤t_time); if((current_time - start_time) >= (time_t)selfchk) { - if(reload_db(engine, dboptions, opts, TRUE, &ret)) { + if(!dbstat.entries) { + logg("No stats for Database check - forcing reload\n"); + pthread_mutex_lock(&reload_mutex); + reload = 1; + pthread_mutex_unlock(&reload_mutex); + } + + if(cl_statchkdir(&dbstat) == 1) { + logg("SelfCheck: Database modification detected. Forcing reload.\n"); pthread_mutex_lock(&reload_mutex); reload = 1; pthread_mutex_unlock(&reload_mutex); + } else { + logg("SelfCheck: Database status OK.\n"); } time(&start_time); } @@ -1360,34 +1357,45 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi pthread_mutex_lock(&reload_mutex); if(reload) { pthread_mutex_unlock(&reload_mutex); -#if defined(FANOTIFY) || defined(CLAMAUTH) - if(optget(opts, "ScanOnAccess")->enabled && tharg) { - logg("Restarting on-access scan\n"); - pthread_kill(fan_pid, SIGUSR1); - pthread_join(fan_pid, NULL); - } -#endif - engine = reload_db(engine, dboptions, opts, FALSE, &ret); - if(ret) { - logg("Terminating because of a fatal error.\n"); - if(new_sd >= 0) - closesocket(new_sd); - break; - } - + struct reload_db_args reload_db_args = { + .engine = engine, + .dboptions = dboptions, + .opts = opts, + }; pthread_mutex_lock(&reload_mutex); reload = 0; - time(&reloaded_time); + pthread_create(&reload_th, NULL, reload_db, &reload_db_args); pthread_mutex_unlock(&reload_mutex); + } else { + if(reload_engine != NULL) { #if defined(FANOTIFY) || defined(CLAMAUTH) - if(optget(opts, "ScanOnAccess")->enabled && tharg) { - tharg->engine = engine; - pthread_create(&fan_pid, &fan_attr, fan_th, tharg); - } + pthread_mutex_unlock(&reload_mutex); + if(optget(opts, "ScanOnAccess")->enabled && tharg) { + logg("Restarting on-access scan\n"); + pthread_kill(fan_pid, SIGUSR1); + pthread_join(fan_pid, NULL); + } + pthread_mutex_lock(&reload_mutex); #endif - time(&start_time); - } else { - pthread_mutex_unlock(&reload_mutex); + static struct cl_engine *tmp; + tmp = engine; + engine = reload_engine; + thrmgr_setactiveengine(engine); + time(&start_time); + reload_engine = NULL; + pthread_mutex_unlock(&reload_mutex); + + cl_engine_free(tmp); + +#if defined(FANOTIFY) || defined(CLAMAUTH) + if(optget(opts, "ScanOnAccess")->enabled && tharg) { + tharg->engine = engine; + pthread_create(&fan_pid, &fan_attr, fan_th, tharg); + } +#endif + } else { + pthread_mutex_unlock(&reload_mutex); + } } } diff --git a/clamd/server.h b/clamd/server.h index bc2a296..e171ea9 100644 --- a/clamd/server.h +++ b/clamd/server.h @@ -46,6 +46,13 @@ struct thrwarg { unsigned int options; }; +/* reload_db arguments */ +struct reload_db_args { + struct cl_engine *engine; + unsigned int dboptions; + const struct optstruct *opts; +}; + int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsigned int dboptions, const struct optstruct *opts); void sighandler(int sig); void sighandler_th(int sig); -- 1.9.0-zedat _______________________________________________ http://lurker.clamav.net/list/clamav-devel.html Please submit your patches to our Bugzilla: http://bugs.clamav.net
