nfs-ganesha 1.4
|
00001 #ifdef HAVE_CONFIG_H 00002 #include "config.h" 00003 #endif 00004 00005 #include "posixdb_internal.h" 00006 #include "posixdb_consistency.h" 00007 #include <string.h> 00008 #include "RW_Lock.h" 00009 00010 /* cyclic cache of paths */ 00011 00012 typedef struct cache_path_entry__ 00013 { 00014 int is_set; 00015 int path_is_set; 00016 int info_is_set; 00017 posixfsal_handle_t handle; 00018 fsal_path_t path; 00019 rw_lock_t entry_lock; 00020 00021 } cache_path_entry_t; 00022 00023 #define CACHE_PATH_SIZE 509 /* prime near 512 */ 00024 00025 int fsal_posixdb_cache_init() 00026 { 00027 #ifdef _ENABLE_CACHE_PATH 00028 unsigned int i; 00029 00030 memset((char *)cache_array, 0, CACHE_PATH_SIZE * sizeof(cache_path_entry_t)); 00031 00032 for(i = 0; i < CACHE_PATH_SIZE; i++) 00033 { 00034 if(rw_lock_init(&cache_array[i].entry_lock)) 00035 return -1; 00036 00037 cache_array[i].is_set = 0; 00038 cache_array[i].path_is_set = 0; 00039 cache_array[i].info_is_set = 0; 00040 } 00041 00042 #endif 00043 return 0; 00044 } 00045 00046 /* @todo pour augmenter les performances d'acces au cache, 00047 * on hash le handle, et on considere qu'un seul element 00048 * ayant un hash donne peut occuper une case du tableau. 00049 */ 00050 00051 void fsal_posixdb_CachePath(posixfsal_handle_t * p_handle, /* IN */ 00052 fsal_path_t * p_path /* IN */ ) 00053 { 00054 00055 #ifdef _ENABLE_CACHE_PATH 00056 00057 unsigned int i; 00058 00059 LogDebug(COMPONENT_FSAL, "fsal_posixdb_CachePath: %u, %u = %s", (unsigned int)(p_handle->id), 00060 (unsigned int)(p_handle->ts), p_path->path); 00061 00062 i = hash_cache_path(p_handle->id, p_handle->ts); 00063 00064 /* in the handle already in cache ? */ 00065 P_w(&cache_array[i].entry_lock); 00066 00067 if(cache_array[i].is_set 00068 && cache_array[i].handle.id == p_handle->id 00069 && cache_array[i].handle.ts == p_handle->ts) 00070 { 00071 cache_array[i].path_is_set = TRUE; 00072 00073 /* override it */ 00074 cache_array[i].path = *p_path; 00075 00076 V_w(&cache_array[i].entry_lock); 00077 return; 00078 } 00079 00080 /* add it (replace previous handle) */ 00081 cache_array[i].is_set = TRUE; 00082 cache_array[i].path_is_set = TRUE; 00083 cache_array[i].info_is_set = FALSE; 00084 cache_array[i].handle = *p_handle; 00085 cache_array[i].path = *p_path; 00086 V_w(&cache_array[i].entry_lock); 00087 00088 #endif 00089 return; 00090 } 00091 00092 /* set/update informations about a handle */ 00093 int fsal_posixdb_UpdateInodeCache(posixfsal_handle_t * p_handle) /* IN */ 00094 { 00095 #ifdef _ENABLE_CACHE_PATH 00096 00097 unsigned int i; 00098 00099 LogDebug(COMPONENT_FSAL, "UpdateInodeCache: inode_id=%llu", p_handle->info.inode); 00100 00101 i = hash_cache_path(p_handle->id, p_handle->ts); 00102 00103 /* in the handle in cache ? */ 00104 P_w(&cache_array[i].entry_lock); 00105 00106 if(cache_array[i].is_set 00107 && cache_array[i].handle.id == p_handle->id 00108 && cache_array[i].handle.ts == p_handle->ts) 00109 { 00110 /* update its inode info */ 00111 cache_array[i].handle.info = p_handle->info; 00112 cache_array[i].info_is_set = TRUE; 00113 00114 LogDebug(COMPONENT_FSAL, "fsal_posixdb_UpdateInodeCache: %u, %u (existing entry)", 00115 (unsigned int)(p_handle->id), (unsigned int)(p_handle->ts)); 00116 00117 V_w(&cache_array[i].entry_lock); 00118 00119 return TRUE; 00120 } 00121 LogDebug(COMPONENT_FSAL, "fsal_posixdb_UpdateInodeCache: %u, %u (new entry)", 00122 (unsigned int)(p_handle->id), (unsigned int)(p_handle->ts)); 00123 00124 /* add it (replace previous handle) */ 00125 cache_array[i].is_set = TRUE; 00126 cache_array[i].path_is_set = FALSE; 00127 cache_array[i].info_is_set = TRUE; 00128 cache_array[i].handle = *p_handle; 00129 memset(&cache_array[i].path, 0, sizeof(fsal_path_t)); 00130 00131 V_w(&cache_array[i].entry_lock); 00132 #endif 00133 return FALSE; 00134 00135 } 00136 00137 /* retrieve last informations about a handle */ 00138 int fsal_posixdb_GetInodeCache(posixfsal_handle_t * p_handle) /* IN/OUT */ 00139 { 00140 #ifdef _ENABLE_CACHE_PATH 00141 unsigned int i; 00142 00143 i = hash_cache_path(p_handle->id, p_handle->ts); 00144 00145 /* in the handle in cache ? */ 00146 P_r(&cache_array[i].entry_lock); 00147 if(cache_array[i].is_set 00148 && cache_array[i].handle.id == p_handle->id 00149 && cache_array[i].handle.ts == p_handle->ts) 00150 { 00151 if(cache_array[i].info_is_set) 00152 { 00153 p_handle->info = cache_array[i].handle.info; 00154 00155 LogDebug(COMPONENT_FSAL, "fsal_posixdb_GetInodeCache(%u, %u)", (unsigned int)(p_handle->id), 00156 (unsigned int)(p_handle->ts)); 00157 V_r(&cache_array[i].entry_lock); 00158 00159 return TRUE; 00160 } 00161 } 00162 V_r(&cache_array[i].entry_lock); 00163 #endif 00164 return FALSE; 00165 00166 } 00167 00168 void fsal_posixdb_InvalidateCache() 00169 { 00170 #ifdef _ENABLE_CACHE_PATH 00171 unsigned int i; 00172 00173 LogDebug(COMPONENT_FSAL, "fsal_posixdb_InvalidateCache"); 00174 00175 for(i = 0; i < CACHE_PATH_SIZE; i++) 00176 { 00177 P_w(&cache_array[i].entry_lock); 00178 cache_array[i].is_set = FALSE; 00179 cache_array[i].path_is_set = FALSE; 00180 cache_array[i].info_is_set = FALSE; 00181 cache_array[i].handle.id = 0; 00182 cache_array[i].handle.ts = 0; 00183 V_w(&cache_array[i].entry_lock); 00184 } 00185 00186 #endif 00187 } 00188 00189 int fsal_posixdb_GetPathCache(posixfsal_handle_t * p_handle, /* IN */ 00190 fsal_path_t * p_path /* OUT */ ) 00191 { 00192 #ifdef _ENABLE_CACHE_PATH 00193 00194 unsigned int i; 00195 00196 i = hash_cache_path(p_handle->id, p_handle->ts); 00197 00198 /* in the handle in cache ? */ 00199 P_r(&cache_array[i].entry_lock); 00200 if(cache_array[i].is_set 00201 && cache_array[i].handle.id == p_handle->id 00202 && cache_array[i].handle.ts == p_handle->ts) 00203 { 00204 if(cache_array[i].path_is_set) 00205 { 00206 /* return path it */ 00207 memcpy(p_path, &cache_array[i].path, sizeof(fsal_path_t)); 00208 V_r(&cache_array[i].entry_lock); 00209 00210 LogDebug(COMPONENT_FSAL, "fsal_posixdb_GetPathCache(%u, %u)=%s", 00211 (unsigned int)p_handle->id, (unsigned int)p_handle->ts, 00212 p_path->path); 00213 return TRUE; 00214 } 00215 } 00216 V_r(&cache_array[i].entry_lock); 00217 #endif 00218 return FALSE; 00219 } 00220 00221 fsal_posixdb_status_t fsal_posixdb_buildOnePath(fsal_posixdb_conn * p_conn, 00222 posixfsal_handle_t * p_handle, 00223 fsal_path_t * p_path) 00224 { 00225 PGresult *p_res; 00226 char handleid_str[MAX_HANDLEIDSTR_SIZE]; 00227 char handlets_str[MAX_HANDLETSSTR_SIZE]; 00228 unsigned int shift; 00229 char *new_pos; 00230 int toomanypaths = 0; 00231 const char *paramValues[2] = { handleid_str, handlets_str }; 00232 00233 if(!p_conn || !p_handle || !p_path) 00234 { 00235 ReturnCodeDB(ERR_FSAL_POSIXDB_FAULT, 0); 00236 } 00237 00238 /* init values */ 00239 memset(p_path, 0, sizeof(fsal_path_t)); 00240 00241 /* Nothing to do, it's the root path */ 00242 if(p_handle->data.id == 0 && p_handle->data.ts == 0) 00243 ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0); 00244 00245 /* check if the entry is in the cache */ 00246 if(fsal_posixdb_GetPathCache(p_handle, p_path)) 00247 ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0); 00248 00249 snprintf(handleid_str, MAX_HANDLEIDSTR_SIZE, "%lli", p_handle->data.id); 00250 snprintf(handlets_str, MAX_HANDLETSSTR_SIZE, "%i", p_handle->data.ts); 00251 00252 /* with PL/PGSQL */ 00253 #ifdef _WITH_PLPGSQL 00254 p_res = PQexecPrepared(p_conn, "buildOnePathPL", 2, paramValues, NULL, NULL, 0); 00255 CheckResult(p_res); 00256 00257 p_path->len = strlen(PQgetvalue(p_res, 0, 0)); 00258 00259 if(p_path->len >= FSAL_MAX_PATH_LEN) 00260 { 00261 PQclear(p_res); 00262 ReturnCodeDB(ERR_FSAL_POSIXDB_PATHTOOLONG, 0); 00263 } 00264 00265 strcpy(p_path->path, PQgetvalue(p_res, 0, 0)); 00266 PQclear(p_res); 00267 00268 /* set result in cache */ 00269 fsal_posixdb_CachePath(p_handle, p_path); 00270 00271 ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0); 00272 00273 #else 00274 /* without PL/PGSQL */ 00275 while(handleid_str[0] != '\0') 00276 { 00277 p_res = PQexecPrepared(p_conn, "buildOnePath", 2, paramValues, NULL, NULL, 0); 00278 CheckResult(p_res); 00279 00280 if(PQntuples(p_res) == 0) 00281 { 00282 PQclear(p_res); 00283 ReturnCodeDB(ERR_FSAL_POSIXDB_NOENT, 0); /* not found */ 00284 } 00285 00286 if(PQntuples(p_res) > 1) 00287 { 00288 LogCrit(COMPONENT_FSAL, "Too many paths found for object %s.%s: found=%d, expected=1", 00289 handleid_str, handlets_str, PQntuples(p_res)); 00290 00291 toomanypaths++; /* too many entries */ 00292 } 00293 00294 if(!strncmp(handleid_str, PQgetvalue(p_res, 0, 1), MAX_HANDLEIDSTR_SIZE) 00295 && !strncmp(handlets_str, PQgetvalue(p_res, 0, 2), MAX_HANDLETSSTR_SIZE)) 00296 { 00297 PQclear(p_res); 00298 break; /* handle is equal to its parent handle (root reached) */ 00299 } 00300 strncpy(handleid_str, PQgetvalue(p_res, 0, 1), MAX_HANDLEIDSTR_SIZE); 00301 strncpy(handlets_str, PQgetvalue(p_res, 0, 2), MAX_HANDLETSSTR_SIZE); 00302 00303 /* insertion of the name at the beginning of the path */ 00304 shift = strlen(PQgetvalue(p_res, 0, 0)); 00305 if(p_path->len + shift >= FSAL_MAX_PATH_LEN) 00306 { 00307 PQclear(p_res); 00308 ReturnCodeDB(ERR_FSAL_POSIXDB_PATHTOOLONG, 0); 00309 } 00310 new_pos = p_path->path + shift; 00311 memmove(new_pos, p_path->path, p_path->len); 00312 memcpy(p_path->path, PQgetvalue(p_res, 0, 0), shift); 00313 p_path->len += shift; 00314 00315 PQclear(p_res); 00316 } 00317 00318 if(toomanypaths) 00319 { 00320 LogCrit(COMPONENT_FSAL, "Returned path: %s", p_path->path); 00321 ReturnCodeDB(ERR_FSAL_POSIXDB_TOOMANYPATHS, toomanypaths); /* too many entries */ 00322 } 00323 else 00324 { 00325 /* set result in cache */ 00326 fsal_posixdb_CachePath(p_handle, p_path); 00327 00328 ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0); 00329 } 00330 #endif 00331 } 00332 00333 fsal_posixdb_status_t fsal_posixdb_recursiveDelete(fsal_posixdb_conn * p_conn, 00334 char *handleid_str, char *handlets_str, 00335 fsal_nodetype_t ftype) 00336 { 00337 PGresult *p_res; 00338 fsal_posixdb_status_t st; 00339 fsal_nodetype_t ftype_tmp; 00340 unsigned int i; 00341 unsigned int i_max; 00342 const char *paramValues[2]; 00343 00344 /* Sanity check */ 00345 if(!p_conn || !handleid_str || !handlets_str) 00346 { 00347 ReturnCodeDB(ERR_FSAL_POSIXDB_FAULT, 0); 00348 } 00349 00350 if(ftype == FSAL_TYPE_DIR) 00351 { 00352 /* We find all the children of the directory in order to delete them, and then we delete the current handle */ 00353 paramValues[0] = handleid_str; 00354 paramValues[1] = handlets_str; 00355 p_res = PQexecPrepared(p_conn, "lookupChildrenFU", 2, paramValues, NULL, NULL, 0); 00356 CheckResult(p_res); 00357 i_max = (unsigned int)PQntuples(p_res); 00358 for(i = 0; i < i_max; i++) 00359 { 00360 ftype_tmp = (fsal_nodetype_t) atoi(PQgetvalue(p_res, i, 2)); 00361 if(ftype_tmp == FSAL_TYPE_DIR) 00362 { 00363 st = fsal_posixdb_recursiveDelete(p_conn, PQgetvalue(p_res, i, 0), 00364 PQgetvalue(p_res, i, 1), ftype_tmp); 00365 } 00366 else 00367 { 00368 st = fsal_posixdb_deleteParent(p_conn, PQgetvalue(p_res, i, 0), /* handleidparent */ 00369 PQgetvalue(p_res, i, 1), /* handletsparent */ 00370 handleid_str, handlets_str, PQgetvalue(p_res, i, 3), /* filename */ 00371 atoi(PQgetvalue(p_res, i, 4)) /* nlink */ 00372 ); 00373 } 00374 if(FSAL_POSIXDB_IS_ERROR(st)) 00375 { 00376 PQclear(p_res); 00377 return st; 00378 } 00379 } 00380 PQclear(p_res); 00381 } 00382 00383 /* Delete the Handle */ 00384 /* All Parent entries having this handle will be deleted thanks to foreign keys */ 00385 paramValues[0] = handleid_str; 00386 paramValues[1] = handlets_str; 00387 00388 /* invalidate name cache */ 00389 fsal_posixdb_InvalidateCache(); 00390 00391 p_res = PQexecPrepared(p_conn, "deleteHandle", 2, paramValues, NULL, NULL, 0); 00392 CheckCommand(p_res); 00393 00394 ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0); 00395 } 00396 00397 fsal_posixdb_status_t fsal_posixdb_deleteParent(fsal_posixdb_conn * p_conn, /* IN */ 00398 char *handleid_str, /* IN */ 00399 char *handlets_str, /* IN */ 00400 char *handleidparent_str, /* IN */ 00401 char *handletsparent_str, /* IN */ 00402 char *filename, /* IN */ 00403 int nlink) /* IN */ 00404 { 00405 PGresult *p_res; 00406 char nlink_str[MAX_NLINKSTR_SIZE]; 00407 const char *paramValues[3]; 00408 00409 /* Sanity check */ 00410 if(!p_conn || !filename || nlink < 1) 00411 { 00412 ReturnCodeDB(ERR_FSAL_POSIXDB_FAULT, 0); 00413 } 00414 00415 /* delete the Parent entry */ 00416 paramValues[0] = handleidparent_str; 00417 paramValues[1] = handletsparent_str; 00418 paramValues[2] = filename; 00419 00420 /* invalidate name cache */ 00421 fsal_posixdb_InvalidateCache(); 00422 00423 p_res = PQexecPrepared(p_conn, "deleteParent", 3, paramValues, NULL, NULL, 0); 00424 CheckCommand(p_res); 00425 00426 /* delete the handle or update it */ 00427 if(nlink == 1) 00428 { 00429 /* delete the handle */ 00430 /* If there are other entries in the Parent table with this Handle, they will be deleted (thanks to foreign keys) */ 00431 paramValues[0] = handleid_str; 00432 paramValues[1] = handlets_str; 00433 00434 /* invalidate cache */ 00435 fsal_posixdb_InvalidateCache(); 00436 00437 p_res = PQexecPrepared(p_conn, "deleteHandle", 2, paramValues, NULL, NULL, 0); 00438 CheckCommand(p_res); 00439 } 00440 else 00441 { 00442 /* update the Handle entry ( Handle.nlink <- (nlink - 1) ) */ 00443 paramValues[0] = handleid_str; 00444 paramValues[1] = handlets_str; 00445 snprintf(nlink_str, MAX_NLINKSTR_SIZE, "%i", nlink - 1); 00446 paramValues[2] = nlink_str; 00447 00448 /* invalidate cache */ 00449 fsal_posixdb_InvalidateCache(); 00450 00451 p_res = PQexecPrepared(p_conn, "updateHandleNlink", 3, paramValues, NULL, NULL, 0); 00452 CheckCommand(p_res); 00453 } 00454 00455 ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0); 00456 } 00457 00458 fsal_posixdb_status_t fsal_posixdb_internal_delete(fsal_posixdb_conn * p_conn, /* IN */ 00459 char *handleidparent_str, /* IN */ 00460 char *handletsparent_str, /* IN */ 00461 char *filename, /* IN */ 00462 fsal_posixdb_fileinfo_t * 00463 p_object_info /* IN */ ) 00464 { 00465 00466 PGresult *p_res; 00467 char handleid_str[MAX_HANDLEIDSTR_SIZE]; 00468 char handlets_str[MAX_HANDLETSSTR_SIZE]; 00469 fsal_posixdb_status_t st; 00470 fsal_posixdb_fileinfo_t infodb; 00471 const char *paramValues[3]; 00472 00473 if(!p_conn || !handleidparent_str || !handletsparent_str || !filename) 00474 ReturnCodeDB(ERR_FSAL_POSIXDB_FAULT, 0); 00475 00476 paramValues[0] = handleidparent_str; 00477 paramValues[1] = handletsparent_str; 00478 paramValues[2] = filename; 00479 p_res = PQexecPrepared(p_conn, "lookupHandleByNameFU", 3, paramValues, NULL, NULL, 0); 00480 CheckResult(p_res); 00481 /* p_res contains : handleid, handlets, deviceId, inode, nlink, ctime, ftype */ 00482 00483 /* no entry found */ 00484 if(PQntuples(p_res) != 1) 00485 { 00486 ReturnCodeDB(ERR_FSAL_POSIXDB_NOENT, 0); 00487 } 00488 00489 strncpy(handleid_str, PQgetvalue(p_res, 0, 0), MAX_HANDLEIDSTR_SIZE); 00490 strncpy(handlets_str, PQgetvalue(p_res, 0, 1), MAX_HANDLETSSTR_SIZE); 00491 00492 /* consistency check */ 00493 /* fill 'infodb' with information about the handle in the database */ 00494 posixdb_internal_fillFileinfoFromStrValues(&infodb, PQgetvalue(p_res, 0, 2), /* no need to compare inode & devid, they are the same */ 00495 PQgetvalue(p_res, 0, 3), PQgetvalue(p_res, 0, 4), /* nlink */ 00496 PQgetvalue(p_res, 0, 5), /* ctime */ 00497 PQgetvalue(p_res, 0, 6) /* ftype */ 00498 ); 00499 PQclear(p_res); 00500 00501 if(p_object_info && fsal_posixdb_consistency_check(&infodb, p_object_info)) 00502 { 00503 /* not consistent, the bad handle have to be deleted */ 00504 LogCrit(COMPONENT_FSAL, "Consistency check failed while deleting a Path : Handle deleted"); 00505 infodb.ftype = FSAL_TYPE_DIR; /* considers that the entry is a directory in order to delete all its Parent entries and its Handle */ 00506 } 00507 00508 switch (infodb.ftype) 00509 { 00510 case FSAL_TYPE_DIR: 00511 /* directory */ 00512 st = fsal_posixdb_recursiveDelete(p_conn, handleid_str, handlets_str, infodb.ftype); 00513 break; 00514 default: 00515 st = fsal_posixdb_deleteParent(p_conn, 00516 handleid_str, 00517 handlets_str, 00518 handleidparent_str, 00519 handletsparent_str, filename, infodb.nlink); 00520 } 00521 return st; 00522 } 00523 00524 fsal_posixdb_status_t posixdb_internal_fillFileinfoFromStrValues(fsal_posixdb_fileinfo_t * 00525 p_info, char *devid_str, 00526 char *inode_str, 00527 char *nlink_str, 00528 char *ctime_str, 00529 char *ftype_str) 00530 { 00531 00532 if(!p_info) 00533 ReturnCodeDB(ERR_FSAL_POSIXDB_FAULT, 0); 00534 00535 p_info->devid = devid_str ? (dev_t) atoll(devid_str) : 0; 00536 p_info->inode = inode_str ? (ino_t) atoll(inode_str) : 0; 00537 p_info->nlink = nlink_str ? atoi(nlink_str) : 0; 00538 p_info->ctime = ctime_str ? (time_t) atoi(ctime_str) : 0; 00539 p_info->ftype = ftype_str ? (fsal_nodetype_t) atoi(ftype_str) : 0; 00540 00541 ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0); 00542 }