Hi, * Julius Plenz <pl...@cis.fu-berlin.de> [2014-04-07 20:43]: > > 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.
We have been running ClamAV on all incoming mail for the past week while periodically reloading a fresh definition database, and it works very well. Any chance of getting this included into upstream? Current patch against Git tag clamav-0.98.1 pasted below. Cheers, Julius -- clamd/server-th.c | 145 ++++++++++++++++++++++++++++++++---------------------- clamd/server.h | 7 +++ 2 files changed, 94 insertions(+), 58 deletions(-) diff --git a/clamd/server-th.c b/clamd/server-th.c index 86a3a48..3df5c9c 100644 --- a/clamd/server-th.c +++ b/clamd/server-th.c @@ -64,6 +64,8 @@ int progexit = 0; pthread_mutex_t exit_mutex = PTHREAD_MUTEX_INITIALIZER; int reload = 0; +volatile int reload_in_progress = 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 +160,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; - - *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; - } - } - - /* release old structure */ - if(engine) { + const char *dbdir; + int retval; + unsigned int sigs = 0; + struct cl_settings *settings = NULL; + struct cl_engine *engine = 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; + + 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 +190,12 @@ 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; + goto err; } if(!(engine = cl_engine_new())) { logg("!Can't initialize antivirus engine\n"); - *ret = 1; - if(settings) - cl_engine_settings_free(settings); - return NULL; + goto err; } if(settings) { @@ -222,25 +205,38 @@ static struct cl_engine *reload_db(struct cl_engine *engine, unsigned int dbopti logg("^Using default engine settings\n"); } cl_engine_settings_free(settings); + settings = NULL; } 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; + goto err; } 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; + goto err; } logg("Database correctly reloaded (%u signatures)\n", sigs); - thrmgr_setactiveengine(engine); - return engine; + pthread_mutex_lock(&reload_mutex); + time(&reloaded_time); + reload_engine = engine; + goto end; + +err: + if(settings) + cl_engine_settings_free(settings); + if(engine) + cl_engine_free(engine); + + pthread_mutex_lock(&reload_mutex); + +end: + reload_in_progress = 0; + pthread_mutex_unlock(&reload_mutex); + + free(args); } /* @@ -713,6 +709,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 +1344,19 @@ 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); + } + else 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); } @@ -1358,34 +1364,57 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi /* DB reload */ pthread_mutex_lock(&reload_mutex); - if(reload) { + if(reload && reload_in_progress) { + logg("Database reload already in progress; ignoring reload request.\n"); + reload = 0; + pthread_mutex_unlock(&reload_mutex); + } else if(reload) { pthread_mutex_unlock(&reload_mutex); + struct reload_db_args *reload_db_args; + reload_db_args = (struct reload_db_args *) malloc(sizeof(struct reload_db_args)); + if (reload_db_args) + { + reload_db_args->engine = engine; + reload_db_args->dboptions = dboptions; + reload_db_args->opts = opts; + + pthread_mutex_lock(&reload_mutex); + reload = 0; + reload_in_progress = 1; + + if (pthread_create(&reload_th, NULL, reload_db, reload_db_args) != 0) { + logg("*Error dispatching DB reload thread!\n"); + reload_in_progress = 0; + free(reload_db_args); + } + pthread_mutex_unlock(&reload_mutex); + } + } else if(reload_engine != NULL) { #if defined(FANOTIFY) || defined(CLAMAUTH) + 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); } -#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; - } - pthread_mutex_lock(&reload_mutex); - reload = 0; - time(&reloaded_time); +#endif + 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 - time(&start_time); } 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