nfs-ganesha 1.4
|
00001 00010 /* 00011 * vim:expandtab:shiftwidth=8:tabstop=8: 00012 */ 00013 #ifdef HAVE_CONFIG_H 00014 #include "config.h" 00015 #endif 00016 00017 #ifdef _SOLARIS 00018 #include "solaris_port.h" 00019 #endif /* _SOLARIS */ 00020 00021 #include "log.h" 00022 #include "HashData.h" 00023 #include "HashTable.h" 00024 #include "fsal.h" 00025 #include "cache_inode.h" 00026 #include "cache_inode_lru.h" 00027 #include "cache_inode_weakref.h" 00028 00029 #include <unistd.h> 00030 #include <sys/types.h> 00031 #include <sys/param.h> 00032 #include <time.h> 00033 #include <pthread.h> 00034 #include <assert.h> 00035 00050 cache_inode_status_t 00051 cache_inode_is_dir_empty(cache_entry_t *entry) 00052 { 00053 cache_inode_status_t status; 00054 00055 /* Sanity check */ 00056 if(entry->type != DIRECTORY) { 00057 return CACHE_INODE_BAD_TYPE; 00058 } 00059 00060 status = (entry->object.dir.nbactive == 0) ? 00061 CACHE_INODE_SUCCESS : 00062 CACHE_INODE_DIR_NOT_EMPTY; 00063 00064 return status; 00065 } /* cache_inode_is_dir_empty */ 00066 00083 cache_inode_status_t 00084 cache_inode_is_dir_empty_WithLock(cache_entry_t *entry) 00085 { 00086 cache_inode_status_t status; 00087 00088 pthread_rwlock_rdlock(&entry->content_lock); 00089 status = cache_inode_is_dir_empty(entry); 00090 pthread_rwlock_unlock(&entry->content_lock); 00091 00092 return status; 00093 } /* cache_inode_is_dir_empty_WithLock */ 00094 00105 cache_inode_status_t 00106 cache_inode_clean_internal(cache_entry_t *entry) 00107 { 00108 hash_buffer_t key, val; 00109 hash_error_t rc = 0; 00110 00111 if (entry->fh_desc.start == 0) 00112 return CACHE_INODE_SUCCESS; 00113 00114 key.pdata = entry->fh_desc.start; 00115 key.len = entry->fh_desc.len; 00116 00117 00118 val.pdata = entry; 00119 val.len = sizeof(cache_entry_t); 00120 00121 rc = HashTable_DelSafe(fh_to_cache_entry_ht, 00122 &key, 00123 &val); 00124 00125 /* Nonexistence is as good as success. */ 00126 if ((rc != HASHTABLE_SUCCESS) && 00127 (rc != HASHTABLE_ERROR_NO_SUCH_KEY)) { 00128 /* XXX this seems to logically prevent relcaiming the HashTable LRU 00129 * reference, and it seems to indicate a very serious problem */ 00130 LogCrit(COMPONENT_CACHE_INODE, 00131 "HashTable_Del error %d in cache_inode_clean_internal", rc); 00132 return CACHE_INODE_INCONSISTENT_ENTRY; 00133 } 00134 00135 /* Delete from the weakref table */ 00136 cache_inode_weakref_delete(&entry->weakref); 00137 00138 if (entry->type == SYMBOLIC_LINK) { 00139 pthread_rwlock_wrlock(&entry->content_lock); 00140 cache_inode_release_symlink(entry); 00141 pthread_rwlock_unlock(&entry->content_lock); 00142 } 00143 00144 return CACHE_INODE_SUCCESS; 00145 } /* cache_inode_clean_internal */ 00146 00163 cache_inode_status_t 00164 cache_inode_remove(cache_entry_t *entry, 00165 fsal_name_t *name, 00166 fsal_attrib_list_t *attr, 00167 fsal_op_context_t *context, 00168 cache_inode_status_t *status) 00169 { 00170 cache_inode_status_t cache_status; 00171 fsal_accessflags_t access_mask = 0; 00172 00173 /* Get the attribute lock and check access */ 00174 pthread_rwlock_wrlock(&entry->attr_lock); 00175 00176 /* Check if caller is allowed to perform the operation */ 00177 access_mask = (FSAL_MODE_MASK_SET(FSAL_W_OK) | 00178 FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_DELETE_CHILD)); 00179 00180 if((*status 00181 = cache_inode_access_sw(entry, 00182 access_mask, 00183 context, 00184 &cache_status, 00185 FALSE)) 00186 != CACHE_INODE_SUCCESS) { 00187 goto unlock_attr; 00188 } 00189 00190 /* Acquire the directory lock and remove the entry */ 00191 00192 pthread_rwlock_wrlock(&entry->content_lock); 00193 00194 cache_inode_remove_impl(entry, 00195 name, 00196 context, 00197 status, 00198 /* Keep the attribute lock so we can copy 00199 attributes back to the caller. I plan 00200 to get rid of this later. --ACE */ 00201 CACHE_INODE_FLAG_ATTR_HAVE | 00202 CACHE_INODE_FLAG_ATTR_HOLD | 00203 CACHE_INODE_FLAG_CONTENT_HAVE); 00204 00205 *attr = entry->attributes; 00206 00207 unlock_attr: 00208 00209 pthread_rwlock_unlock(&entry->attr_lock); 00210 00211 return *status; 00212 } /* cache_inode_remove */ 00213 00230 cache_inode_status_t 00231 cache_inode_remove_impl(cache_entry_t *entry, 00232 fsal_name_t *name, 00233 fsal_op_context_t *context, 00234 cache_inode_status_t *status, 00235 uint32_t flags) 00236 { 00237 cache_entry_t *to_remove_entry = NULL; 00238 fsal_status_t fsal_status = {0, 0}; 00239 #ifdef _USE_NFS4_ACL 00240 fsal_acl_t *saved_acl = NULL; 00241 fsal_acl_status_t acl_status = 0; 00242 #endif /* _USE_NFS4_ACL */ 00243 00244 if(entry->type != DIRECTORY) { 00245 *status = CACHE_INODE_BAD_TYPE; 00246 goto out; 00247 } 00248 00249 if (!(flags & CACHE_INODE_FLAG_CONTENT_HAVE)) { 00250 pthread_rwlock_rdlock(&entry->content_lock); 00251 flags |= CACHE_INODE_FLAG_CONTENT_HAVE; 00252 } 00253 00254 /* Factor this somewhat. In the case where the directory hasn't 00255 been populated, the entry may not exist in the cache and we'd 00256 be bringing it in just to dispose of it. */ 00257 00258 /* Looks up for the entry to remove */ 00259 if ((to_remove_entry 00260 = cache_inode_lookup_impl(entry, 00261 name, 00262 context, 00263 status)) == NULL) { 00264 goto out; 00265 } 00266 00267 /* Lock the attributes (so we can decrement the link count) */ 00268 pthread_rwlock_wrlock(&to_remove_entry->attr_lock); 00269 00270 LogDebug(COMPONENT_CACHE_INODE, 00271 "---> Cache_inode_remove : %s", name->name); 00272 00273 00274 #ifdef _USE_NFS4_ACL 00275 saved_acl = entry->attributes.acl; 00276 #endif /* _USE_NFS4_ACL */ 00277 fsal_status = FSAL_unlink(&entry->handle, 00278 name, 00279 context, 00280 &entry->attributes); 00281 00282 if (FSAL_IS_ERROR(fsal_status)) { 00283 *status = cache_inode_error_convert(fsal_status); 00284 if (fsal_status.major == ERR_FSAL_STALE) { 00285 cache_inode_kill_entry(entry); 00286 } 00287 goto unlock; 00288 } else { 00289 #ifdef _USE_NFS4_ACL 00290 /* Decrement refcount on saved ACL */ 00291 nfs4_acl_release_entry(saved_acl, &acl_status); 00292 if (acl_status != NFS_V4_ACL_SUCCESS) { 00293 LogCrit(COMPONENT_CACHE_INODE, 00294 "Failed to release old acl, status=%d", 00295 acl_status); 00296 } 00297 #endif /* _USE_NFS4_ACL */ 00298 } 00299 cache_inode_fixup_md(entry); 00300 00301 if ((flags & CACHE_INODE_FLAG_ATTR_HAVE) && 00302 !(flags & CACHE_INODE_FLAG_ATTR_HOLD)) { 00303 pthread_rwlock_unlock(&entry->attr_lock); 00304 } 00305 00306 /* Remove the entry from parent dir_entries avl */ 00307 cache_inode_remove_cached_dirent(entry, name, status); 00308 00309 LogFullDebug(COMPONENT_CACHE_INODE, 00310 "cache_inode_remove_cached_dirent: status=%d", *status); 00311 00312 /* Update the attributes for the removed entry */ 00313 00314 if ((to_remove_entry->type != DIRECTORY) && 00315 (to_remove_entry->attributes.numlinks > 1)) { 00316 if ((*status = cache_inode_refresh_attrs(to_remove_entry, 00317 context)) 00318 != CACHE_INODE_SUCCESS) { 00319 goto unlock; 00320 } 00321 } else { 00322 /* Otherwise our count is zero, or it was an empty 00323 directory. */ 00324 to_remove_entry->attributes.numlinks = 0; 00325 } 00326 00327 /* Now, delete "to_remove_entry" from the cache inode and free 00328 its associated resources, but only if numlinks == 0 */ 00329 if (to_remove_entry->attributes.numlinks == 0) { 00330 /* Destroy the entry when everyone's references to it have 00331 been relinquished. Most likely now. */ 00332 pthread_rwlock_unlock(&to_remove_entry->attr_lock); 00333 /* Kill off the sentinel reference (and mark the entry so 00334 it doesn't get recycled while a reference exists.) */ 00335 cache_inode_lru_kill(to_remove_entry); 00336 } else { 00337 unlock: 00338 00339 pthread_rwlock_unlock(&to_remove_entry->attr_lock); 00340 } 00341 00342 out: 00343 if ((flags & CACHE_INODE_FLAG_CONTENT_HAVE) && 00344 !(flags & CACHE_INODE_FLAG_CONTENT_HOLD)) { 00345 pthread_rwlock_unlock(&entry->content_lock); 00346 } 00347 00348 /* This is for the reference taken by lookup */ 00349 if (to_remove_entry) 00350 { 00351 cache_inode_put(to_remove_entry); 00352 } 00353 00354 return *status; 00355 }