nfs-ganesha 1.4
|
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 */