nfs-ganesha 1.4
|
00001 /* 00002 * Copyright CEA/DAM/DIF (2008) 00003 * contributeur : Philippe DENIEL philippe.deniel@cea.fr 00004 * Thomas LEIBOVICI thomas.leibovici@cea.fr 00005 * 00006 * 00007 * This program is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 3 of the License, or (at your option) any later version. 00011 * 00012 * This program is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00020 * 02110-1301 USA 00021 * 00022 * --------------------------------------- 00023 */ 00024 00033 #ifdef HAVE_CONFIG_H 00034 #include "config.h" 00035 #endif 00036 00037 #ifdef _SOLARIS 00038 #include "solaris_port.h" 00039 #endif /* _SOLARIS */ 00040 00041 #include "abstract_atomic.h" 00042 #include "log.h" 00043 #include "HashData.h" 00044 #include "HashTable.h" 00045 #include "fsal.h" 00046 #include "cache_inode.h" 00047 #include "cache_inode_avl.h" 00048 #include "cache_inode_lru.h" 00049 #include "cache_inode_weakref.h" 00050 #include "nfs4_acls.h" 00051 00052 #include <unistd.h> 00053 #include <sys/types.h> 00054 #include <sys/param.h> 00055 #include <time.h> 00056 #include <pthread.h> 00057 #include <string.h> 00058 #include <assert.h> 00059 00060 cache_inode_gc_policy_t cache_inode_gc_policy; 00061 cache_inode_parameter_t cache_inode_params; 00062 00063 pool_t *cache_inode_entry_pool; 00064 pool_t *cache_inode_symlink_pool; 00065 pool_t *cache_inode_dir_entry_pool; 00066 00067 const char *cache_inode_err_str(cache_inode_status_t err) 00068 { 00069 switch(err) 00070 { 00071 case CACHE_INODE_SUCCESS: 00072 return "CACHE_INODE_SUCCESS"; 00073 case CACHE_INODE_MALLOC_ERROR: 00074 return "CACHE_INODE_MALLOC_ERROR"; 00075 case CACHE_INODE_POOL_MUTEX_INIT_ERROR: 00076 return "CACHE_INODE_POOL_MUTEX_INIT_ERROR"; 00077 case CACHE_INODE_GET_NEW_LRU_ENTRY: 00078 return "CACHE_INODE_GET_NEW_LRU_ENTRY"; 00079 case CACHE_INODE_UNAPPROPRIATED_KEY: 00080 return "CACHE_INODE_UNAPPROPRIATED_KEY"; 00081 case CACHE_INODE_INIT_ENTRY_FAILED: 00082 return "CACHE_INODE_INIT_ENTRY_FAILED"; 00083 case CACHE_INODE_FSAL_ERROR: 00084 return "CACHE_INODE_FSAL_ERROR"; 00085 case CACHE_INODE_LRU_ERROR: 00086 return "CACHE_INODE_LRU_ERROR"; 00087 case CACHE_INODE_HASH_SET_ERROR: 00088 return "CACHE_INODE_HASH_SET_ERROR"; 00089 case CACHE_INODE_NOT_A_DIRECTORY: 00090 return "CACHE_INODE_NOT_A_DIRECTORY"; 00091 case CACHE_INODE_INCONSISTENT_ENTRY: 00092 return "CACHE_INODE_INCONSISTENT_ENTRY"; 00093 case CACHE_INODE_BAD_TYPE: 00094 return "CACHE_INODE_BAD_TYPE"; 00095 case CACHE_INODE_ENTRY_EXISTS: 00096 return "CACHE_INODE_ENTRY_EXISTS"; 00097 case CACHE_INODE_DIR_NOT_EMPTY: 00098 return "CACHE_INODE_DIR_NOT_EMPTY"; 00099 case CACHE_INODE_NOT_FOUND: 00100 return "CACHE_INODE_NOT_FOUND"; 00101 case CACHE_INODE_INVALID_ARGUMENT: 00102 return "CACHE_INODE_INVALID_ARGUMENT"; 00103 case CACHE_INODE_INSERT_ERROR: 00104 return "CACHE_INODE_INSERT_ERROR"; 00105 case CACHE_INODE_HASH_TABLE_ERROR: 00106 return "CACHE_INODE_HASH_TABLE_ERROR"; 00107 case CACHE_INODE_FSAL_EACCESS: 00108 return "CACHE_INODE_FSAL_EACCESS"; 00109 case CACHE_INODE_IS_A_DIRECTORY: 00110 return "CACHE_INODE_IS_A_DIRECTORY"; 00111 case CACHE_INODE_FSAL_EPERM: 00112 return "CACHE_INODE_FSAL_EPERM"; 00113 case CACHE_INODE_NO_SPACE_LEFT: 00114 return "CACHE_INODE_NO_SPACE_LEFT"; 00115 case CACHE_INODE_CACHE_CONTENT_ERROR: 00116 return "CACHE_INODE_CACHE_CONTENT_ERROR"; 00117 case CACHE_INODE_CACHE_CONTENT_EXISTS: 00118 return "CACHE_INODE_CACHE_CONTENT_EXISTS"; 00119 case CACHE_INODE_CACHE_CONTENT_EMPTY: 00120 return "CACHE_INODE_CACHE_CONTENT_EMPTY"; 00121 case CACHE_INODE_READ_ONLY_FS: 00122 return "CACHE_INODE_READ_ONLY_FS"; 00123 case CACHE_INODE_IO_ERROR: 00124 return "CACHE_INODE_IO_ERROR"; 00125 case CACHE_INODE_FSAL_ESTALE: 00126 return "CACHE_INODE_FSAL_ESTALE"; 00127 case CACHE_INODE_FSAL_ERR_SEC: 00128 return "CACHE_INODE_FSAL_ERR_SEC"; 00129 case CACHE_INODE_STATE_CONFLICT: 00130 return "CACHE_INODE_STATE_CONFLICT"; 00131 case CACHE_INODE_QUOTA_EXCEEDED: 00132 return "CACHE_INODE_QUOTA_EXCEEDED"; 00133 case CACHE_INODE_DEAD_ENTRY: 00134 return "CACHE_INODE_DEAD_ENTRY"; 00135 case CACHE_INODE_ASYNC_POST_ERROR: 00136 return "CACHE_INODE_ASYNC_POST_ERROR"; 00137 case CACHE_INODE_NOT_SUPPORTED: 00138 return "CACHE_INODE_NOT_SUPPORTED"; 00139 case CACHE_INODE_STATE_ERROR: 00140 return "CACHE_INODE_STATE_ERROR"; 00141 case CACHE_INODE_DELAY: 00142 return "CACHE_INODE_FSAL_DELAY"; 00143 case CACHE_INODE_NAME_TOO_LONG: 00144 return "CACHE_INODE_NAME_TOO_LONG"; 00145 case CACHE_INODE_BAD_COOKIE: 00146 return "CACHE_INODE_BAD_COOKIE"; 00147 case CACHE_INODE_FILE_BIG: 00148 return "CACHE_INODE_FILE_BIG"; 00149 case CACHE_INODE_KILLED: 00150 return "CACHE_INODE_KILLED"; 00151 case CACHE_INODE_FILE_OPEN: 00152 return "CACHE_INODE_FILE_OPEN"; 00153 } 00154 return "unknown"; 00155 } 00156 00171 int cache_inode_compare_key_fsal(hash_buffer_t *buff1, 00172 hash_buffer_t *buff2) 00173 { 00174 int rc; 00175 fsal_status_t fsal_status; 00176 00177 /* Test if one of the entries is NULL */ 00178 if(buff1->pdata == NULL) 00179 return (buff2->pdata == NULL) ? 0 : 1; 00180 else 00181 { 00182 if(buff2->pdata == NULL) { 00183 return -1; /* left member is the greater one */ 00184 } 00185 00186 rc = FSAL_handlecmp((fsal_handle_t *)buff1->pdata, 00187 (fsal_handle_t *)buff2->pdata, 00188 &fsal_status); 00189 if((rc != 0) || FSAL_IS_ERROR(fsal_status)) 00190 { 00191 LogDebug(COMPONENT_CACHE_INODE, "Handle cmp failed rc:%d\n", rc); 00192 return 1; /* Failure */ 00193 } 00194 return 0; /* Success */ 00195 } 00196 /* This line should never be reached */ 00197 } /* cache_inode_compare_key_fsal */ 00198 00199 00212 int cache_inode_set_time_current(fsal_time_t *time) 00213 { 00214 struct timeval t; 00215 00216 if (time == NULL) 00217 return -1; 00218 00219 if (gettimeofday(&t, NULL) != 0) 00220 return -1; 00221 00222 time->seconds = t.tv_sec; 00223 time->nseconds = 1000*t.tv_usec; 00224 00225 return 0; 00226 } /* cache_inode_set_time_current */ 00227 00228 00245 cache_entry_t * 00246 cache_inode_new_entry(cache_inode_fsal_data_t *fsdata, 00247 fsal_attrib_list_t *attr, 00248 cache_inode_file_type_t type, 00249 cache_inode_create_arg_t *create_arg, 00250 cache_inode_status_t *status) 00251 { 00252 cache_entry_t *entry = NULL; 00253 cache_entry_t *new_entry = NULL; 00254 hash_buffer_t key, value; 00255 int rc = 0; 00256 bool_t lrurefed = FALSE; 00257 bool_t weakrefed = FALSE; 00258 bool_t locksinited = FALSE; 00259 bool_t typespec = FALSE; 00260 bool_t latched = FALSE; 00261 struct hash_latch latch; 00262 hash_error_t hrc = 0; 00263 00264 assert(attr); 00265 00266 key.pdata = fsdata->fh_desc.start; 00267 key.len = fsdata->fh_desc.len; 00268 00269 /* Check if the entry doesn't already exists */ 00270 /* This is slightly ugly, since we make two tries in the event 00271 that the lru reference fails. */ 00272 hrc = HashTable_GetLatch(fh_to_cache_entry_ht, &key, &value, 00273 TRUE, &latch); 00274 if ((hrc != HASHTABLE_SUCCESS) && (hrc != HASHTABLE_ERROR_NO_SUCH_KEY)) { 00275 *status = CACHE_INODE_HASH_TABLE_ERROR; 00276 LogCrit(COMPONENT_CACHE_INODE, "Hash access failed with code %d" 00277 " - this should not have happened", hrc); 00278 goto out; 00279 } 00280 if (hrc == HASHTABLE_SUCCESS) { 00281 /* Entry is already in the cache, do not add it */ 00282 entry = value.pdata; 00283 *status = CACHE_INODE_ENTRY_EXISTS; 00284 LogDebug(COMPONENT_CACHE_INODE, 00285 "cache_inode_new_entry: Trying to add an already existing " 00286 "entry. Found entry %p type: %d, New type: %d", 00287 entry, entry->type, type); 00288 if (cache_inode_lru_ref(entry, LRU_FLAG_NONE) == 00289 CACHE_INODE_SUCCESS) { 00290 /* Release the subtree hash table mutex acquired in 00291 HashTable_GetEx */ 00292 HashTable_ReleaseLatched(fh_to_cache_entry_ht, &latch); 00293 goto out; 00294 } else { 00295 /* Entry is being deconstructed, so just replace it. */ 00296 entry = NULL; 00297 *status = CACHE_INODE_SUCCESS; 00298 } 00299 } 00300 /* We did not find the object; we need to get a new one. 00301 Let us drop the latch and reacquire before inserting it. */ 00302 00303 HashTable_ReleaseLatched(fh_to_cache_entry_ht, &latch); 00304 00305 /* Pull an entry off the LRU */ 00306 new_entry = cache_inode_lru_get(status, 0); 00307 if (new_entry == NULL) { 00308 LogCrit(COMPONENT_CACHE_INODE, 00309 "cache_inode_new_entry: cache_inode_lru_get failed"); 00310 *status = CACHE_INODE_MALLOC_ERROR; 00311 goto out; 00312 } 00313 assert(new_entry->lru.refcount > 1); 00314 /* Now we got the entry; get the latch and see if someone raced us. */ 00315 hrc = HashTable_GetLatch(fh_to_cache_entry_ht, &key, &value, 00316 TRUE, &latch); 00317 if ((hrc != HASHTABLE_SUCCESS) && (hrc != HASHTABLE_ERROR_NO_SUCH_KEY)) { 00318 *status = CACHE_INODE_HASH_TABLE_ERROR; 00319 LogCrit(COMPONENT_CACHE_INODE, "Hash access failed with code %d" 00320 " - this should not have happened", hrc); 00321 /* Release our reference and the sentinel on the entry we 00322 acquired. */ 00323 cache_inode_lru_kill(new_entry); 00324 cache_inode_lru_unref(new_entry, LRU_FLAG_NONE); 00325 goto out; 00326 } 00327 if (hrc == HASHTABLE_SUCCESS) { 00328 /* Entry is already in the cache, do not add it */ 00329 entry = value.pdata; 00330 *status = CACHE_INODE_ENTRY_EXISTS; 00331 LogDebug(COMPONENT_CACHE_INODE, 00332 "cache_inode_new_entry: Trying to add an already existing " 00333 "entry. Found entry %p type: %d, New type: %d", 00334 entry, entry->type, type); 00335 if (cache_inode_lru_ref(entry, LRU_FLAG_NONE) == 00336 CACHE_INODE_SUCCESS) { 00337 /* Release the subtree hash table mutex acquired in 00338 HashTable_GetEx */ 00339 HashTable_ReleaseLatched(fh_to_cache_entry_ht, &latch); 00340 /* Release the new entry we acquired. */ 00341 cache_inode_lru_kill(new_entry); 00342 cache_inode_lru_unref(new_entry, LRU_FLAG_NONE); 00343 goto out; 00344 } 00345 } 00346 entry = new_entry; 00347 latched = TRUE; 00348 /* This should be the sentinel, plus one to use the entry we 00349 just returned. */ 00350 lrurefed = TRUE; 00351 00352 memset(&entry->handle, 0, sizeof(entry->handle)); 00353 memcpy(&entry->handle, 00354 fsdata->fh_desc.start, 00355 fsdata->fh_desc.len); 00356 entry->fh_desc.start = (caddr_t) &entry->handle; 00357 entry->fh_desc.len = fsdata->fh_desc.len; 00358 00359 /* Enroll the object in the weakref table */ 00360 00361 entry->weakref = 00362 cache_inode_weakref_insert(entry); 00363 assert(entry->weakref.ptr != 0); /* A NULL pointer here would 00364 indicate a programming 00365 error, such as an old entry 00366 not being unenrolled from 00367 the table. */ 00368 weakrefed = TRUE; 00369 00370 /* Initialize the entry locks */ 00371 if (((rc = pthread_rwlock_init(&entry->attr_lock, NULL)) != 0) || 00372 ((rc = pthread_rwlock_init(&entry->content_lock, NULL)) != 0) || 00373 ((rc = pthread_rwlock_init(&entry->state_lock, NULL)) != 0)) { 00374 /* Recycle */ 00375 LogCrit(COMPONENT_CACHE_INODE, 00376 "cache_inode_new_entry: pthread_rwlock_init " 00377 "returned %d (%s)", rc, strerror(rc)); 00378 *status = CACHE_INODE_INIT_ENTRY_FAILED; 00379 goto out; 00380 } 00381 locksinited = TRUE; 00382 00383 /* Initialize common fields */ 00384 00385 entry->type = type; 00386 entry->flags = 0; 00387 init_glist(&entry->state_list); 00388 00389 switch (type) { 00390 case REGULAR_FILE: 00391 LogDebug(COMPONENT_CACHE_INODE, 00392 "cache_inode_new_entry: Adding a REGULAR_FILE, entry=%p", 00393 entry); 00394 00395 /* No locks, yet. */ 00396 init_glist(&entry->object.file.lock_list); 00397 #ifdef _USE_NLM 00398 init_glist(&entry->object.file.nlm_share_list); /* No associated NLM shares yet */ 00399 #endif 00400 00401 entry->object.file.open_fd.openflags = FSAL_O_CLOSED; 00402 memset(&(entry->object.file.open_fd.fd), 0, sizeof(fsal_file_t)); 00403 memset(&(entry->object.file.unstable_data), 0, 00404 sizeof(cache_inode_unstable_data_t)); 00405 memset(&(entry->object.file.share_state), 0, 00406 sizeof(cache_inode_share_t)); 00407 break; 00408 00409 case DIRECTORY: 00410 LogDebug(COMPONENT_CACHE_INODE, 00411 "cache_inode_new_entry: Adding a DIRECTORY, entry=%p", 00412 entry); 00413 00414 /* If the directory is newly created, it is empty. Because 00415 we know its content, we consider it read. */ 00416 if ((create_arg != NULL) && 00417 (create_arg->newly_created_dir)) { 00418 atomic_set_uint32_t_bits(&entry->flags, 00419 CACHE_INODE_TRUST_CONTENT | 00420 CACHE_INODE_DIR_POPULATED); 00421 } else { 00422 atomic_clear_uint32_t_bits(&entry->flags, 00423 CACHE_INODE_TRUST_CONTENT | 00424 CACHE_INODE_DIR_POPULATED); 00425 } 00426 00427 entry->object.dir.avl.collisions = 0; 00428 entry->object.dir.nbactive = 0; 00429 entry->object.dir.referral = NULL; 00430 entry->object.dir.parent.ptr = NULL; 00431 entry->object.dir.parent.gen = 0; 00432 entry->object.dir.root = FALSE; 00433 /* init avl tree */ 00434 cache_inode_avl_init(entry); 00435 break; 00436 case SYMBOLIC_LINK: 00437 LogDebug(COMPONENT_CACHE_INODE, 00438 "cache_inode_new_entry: Adding a SYMBOLIC_LINK pentry=%p ", 00439 entry); 00440 entry->object.symlink = 00441 pool_alloc(cache_inode_symlink_pool, NULL); 00442 if (entry->object.symlink == NULL) { 00443 LogDebug(COMPONENT_CACHE_INODE, 00444 "Can't allocate entry symlink from symlink pool"); 00445 00446 *status = CACHE_INODE_MALLOC_ERROR; 00447 goto out; 00448 } 00449 FSAL_pathcpy(&entry->object.symlink->content, 00450 &create_arg->link_content); 00451 break; 00452 00453 case SOCKET_FILE: 00454 case FIFO_FILE: 00455 case BLOCK_FILE: 00456 case CHARACTER_FILE: 00457 LogDebug(COMPONENT_CACHE_INODE, 00458 "cache_inode_new_entry: Adding a special file of type %d " 00459 "entry=%p", type, entry); 00460 break; 00461 00462 case FS_JUNCTION: 00463 /* I don't think this ever actually gets called */ 00464 abort(); 00465 break; 00466 00467 default: 00468 /* Should never happen */ 00469 *status = CACHE_INODE_INCONSISTENT_ENTRY; 00470 LogMajor(COMPONENT_CACHE_INODE, 00471 "cache_inode_new_entry: unknown type %u provided", 00472 type); 00473 goto out; 00474 } 00475 typespec = TRUE; 00476 00477 /* Use the supplied attributes and fix up metadata */ 00478 entry->attributes = *attr; 00479 cache_inode_fixup_md(entry); 00480 00481 /* Adding the entry in the hash table */ 00482 key.pdata = entry->fh_desc.start; 00483 key.len = entry->fh_desc.len; 00484 00485 value.pdata = entry; 00486 value.len = sizeof(cache_entry_t); 00487 00488 rc = HashTable_SetLatched(fh_to_cache_entry_ht, &key, &value, 00489 &latch, TRUE, NULL, NULL); 00490 /* HashTable_SetLatched release the latch irrespective 00491 * of success/failure. */ 00492 latched = FALSE; 00493 if ((rc != HASHTABLE_SUCCESS) && (rc != HASHTABLE_OVERWRITTEN)) { 00494 LogCrit(COMPONENT_CACHE_INODE, 00495 "cache_inode_new_entry: entry could not be added to hash, " 00496 "rc=%d", rc); 00497 *status = CACHE_INODE_HASH_SET_ERROR; 00498 goto out; 00499 } 00500 00501 LogDebug(COMPONENT_CACHE_INODE, 00502 "cache_inode_new_entry: New entry %p added", entry); 00503 *status = CACHE_INODE_SUCCESS; 00504 00505 out: 00506 if (*status != CACHE_INODE_SUCCESS) { 00507 /* Deconstruct the object */ 00508 if (typespec) { 00509 switch (type) { 00510 case SYMBOLIC_LINK: 00511 cache_inode_release_symlink(entry); 00512 break; 00513 00514 default: 00515 break; 00516 } 00517 } 00518 if (locksinited) { 00519 pthread_rwlock_destroy(&entry->attr_lock); 00520 pthread_rwlock_destroy(&entry->content_lock); 00521 pthread_rwlock_destroy(&entry->state_lock); 00522 } 00523 if (weakrefed) { 00524 cache_inode_weakref_delete(&entry->weakref); 00525 } 00526 if (latched) { 00527 HashTable_ReleaseLatched(fh_to_cache_entry_ht, &latch); 00528 } 00529 if (lrurefed && *status != CACHE_INODE_ENTRY_EXISTS) { 00530 cache_inode_lru_unref(entry, LRU_FLAG_NONE); 00531 } 00532 if (*status != CACHE_INODE_ENTRY_EXISTS) { 00533 entry = NULL; 00534 } 00535 } 00536 00537 return entry; 00538 } /* cache_inode_new_entry */ 00539 00547 void cache_inode_clean_entry(cache_entry_t *entry) 00548 { 00549 entry->type = RECYCLED; 00550 pthread_rwlock_destroy(&entry->content_lock); 00551 pthread_rwlock_destroy(&entry->state_lock); 00552 pthread_rwlock_destroy(&entry->attr_lock); 00553 } 00554 00566 cache_inode_status_t 00567 cache_inode_error_convert(fsal_status_t fsal_status) 00568 { 00569 switch (fsal_status.major) 00570 { 00571 case ERR_FSAL_NO_ERROR: 00572 return CACHE_INODE_SUCCESS; 00573 00574 case ERR_FSAL_NOENT: 00575 return CACHE_INODE_NOT_FOUND; 00576 00577 case ERR_FSAL_EXIST: 00578 return CACHE_INODE_ENTRY_EXISTS; 00579 00580 case ERR_FSAL_ACCESS: 00581 return CACHE_INODE_FSAL_EACCESS; 00582 00583 case ERR_FSAL_PERM: 00584 return CACHE_INODE_FSAL_EPERM; 00585 00586 case ERR_FSAL_NOSPC: 00587 return CACHE_INODE_NO_SPACE_LEFT; 00588 00589 case ERR_FSAL_NOTEMPTY: 00590 return CACHE_INODE_DIR_NOT_EMPTY; 00591 00592 case ERR_FSAL_ROFS: 00593 return CACHE_INODE_READ_ONLY_FS; 00594 00595 case ERR_FSAL_NOTDIR: 00596 return CACHE_INODE_NOT_A_DIRECTORY; 00597 00598 case ERR_FSAL_IO: 00599 case ERR_FSAL_NXIO: 00600 return CACHE_INODE_IO_ERROR; 00601 00602 case ERR_FSAL_STALE: 00603 case ERR_FSAL_BADHANDLE: 00604 case ERR_FSAL_FHEXPIRED: 00605 return CACHE_INODE_FSAL_ESTALE; 00606 00607 case ERR_FSAL_INVAL: 00608 case ERR_FSAL_OVERFLOW: 00609 return CACHE_INODE_INVALID_ARGUMENT; 00610 00611 case ERR_FSAL_DQUOT: 00612 return CACHE_INODE_QUOTA_EXCEEDED; 00613 00614 case ERR_FSAL_SEC: 00615 return CACHE_INODE_FSAL_ERR_SEC; 00616 00617 case ERR_FSAL_NOTSUPP: 00618 case ERR_FSAL_ATTRNOTSUPP: 00619 return CACHE_INODE_NOT_SUPPORTED; 00620 00621 case ERR_FSAL_DELAY: 00622 return CACHE_INODE_DELAY; 00623 00624 case ERR_FSAL_NAMETOOLONG: 00625 return CACHE_INODE_NAME_TOO_LONG; 00626 00627 case ERR_FSAL_NOMEM: 00628 return CACHE_INODE_MALLOC_ERROR; 00629 00630 case ERR_FSAL_BADCOOKIE: 00631 return CACHE_INODE_BAD_COOKIE; 00632 00633 case ERR_FSAL_FILE_OPEN: 00634 return CACHE_INODE_FILE_OPEN; 00635 00636 case ERR_FSAL_NOT_OPENED: 00637 LogDebug(COMPONENT_CACHE_INODE, 00638 "Conversion of ERR_FSAL_NOT_OPENED to CACHE_INODE_FSAL_ERROR"); 00639 return CACHE_INODE_FSAL_ERROR; 00640 00641 case ERR_FSAL_SYMLINK: 00642 case ERR_FSAL_ISDIR: 00643 case ERR_FSAL_BADTYPE: 00644 return CACHE_INODE_BAD_TYPE; 00645 00646 case ERR_FSAL_FBIG: 00647 return CACHE_INODE_FILE_BIG; 00648 00649 case ERR_FSAL_DEADLOCK: 00650 case ERR_FSAL_BLOCKED: 00651 case ERR_FSAL_INTERRUPT: 00652 case ERR_FSAL_FAULT: 00653 case ERR_FSAL_NOT_INIT: 00654 case ERR_FSAL_ALREADY_INIT: 00655 case ERR_FSAL_BAD_INIT: 00656 case ERR_FSAL_NO_QUOTA: 00657 case ERR_FSAL_XDEV: 00658 case ERR_FSAL_MLINK: 00659 case ERR_FSAL_TOOSMALL: 00660 case ERR_FSAL_TIMEOUT: 00661 case ERR_FSAL_SERVERFAULT: 00662 /* These errors should be handled inside Cache Inode (or should never be seen by Cache Inode) */ 00663 LogDebug(COMPONENT_CACHE_INODE, 00664 "Conversion of FSAL error %d,%d to CACHE_INODE_FSAL_ERROR", 00665 fsal_status.major, fsal_status.minor); 00666 return CACHE_INODE_FSAL_ERROR; 00667 } 00668 00669 /* We should never reach this line, this may produce a warning with certain compiler */ 00670 LogCrit(COMPONENT_CACHE_INODE, 00671 "cache_inode_error_convert: default conversion to " 00672 "CACHE_INODE_FSAL_ERROR for error %d, line %u should never be reached", 00673 fsal_status.major, __LINE__); 00674 return CACHE_INODE_FSAL_ERROR; 00675 } /* cache_inode_error_convert */ 00676 00688 cache_inode_file_type_t 00689 cache_inode_fsal_type_convert(fsal_nodetype_t type) 00690 { 00691 cache_inode_file_type_t rctype; 00692 00693 switch (type) 00694 { 00695 case FSAL_TYPE_DIR: 00696 rctype = DIRECTORY; 00697 break; 00698 00699 case FSAL_TYPE_FILE: 00700 rctype = REGULAR_FILE; 00701 break; 00702 00703 case FSAL_TYPE_LNK: 00704 rctype = SYMBOLIC_LINK; 00705 break; 00706 00707 case FSAL_TYPE_BLK: 00708 rctype = BLOCK_FILE; 00709 break; 00710 00711 case FSAL_TYPE_FIFO: 00712 rctype = FIFO_FILE; 00713 break; 00714 00715 case FSAL_TYPE_CHR: 00716 rctype = CHARACTER_FILE; 00717 break; 00718 00719 case FSAL_TYPE_SOCK: 00720 rctype = SOCKET_FILE; 00721 break; 00722 00723 case FSAL_TYPE_JUNCTION: 00724 rctype = FS_JUNCTION ; 00725 break ; 00726 00727 default: 00728 rctype = UNASSIGNED; 00729 break; 00730 } 00731 00732 return rctype; 00733 } /* cache_inode_fsal_type_convert */ 00734 00746 bool_t 00747 cache_inode_types_are_rename_compatible(cache_entry_t *src, 00748 cache_entry_t *dest) 00749 { 00750 /* TRUE is both entries are non directories or if both are 00751 directories and the second is empty */ 00752 if(src->type == DIRECTORY) 00753 { 00754 if(dest->type == DIRECTORY) 00755 { 00756 if(cache_inode_is_dir_empty(dest) == CACHE_INODE_SUCCESS) 00757 return TRUE; 00758 else 00759 return FALSE; 00760 } 00761 else 00762 return FALSE; 00763 } 00764 else 00765 { 00766 /* pentry_src is not a directory */ 00767 if(dest->type == DIRECTORY) 00768 return FALSE; 00769 else 00770 return TRUE; 00771 } 00772 } /* cache_inode_types_are_rename_compatible */ 00773 00783 void cache_inode_print_dir(cache_entry_t *entry) 00784 { 00785 struct avltree_node *dirent_node; 00786 cache_inode_dir_entry_t *dirent; 00787 int i = 0; 00788 00789 if(entry->type != DIRECTORY) 00790 { 00791 LogDebug(COMPONENT_CACHE_INODE, 00792 "This entry is not a directory"); 00793 return; 00794 } 00795 00796 dirent_node = avltree_first(&entry->object.dir.avl.t); 00797 do { 00798 dirent = avltree_container_of(dirent_node, cache_inode_dir_entry_t, 00799 node_hk); 00800 LogFullDebug(COMPONENT_CACHE_INODE, 00801 "Name = %s, DIRECTORY entry = (%p, %"PRIu64") i=%d", 00802 dirent->name.name, 00803 dirent->entry.ptr, 00804 dirent->entry.gen, 00805 i); 00806 i++; 00807 } while ((dirent_node = avltree_next(dirent_node))); 00808 00809 LogFullDebug(COMPONENT_CACHE_INODE, "------------------"); 00810 } /* cache_inode_print_dir */ 00811 00819 void cache_inode_release_symlink(cache_entry_t *entry) 00820 { 00821 assert(entry); 00822 assert(entry->type == SYMBOLIC_LINK); 00823 if (entry->object.symlink) 00824 { 00825 pool_free(cache_inode_symlink_pool, entry->object.symlink); 00826 entry->object.symlink = NULL; 00827 } 00828 } 00829 00840 void cache_inode_release_dirents(cache_entry_t *entry, 00841 cache_inode_avl_which_t which) 00842 { 00843 struct avltree_node *dirent_node = NULL; 00844 struct avltree_node *next_dirent_node = NULL; 00845 struct avltree *tree = NULL; 00846 cache_inode_dir_entry_t *dirent = NULL; 00847 00848 /* Won't see this */ 00849 if (entry->type != DIRECTORY) 00850 return; 00851 00852 switch (which) 00853 { 00854 case CACHE_INODE_AVL_NAMES: 00855 tree = &entry->object.dir.avl.t; 00856 break; 00857 00858 case CACHE_INODE_AVL_COOKIES: 00859 tree = &entry->object.dir.avl.c; 00860 break; 00861 00862 case CACHE_INODE_AVL_BOTH: 00863 cache_inode_release_dirents(entry, CACHE_INODE_AVL_NAMES); 00864 cache_inode_release_dirents(entry, CACHE_INODE_AVL_COOKIES); 00865 /* tree == NULL */ 00866 break; 00867 00868 default: 00869 /* tree == NULL */ 00870 break; 00871 } 00872 00873 if (tree) { 00874 dirent_node = avltree_first(tree); 00875 00876 while( dirent_node ) 00877 { 00878 next_dirent_node = avltree_next(dirent_node); 00879 dirent = avltree_container_of(dirent_node, 00880 cache_inode_dir_entry_t, 00881 node_hk); 00882 avltree_remove(dirent_node, tree); 00883 pool_free(cache_inode_dir_entry_pool, dirent); 00884 dirent_node = next_dirent_node; 00885 } 00886 00887 if (tree == &entry->object.dir.avl.t) { 00888 entry->object.dir.nbactive = 0; 00889 atomic_clear_uint32_t_bits(&entry->flags, 00890 (CACHE_INODE_TRUST_CONTENT | 00891 CACHE_INODE_DIR_POPULATED)); 00892 } 00893 } 00894 } 00895 00907 inline bool_t 00908 cache_inode_file_holds_state(cache_entry_t *entry) 00909 { 00910 return (entry != NULL) && 00911 ((entry->type == REGULAR_FILE && 00912 !glist_empty(&entry->object.file.lock_list)) || 00913 !glist_empty(&entry->state_list)); 00914 } /* cache_inode_file_holds_state */ 00915 00928 cache_inode_status_t 00929 cache_inode_check_trust(cache_entry_t *entry, 00930 fsal_op_context_t *context) 00931 { 00932 time_t current_time = 0; 00933 cache_inode_status_t status = CACHE_INODE_SUCCESS; 00934 time_t oldmtime = 0; 00935 fsal_status_t fsal_status = {0, 0}; 00936 00937 if ((entry->type == FS_JUNCTION) || 00938 (entry->type == UNASSIGNED) || 00939 (entry->type == RECYCLED)) { 00940 LogCrit(COMPONENT_CACHE_INODE, 00941 "cache_inode_check_attrs called on file %p of bad type %d", 00942 entry, entry->type); 00943 00944 status = CACHE_INODE_BAD_TYPE; 00945 goto out; 00946 } 00947 00948 pthread_rwlock_rdlock(&entry->attr_lock); 00949 current_time = time(NULL); 00950 00951 oldmtime = entry->attributes.mtime.seconds; 00952 00953 /* Do we need a refresh? */ 00954 if (((cache_inode_params.expire_type_attr == CACHE_INODE_EXPIRE_NEVER) || 00955 (current_time - entry->attr_time < 00956 cache_inode_params.grace_period_attr)) && 00957 (entry->flags & CACHE_INODE_TRUST_ATTRS) && 00958 !((cache_inode_params.getattr_dir_invalidation)&& 00959 (entry->type == DIRECTORY))) { 00960 goto unlock; 00961 } 00962 00963 pthread_rwlock_unlock(&entry->attr_lock); 00964 00965 /* Update the atributes */ 00966 pthread_rwlock_wrlock(&entry->attr_lock); 00967 current_time = time(NULL); 00968 00969 /* Make sure no one else has first */ 00970 if (((cache_inode_params.expire_type_attr == CACHE_INODE_EXPIRE_NEVER) || 00971 (current_time - entry->attr_time < 00972 cache_inode_params.grace_period_attr)) && 00973 (entry->flags & CACHE_INODE_TRUST_ATTRS) && 00974 !((cache_inode_params.getattr_dir_invalidation) && 00975 (entry->type == DIRECTORY))) { 00976 goto unlock; 00977 } 00978 00979 if ((status = cache_inode_refresh_attrs(entry, context)) 00980 != CACHE_INODE_SUCCESS) { 00981 goto unlock; 00982 } 00983 00984 if (entry->type == SYMBOLIC_LINK && 00985 ((cache_inode_params.expire_type_link != CACHE_INODE_EXPIRE_NEVER && 00986 ((current_time - entry->change_time >= 00987 cache_inode_params.grace_period_link))) || 00988 !(entry->flags & CACHE_INODE_TRUST_CONTENT))) { 00989 pthread_rwlock_wrlock(&entry->content_lock); 00990 pthread_rwlock_unlock(&entry->attr_lock); 00991 00992 assert(entry->object.symlink); 00993 00994 fsal_status = FSAL_readlink(&entry->handle, 00995 context, 00996 &entry->object.symlink->content, 00997 NULL); 00998 00999 if (FSAL_IS_ERROR(fsal_status)) { 01000 if (fsal_status.major == ERR_FSAL_STALE) { 01001 cache_inode_kill_entry(entry); 01002 } 01003 status = cache_inode_error_convert(fsal_status); 01004 } 01005 pthread_rwlock_unlock(&entry->content_lock); 01006 goto out; 01007 } else if ((entry->type == DIRECTORY) && 01008 (oldmtime < entry->attributes.mtime.seconds)) { 01009 pthread_rwlock_wrlock(&entry->content_lock); 01010 pthread_rwlock_unlock(&entry->attr_lock); 01011 01012 atomic_clear_uint32_t_bits(&entry->flags, CACHE_INODE_TRUST_CONTENT | 01013 CACHE_INODE_DIR_POPULATED); 01014 01015 if (cache_inode_invalidate_all_cached_dirent(entry, &status) 01016 != CACHE_INODE_SUCCESS) { 01017 LogCrit(COMPONENT_CACHE_INODE, 01018 "cache_inode_invalidate_all_cached_dirent " 01019 "returned %d (%s)", status, 01020 cache_inode_err_str(status)); 01021 } 01022 01023 pthread_rwlock_unlock(&entry->content_lock); 01024 goto out; 01025 } 01026 01027 unlock: 01028 01029 pthread_rwlock_unlock(&entry->attr_lock); 01030 01031 out: 01032 return status; 01033 }