nfs-ganesha 1.4

cache_inode_misc.c

Go to the documentation of this file.
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 }