nfs-ganesha 1.4

cache_content_emergency_flush.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 
00038 #ifdef HAVE_CONFIG_H
00039 #include "config.h"
00040 #endif
00041 
00042 #ifdef _SOLARIS
00043 #include "solaris_port.h"
00044 #include <sys/statvfs.h>
00045 #endif                          /* _SOLARIS */
00046 
00047 #include "LRU_List.h"
00048 #include "log.h"
00049 #include "HashData.h"
00050 #include "HashTable.h"
00051 #include "fsal.h"
00052 #include "nfs_core.h"
00053 #include "cache_inode.h"
00054 #include "cache_content.h"
00055 
00056 #include <unistd.h>
00057 #include <sys/types.h>
00058 #include <sys/param.h>
00059 #include <time.h>
00060 #include <pthread.h>
00061 #include <errno.h>
00062 
00063 #include <sys/types.h>
00064 #include <dirent.h>
00065 #include <sys/stat.h>
00066 #include <string.h>
00067 
00068 #ifdef _LINUX
00069 #include <sys/vfs.h>            /* For statfs */
00070 #endif
00071 
00072 #ifdef _APPLE
00073 #include <sys/param.h>          /* For Statfs */
00074 #include <sys/mount.h>
00075 #endif
00076 
00077 extern unsigned int cache_content_dir_errno;
00078 
00103 cache_content_status_t cache_content_emergency_flush(char *cachedir,
00104                                                      cache_content_flush_behaviour_t
00105                                                      flushhow,
00106                                                      unsigned int lw_mark_trigger_flag,
00107                                                      time_t grace_period,
00108                                                      unsigned int index, unsigned int mod,
00109                                                      unsigned int *p_nb_flushed,
00110                                                      unsigned int *p_nb_too_young,
00111                                                      unsigned int *p_nb_errors,
00112                                                      unsigned int *p_nb_orphans,
00113                                                      fsal_op_context_t * pcontext,
00114                                                      cache_content_status_t * pstatus)
00115 {
00116   fsal_handle_t fsal_handle;
00117   fsal_status_t fsal_status;
00118   cache_content_dirinfo_t directory;
00119   struct dirent dir_entry;
00120   FILE *stream = NULL;
00121   char buff[CACHE_INODE_DUMP_LEN + 1];
00122   int inum;
00123   char indexpath[MAXPATHLEN];
00124   char datapath[MAXPATHLEN];
00125   fsal_path_t fsal_path;
00126   fsal_mdsize_t strsize = MAXPATHLEN + 1;
00127   struct stat buffstat;
00128   time_t max_acmtime = 0;
00129 #ifdef _USE_PROXY
00130   __attribute__((unused)) fsal_u64_t fileid;
00131 #endif
00132   cache_content_flush_behaviour_t local_flushhow = flushhow;
00133   unsigned int passcounter = 0;
00134 #ifdef _SOLARIS
00135   struct statvfs info_fs;
00136 #else
00137   struct statfs info_fs;
00138 #endif
00139   double tx_used;
00140 
00141   /* TODO: I'm not really sure how these work at all as I don't see an
00142      assignment later, just that these get used */
00143   double hw = 0;
00144   double lw = 0;
00145 
00146   *pstatus = CACHE_CONTENT_SUCCESS;
00147 
00148   if(cache_content_local_cache_opendir(cachedir, &directory) == FALSE)
00149     {
00150       LogCrit(COMPONENT_CACHE_CONTENT, "cache_content_emergency_flush can't open directory %s, errno=%u (%s)",
00151                  cachedir, cache_content_dir_errno, strerror(cache_content_dir_errno));
00152       *pstatus = CACHE_CONTENT_LOCAL_CACHE_ERROR;
00153       return *pstatus;
00154     }
00155 
00156   while(cache_content_local_cache_dir_iter(&directory, &dir_entry, index, mod))
00157     {
00158       if((lw_mark_trigger_flag == TRUE)
00159          && (local_flushhow == CACHE_CONTENT_FLUSH_AND_DELETE))
00160         {
00161           passcounter += 1;
00162 
00163           if(passcounter == 100)
00164             {
00165               passcounter = 0;
00166 
00167               if(statfs(cachedir, &info_fs) != 0)
00168                 {
00169                   LogCrit(COMPONENT_CACHE_CONTENT,"Error getting local filesystem info: path=%s errno=%u",
00170                              cachedir, errno);
00171                   return CACHE_CONTENT_LOCAL_CACHE_ERROR;
00172                 }
00173               /* Compute thresholds and total block count.
00174                * Those formulas are based on the df's code:
00175                * used = f_blocks - available_to_root
00176                *      = f_blocks - f_bfree
00177                * total = used + available
00178                *       = f_blocks - f_bfree + f_bavail
00179                */
00180               tx_used = 100.0 * ((double)info_fs.f_blocks - (double)info_fs.f_bfree) /
00181                   ((double)info_fs.f_blocks + (double)info_fs.f_bavail -
00182                    (double)info_fs.f_bfree);
00183 
00184               LogEvent(COMPONENT_CACHE_CONTENT,
00185                               "Datacache: %s: %.2f%% used, low_wm = %.2f%%, high_wm = %.2f%%",
00186                               cachedir, tx_used, lw, hw);
00187 
00188               if(tx_used < nfs_param.cache_layers_param.dcgcpol.lwmark_df)
00189                 {
00190                   /* No need to purge more, downgrade to sync mode */
00191                   local_flushhow = CACHE_CONTENT_FLUSH_SYNC_ONLY;
00192                   LogEvent(COMPONENT_CACHE_CONTENT,
00193                                   "Datacache: Low Water is reached, I stop purging but continue on syncing");
00194                 }
00195             }
00196         }
00197 
00198       /* Manage only index files */
00199       if(!strcmp(dir_entry.d_name + strlen(dir_entry.d_name) - 5, "index"))
00200         {
00201           if((inum = cache_content_get_inum(dir_entry.d_name)) == -1)
00202             {
00203               LogCrit(COMPONENT_CACHE_CONTENT, "Bad file name %s found in cache", dir_entry.d_name);
00204               continue;
00205             }
00206 
00207           /* read the content of the index file, for having the FSAL handle */
00208 
00209           snprintf(indexpath, MAXPATHLEN, "%s/%s", cachedir, dir_entry.d_name);
00210 
00211           if((stream = fopen(indexpath, "r")) == NULL)
00212             return CACHE_CONTENT_LOCAL_CACHE_ERROR;
00213 
00214           #define XSTR(s) STR(s)
00215           #define STR(s) #s
00216           if((fscanf(stream, "internal:read_time=%" XSTR(CACHE_INODE_DUMP_LEN) "s\n", buff) != 1) ||
00217              (fscanf(stream, "internal:mod_time=%" XSTR(CACHE_INODE_DUMP_LEN) "s\n", buff) != 1) ||
00218              (fscanf(stream, "internal:export_id=%" XSTR(CACHE_INODE_DUMP_LEN) "s\n", buff) != 1) ||
00219              (fscanf(stream, "file: FSAL handle=%" XSTR(CACHE_INODE_DUMP_LEN) "s", buff) != 1))
00220             {
00221               fclose(stream);
00222               LogCrit(COMPONENT_CACHE_CONTENT,
00223                       "Corrupted FSAL handle in index file %s", indexpath);
00224               continue;
00225             }
00226           #undef STR
00227           #undef XSTR
00228 
00229           fclose(stream);
00230           if(sscanHandle(&fsal_handle, buff) < 0)
00231             {
00232               /* expected = 2*sizeof(fsal_handle_t) in hexa representation */
00233               LogCrit(COMPONENT_CACHE_CONTENT,
00234                   "Invalid FSAL handle in index file %s: unexpected length %u (expected=%u)",
00235                    indexpath, (unsigned int)strlen(buff),
00236                    (unsigned int)(2 * sizeof(fsal_handle_t)));
00237               continue;  /* if the while test fails, stream will still be opened */
00238             }
00239 
00240           /* Now close the stream */
00241           fclose(stream);
00242           stream = NULL;
00243 
00244           cache_content_get_datapath(cachedir, inum, datapath);
00245 
00246           /* Stat the data file to now if it is eligible or not */
00247           if(stat(datapath, &buffstat) == -1)
00248             {
00249               LogCrit(COMPONENT_CACHE_CONTENT,
00250                   "Can't stat file %s errno=%u(%s), continuing with next entries...",
00251                    datapath, errno, strerror(errno));
00252               continue;
00253             }
00254 
00255           /* Get the max into atime, mtime, ctime */
00256           max_acmtime = 0;
00257 
00258           if(buffstat.st_atime > max_acmtime)
00259             max_acmtime = buffstat.st_atime;
00260           if(buffstat.st_mtime > max_acmtime)
00261             max_acmtime = buffstat.st_mtime;
00262           if(buffstat.st_ctime > max_acmtime)
00263             max_acmtime = buffstat.st_ctime;
00264 
00265           LogFullDebug(COMPONENT_CACHE_CONTENT,
00266               "date=%d max_acmtime=%d ,time( NULL ) - max_acmtime = %d, grace_period = %d",
00267                (int)time(NULL), (int)max_acmtime, (int)(time(NULL) - max_acmtime), (int)grace_period);
00268 
00269           if(time(NULL) - max_acmtime < grace_period)
00270             {
00271               /* update stats, if provided */
00272               if(p_nb_too_young != NULL)
00273                 *p_nb_too_young += 1;
00274 
00275               LogDebug(COMPONENT_CACHE_CONTENT, "File %s is too young to die, preserving it...", datapath);
00276               continue;
00277             }
00278 
00279           if(isFullDebug(COMPONENT_CACHE_CONTENT))
00280             {
00281               LogFullDebug(COMPONENT_CACHE_CONTENT, "=====> local=%s FSAL HANDLE=", datapath);
00282               print_buff(COMPONENT_CACHE_CONTENT, (char *)&fsal_handle, sizeof(fsal_handle));
00283             }
00284 
00285           fsal_status = FSAL_str2path(datapath, strsize, &fsal_path);
00286           if(!FSAL_IS_ERROR(fsal_status))
00287             {
00288               fsal_status = FSAL_rcp(&fsal_handle,
00289                                      pcontext, &fsal_path, FSAL_RCP_LOCAL_TO_FS);
00290             }
00291           if(FSAL_IS_ERROR(fsal_status))
00292             {
00293               if((fsal_status.major == ERR_FSAL_NOENT) ||
00294                  (fsal_status.major == ERR_FSAL_STALE))
00295                 {
00296                   LogDebug(COMPONENT_CACHE_CONTENT,
00297                       "Cached entry %x doesn't exist anymore in FSAL, removing....",
00298                        inum);
00299 
00300                   /* update stats, if provided */
00301                   if(p_nb_orphans != NULL)
00302                     *p_nb_orphans += 1;
00303 
00304                   /* Remove the index file from the data cache */
00305                   if(unlink(indexpath))
00306                     {
00307                       LogCrit(COMPONENT_CACHE_CONTENT,"Can't unlink flushed index %s, errno=%u(%s)", indexpath,
00308                                  errno, strerror(errno));
00309                       return CACHE_CONTENT_LOCAL_CACHE_ERROR;
00310                     }
00311 
00312                   /* Remove the data file from the data cache */
00313                   if(unlink(datapath))
00314                     {
00315                       LogCrit(COMPONENT_CACHE_CONTENT,"Can't unlink flushed index %s, errno=%u(%s)", datapath,
00316                                  errno, strerror(errno));
00317                       return CACHE_CONTENT_LOCAL_CACHE_ERROR;
00318                     }
00319                 }
00320               else
00321                 {
00322                   /* update stats, if provided */
00323                   if(p_nb_errors != NULL)
00324                     *p_nb_errors += 1;
00325 
00326                   LogCrit(COMPONENT_CACHE_CONTENT,
00327                       "Can't flush file #%x, fsal_status.major=%u fsal_status.minor=%u",
00328                        inum, fsal_status.major, fsal_status.minor);
00329                 }
00330             }
00331           else
00332             {
00333               /* success */
00334               /* update stats, if provided */
00335               if(p_nb_flushed != NULL)
00336                 *p_nb_flushed += 1;
00337 
00338               switch (local_flushhow)
00339                 {
00340                 case CACHE_CONTENT_FLUSH_AND_DELETE:
00341                   /* Remove the index file from the data cache */
00342                   if(unlink(indexpath))
00343                     {
00344                       LogCrit(COMPONENT_CACHE_CONTENT,"Can't unlink flushed index %s, errno=%u(%s)", indexpath,
00345                                  errno, strerror(errno));
00346                       return CACHE_CONTENT_LOCAL_CACHE_ERROR;
00347                     }
00348 
00349                   /* Remove the data file from the data cache */
00350                   if(unlink(datapath))
00351                     {
00352                       LogCrit(COMPONENT_CACHE_CONTENT,"Can't unlink flushed index %s, errno=%u(%s)", datapath,
00353                                  errno, strerror(errno));
00354                       return CACHE_CONTENT_LOCAL_CACHE_ERROR;
00355                     }
00356                   break;
00357 
00358                 case CACHE_CONTENT_FLUSH_SYNC_ONLY:
00359                   /* do nothing */
00360                   break;
00361                 }               /* switch */
00362             }                   /* else */
00363         }                       /* if */
00364     }                           /* while */
00365 
00366   cache_content_local_cache_closedir(&directory);
00367 
00368   if(stream != NULL)
00369     fclose(stream);
00370 
00371   return *pstatus;
00372 }                               /* cache_content_emergency_flush */