nfs-ganesha 1.4

cache_inode_get.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 
00037 #ifdef HAVE_CONFIG_H
00038 #include "config.h"
00039 #endif
00040 
00041 #ifdef _SOLARIS
00042 #include "solaris_port.h"
00043 #endif                          /* _SOLARIS */
00044 
00045 #include "LRU_List.h"
00046 #include "log.h"
00047 #include "HashData.h"
00048 #include "HashTable.h"
00049 #include "fsal.h"
00050 #include "cache_inode.h"
00051 #include "cache_inode_lru.h"
00052 
00053 #include <unistd.h>
00054 #include <sys/types.h>
00055 #include <sys/param.h>
00056 #include <time.h>
00057 #include <pthread.h>
00058 #include <assert.h>
00059 
00083 cache_entry_t *
00084 cache_inode_get(cache_inode_fsal_data_t *fsdata,
00085                 fsal_attrib_list_t *attr,
00086                 fsal_op_context_t *context,
00087                 cache_entry_t *associated,
00088                 cache_inode_status_t *status)
00089 {
00090      hash_buffer_t key, value;
00091      cache_entry_t *entry = NULL;
00092      fsal_status_t fsal_status = {0, 0};
00093      cache_inode_create_arg_t create_arg = {
00094           .newly_created_dir = FALSE
00095      };
00096      cache_inode_file_type_t type = UNASSIGNED;
00097      hash_error_t hrc = 0;
00098      fsal_attrib_list_t fsal_attributes;
00099      fsal_handle_t *file_handle;
00100      struct hash_latch latch;
00101 
00102      /* Set the return default to CACHE_INODE_SUCCESS */
00103      *status = CACHE_INODE_SUCCESS;
00104 
00105      /* Turn the input to a hash key on our own.
00106       */
00107      key.pdata = fsdata->fh_desc.start;
00108      key.len = fsdata->fh_desc.len;
00109 
00110      hrc = HashTable_GetLatch(fh_to_cache_entry_ht, &key, &value,
00111                               FALSE,
00112                               &latch);
00113 
00114      if ((hrc != HASHTABLE_SUCCESS) &&
00115          (hrc != HASHTABLE_ERROR_NO_SUCH_KEY)) {
00116           /* This should not happened */
00117           *status = CACHE_INODE_HASH_TABLE_ERROR;
00118           LogCrit(COMPONENT_CACHE_INODE,
00119                   "Hash access failed with code %d"
00120                   " - this should not have happened",
00121                   hrc);
00122           return NULL;
00123      }
00124 
00125      if (hrc == HASHTABLE_SUCCESS) {
00126           /* Entry exists in the cache and was found */
00127           entry = value.pdata;
00128           /* take an extra reference within the critical section */
00129           if (cache_inode_lru_ref(entry, LRU_REQ_INITIAL) !=
00130               CACHE_INODE_SUCCESS) {
00131                /* Dead entry.  Treat like a lookup failure. */
00132                entry = NULL;
00133           } else {
00134                if (entry == associated) {
00135                     /* Take a quick exit so we don't invert lock
00136                        ordering. */
00137                     HashTable_ReleaseLatched(fh_to_cache_entry_ht, &latch);
00138                     return entry;
00139                }
00140           }
00141      }
00142      HashTable_ReleaseLatched(fh_to_cache_entry_ht, &latch);
00143 
00144      if (!context) {
00145           /* Upcalls have no access to fsal_op_context_t,
00146              so just return the entry without revalidating it or
00147              creating a new one. */
00148           if (entry == NULL) {
00149                *status = CACHE_INODE_NOT_FOUND;
00150           }
00151           return entry;
00152      }
00153 
00154      if (!entry) {
00155           /* Cache miss, allocate a new entry */
00156           file_handle = (fsal_handle_t *) fsdata->fh_desc.start;
00157           /* First, call FSAL to know what the object is */
00158           fsal_attributes.asked_attributes = cache_inode_params.attrmask;
00159           fsal_status
00160                = FSAL_getattrs(file_handle, context, &fsal_attributes);
00161           if (FSAL_IS_ERROR(fsal_status)) {
00162                *status = cache_inode_error_convert(fsal_status);
00163                LogDebug(COMPONENT_CACHE_INODE,
00164                         "cache_inode_get: cache_inode_status=%u "
00165                         "fsal_status=%u,%u ", *status,
00166                         fsal_status.major,
00167                         fsal_status.minor);
00168                return NULL;
00169           }
00170 
00171           /* The type has to be set in the attributes */
00172           if (!FSAL_TEST_MASK(fsal_attributes.supported_attributes,
00173                               FSAL_ATTR_TYPE)) {
00174                *status = CACHE_INODE_FSAL_ERROR;
00175                return NULL;
00176           }
00177 
00178           /* Get the cache_inode file type */
00179           type = cache_inode_fsal_type_convert(fsal_attributes.type);
00180           if (type == SYMBOLIC_LINK) {
00181                fsal_attributes.asked_attributes = cache_inode_params.attrmask;
00182                fsal_status =
00183                     FSAL_readlink(file_handle, context,
00184                                   &create_arg.link_content,
00185                                   &fsal_attributes);
00186 
00187                if (FSAL_IS_ERROR(fsal_status)) {
00188                     *status = cache_inode_error_convert(fsal_status);
00189                     return NULL;
00190                }
00191           }
00192           if ((entry
00193                = cache_inode_new_entry(fsdata,
00194                                        &fsal_attributes,
00195                                        type,
00196                                        &create_arg,
00197                                        status)) == NULL) {
00198                return NULL;
00199           }
00200 
00201      }
00202 
00203      *status = CACHE_INODE_SUCCESS;
00204 
00205      /* This is the replacement for cache_inode_renew_entry.  Rather
00206         than calling that function at the start of every cache_inode
00207         call with the inode locked, we call cache_inode_check trust to
00208         perform 'heavyweight' (timed expiration of cached attributes,
00209         getattr-based directory trust) checks the first time after
00210         getting an inode.  It does all of the checks read-locked and
00211         only acquires a write lock if there's something requiring a
00212         change.
00213 
00214         There is a second light-weight check done before use of cached
00215         data that checks whether the bits saying that inode attributes
00216         or inode content are trustworthy have been cleared by, for
00217         example, FSAL_CB.
00218 
00219         To summarize, the current implementation is that policy-based
00220         trust of validity is checked once per logical series of
00221         operations at cache_inode_get, and asynchronous trust is
00222         checked with use (when the attributes are locked for reading,
00223         for example.) */
00224 
00225      if ((*status = cache_inode_check_trust(entry,
00226                                             context))
00227          != CACHE_INODE_SUCCESS) {
00228        goto out_put;
00229      }
00230 
00231      /* Set the returned attributes */
00232      *status = cache_inode_lock_trust_attrs(entry, context);
00233 
00234      /* cache_inode_lock_trust_attrs may fail, in that case, the
00235         attributes are wrong and pthread_rwlock_unlock can't be called
00236         again */
00237      if(*status != CACHE_INODE_SUCCESS)
00238        {
00239          goto out_put;
00240        }
00241      *attr = entry->attributes;
00242      pthread_rwlock_unlock(&entry->attr_lock);
00243 
00244      return entry;
00245 
00246  out_put:
00247      cache_inode_put(entry);
00248      entry = NULL;
00249      return entry;
00250 } /* cache_inode_get */
00251 
00269 void cache_inode_put(cache_entry_t *entry)
00270 {
00271   cache_inode_lru_unref(entry, LRU_FLAG_NONE);
00272 }