nfs-ganesha 1.4

nfs_file_content_gc_thread.c

Go to the documentation of this file.
00001 /*
00002  * vim:expandtab:shiftwidth=8:tabstop=8:
00003  *
00004  * Copyright CEA/DAM/DIF  (2008)
00005  * contributeur : Philippe DENIEL   philippe.deniel@cea.fr
00006  *                Thomas LEIBOVICI  thomas.leibovici@cea.fr
00007  *
00008  *
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 3 of the License, or (at your option) any later version.
00013  * 
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  * 
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022  * 
00023  * ---------------------------------------
00024  */
00025 
00037 #ifdef HAVE_CONFIG_H
00038 #include "config.h"
00039 #endif
00040 
00041 #ifdef _SOLARIS
00042 #include "solaris_port.h"
00043 #endif
00044 
00045 #include <stdio.h>
00046 #include <string.h>
00047 #include <pthread.h>
00048 #include <fcntl.h>
00049 #include <sys/file.h>           /* for having FNDELAY */
00050 #include "HashData.h"
00051 #include "HashTable.h"
00052 #include "log.h"
00053 #include "ganesha_rpc.h"
00054 #include "nfs23.h"
00055 #include "nfs4.h"
00056 #include "mount.h"
00057 #include "nfs_core.h"
00058 #include "cache_inode.h"
00059 #include "nfs_exports.h"
00060 #include "nfs_creds.h"
00061 #include "nfs_proto_functions.h"
00062 #include "nfs_dupreq.h"
00063 #include "nfs_file_handle.h"
00064 #include "nfs_stat.h"
00065 #include "SemN.h"
00066 #include "nfs_tcb.h"
00067 
00068 /* Structures from another module */
00069 
00070 extern char ganesha_exec_path[MAXPATHLEN];
00071 extern char fcc_log_path[MAXPATHLEN];
00072 extern int fcc_debug_level;
00073 
00074 /* Use the same structure as the worker (but not all the fields will be used) */
00075 nfs_worker_data_t fcc_gc_data;
00076 static fsal_op_context_t fsal_context;
00077 
00078 /* Variable used for forcing flush via a signal */
00079 unsigned int force_flush_by_signal;
00080 
00081 int ___cache_content_invalidate_flushed(LRU_entry_t * plru_entry, void *addparam)
00082 {
00083   cache_content_entry_t *pentry = NULL;
00084   cache_content_client_t *pclient = NULL;
00085 
00086   pentry = (cache_content_entry_t *) plru_entry->buffdata.pdata;
00087   pclient = (cache_content_client_t *) addparam;
00088 
00089   if(pentry->local_fs_entry.sync_state != SYNC_OK)
00090     {
00091       /* Entry is not to be set invalid */
00092       return LRU_LIST_DO_NOT_SET_INVALID;
00093     }
00094 
00095   /* Release the entry */
00096   pool_free(pclient->content_pool, pentry);
00097 
00098   /* Retour de la pentry dans le pool */
00099   return LRU_LIST_SET_INVALID;
00100 }                               /* cache_content_invalidate_flushed */
00101 
00102 int file_content_gc_manage_entry(LRU_entry_t * plru_entry, void *addparam)
00103 {
00104   cache_content_entry_t *pentry = NULL;
00105   cache_content_status_t cache_content_status;
00106 
00107   pentry = (cache_content_entry_t *) plru_entry->buffdata.pdata;
00108 
00109   if(pentry->local_fs_entry.sync_state == SYNC_OK)
00110     {
00111       /* No flush needed */
00112       return TRUE;
00113     }
00114   if((cache_content_status = cache_content_flush(pentry,
00115                                                  CACHE_CONTENT_FLUSH_AND_DELETE,
00116                                                  &fcc_gc_data.cache_content_client,
00117                                                  &fsal_context,
00118                                                  &cache_content_status)) !=
00119      CACHE_CONTENT_SUCCESS)
00120     {
00121       LogCrit(COMPONENT_MAIN,
00122               "NFS FILE CONTENT GARBAGE COLLECTION : /!\\ Can't flush %s : error %d",
00123               pentry->local_fs_entry.cache_path_data, cache_content_status);
00124     }
00125 
00126   /* Continue with next entry in LRU_Apply_function */
00127   return TRUE;
00128 }                               /* file_content_gc_manage_entry */
00129 
00130 extern  nfs_tcb_t gccb;
00131 
00132 void *file_content_gc_thread(void *UnusedArg)
00133 {
00134   char command[2 * MAXPATHLEN];
00135   exportlist_t *pexport = NULL;
00136   int is_hw_reached = FALSE;
00137   int some_flush_to_do = FALSE;
00138   unsigned long nb_blocks_to_manage;
00139   char cache_sub_dir[MAXPATHLEN];
00140   cache_content_status_t cache_content_status;
00141   FILE *command_stream = NULL;
00142 
00143   char logfile_arg[MAXPATHLEN];
00144   char *loglevel_arg;
00145 
00146   SetNameFunction("file_content_gc_thread");
00147 
00148   LogEvent(COMPONENT_MAIN,
00149            "NFS FILE CONTENT GARBAGE COLLECTION : Starting GC thread");
00150 
00151   if(mark_thread_existing(&gccb) == PAUSE_EXIT)
00152     {
00153       /* Oops, that didn't last long... exit. */
00154       mark_thread_done(&gccb);
00155       LogDebug(COMPONENT_DISPATCH,
00156                "NFS FILE CONTENT GARBAGE COLLECTION Thread exiting before initialization");
00157       return NULL;
00158     }
00159 
00160   LogDebug(COMPONENT_MAIN,
00161            "NFS FILE CONTENT GARBAGE COLLECTION : my pthread id is %p",
00162            (caddr_t) pthread_self());
00163 
00164   while(1)
00165     {
00166       /* Sleep until some work is to be done */
00167       sleep(nfs_param.cache_layers_param.dcgcpol.run_interval);
00168 
00169       if(gccb.tcb_state != STATE_AWAKE)
00170         {
00171           while(1)
00172             {
00173               P(gccb.tcb_mutex);
00174               if(gccb.tcb_state == STATE_AWAKE)
00175                 {
00176                   V(gccb.tcb_mutex);
00177                   break;
00178                 }
00179               switch(thread_sm_locked(&gccb))
00180                 {
00181                   case THREAD_SM_RECHECK:
00182                     V(gccb.tcb_mutex);
00183                     continue;
00184 
00185                   case THREAD_SM_BREAK:
00186                     V(gccb.tcb_mutex);
00187                     break;
00188 
00189                   case THREAD_SM_EXIT:
00190                     V(gccb.tcb_mutex);
00191                     return NULL;
00192                 }
00193             }
00194         }
00195 
00196       LogEvent(COMPONENT_MAIN,
00197                "NFS FILE CONTENT GARBAGE COLLECTION : processing...");
00198       for(pexport = nfs_param.pexportlist; pexport != NULL; pexport = pexport->next)
00199         {
00200           if(pexport->options & EXPORT_OPTION_USE_DATACACHE)
00201             {
00202               snprintf(cache_sub_dir, MAXPATHLEN, "%s/export_id=%d",
00203                        nfs_param.cache_layers_param.cache_content_client_param.cache_dir,
00204                        0);
00205 
00206               if((cache_content_status = cache_content_check_threshold(cache_sub_dir,
00207                                                                        nfs_param.
00208                                                                        cache_layers_param.
00209                                                                        dcgcpol.lwmark_df,
00210                                                                        nfs_param.
00211                                                                        cache_layers_param.
00212                                                                        dcgcpol.hwmark_df,
00213                                                                        &is_hw_reached,
00214                                                                        &nb_blocks_to_manage))
00215                  == CACHE_CONTENT_SUCCESS)
00216                 {
00217                   if(is_hw_reached)
00218                     {
00219                       LogEvent(COMPONENT_MAIN,
00220                                "NFS FILE CONTENT GARBAGE COLLECTION : High Water Mark is  reached, %lu blocks to be removed",
00221                                nb_blocks_to_manage);
00222                       some_flush_to_do = TRUE;
00223                       break;
00224                     }
00225                   else {
00226                     LogEvent(COMPONENT_MAIN,
00227                              "NFS FILE CONTENT GARBAGE COLLECTION : High Water Mark is not reached");
00228                   }
00229 
00230                   /* Use signal management */
00231                   if(force_flush_by_signal == TRUE)
00232                     {
00233                       some_flush_to_do = TRUE;
00234                       break;
00235                     }
00236                 }
00237             }
00238         }                       /* for */
00239 
00240       if (strncmp(fcc_log_path, "/dev/null", 9) == 0)
00241         switch(LogComponents[COMPONENT_CACHE_INODE_GC].comp_log_type)
00242           {
00243           case FILELOG:
00244             strncpy(logfile_arg, LogComponents[COMPONENT_CACHE_INODE_GC].comp_log_file, MAXPATHLEN);
00245             break;
00246           case SYSLOG:
00247             strncpy(logfile_arg, "SYSLOG", MAXPATHLEN);
00248             break;
00249           case STDERRLOG:
00250             strncpy(logfile_arg, "STDERRLOG", MAXPATHLEN);
00251             break;
00252           case STDOUTLOG:
00253             strncpy(logfile_arg, "STDOUTLOG", MAXPATHLEN);
00254             break;
00255           default:
00256             LogCrit(COMPONENT_MAIN,
00257                     "Could not figure out the proper -L option for emergency cache flush thread.");
00258           }
00259       else
00260         strncpy(logfile_arg, fcc_log_path, MAXPATHLEN); /* config variable */
00261 
00262       if(fcc_debug_level != -1) /* config variable */
00263         loglevel_arg = ReturnLevelInt(fcc_debug_level);
00264       else
00265         loglevel_arg = ReturnLevelInt(ReturnLevelComponent(COMPONENT_CACHE_INODE_GC));
00266 
00267       snprintf(command, 2 * MAXPATHLEN, "%s -f %s -N %s -L %s",
00268                ganesha_exec_path, config_path, loglevel_arg, logfile_arg);
00269                
00270       if(some_flush_to_do)
00271         strncat(command, " -P 3", 2 * MAXPATHLEN);      /* Sync and erase */
00272       else
00273         strncat(command, " -S 3", 2 * MAXPATHLEN);      /* Sync Only */
00274 
00275       if((command_stream = popen(command, "r")) == NULL)
00276         LogCrit(COMPONENT_MAIN,
00277                 "NFS FILE CONTENT GARBAGE COLLECTION : /!\\ Cannot lauch command %s",
00278                 command);
00279       else
00280         LogEvent(COMPONENT_MAIN,
00281                  "NFS FILE CONTENT GARBAGE COLLECTION : I launched command %s",
00282                  command);
00283 
00284       pclose(command_stream);
00285     }
00286   tcb_remove(&gccb);
00287 }                               /* file_content_gc_thread */