nfs-ganesha 1.4

cache_inode_remove.c

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