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 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 }