nfs-ganesha 1.4

cache_inode_link.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 
00080 cache_inode_status_t cache_inode_link(cache_entry_t *entry,
00081                                       cache_entry_t *dest_dir,
00082                                       fsal_name_t *name,
00083                                       fsal_attrib_list_t *attr,
00084                                       fsal_op_context_t *context,
00085                                       cache_inode_status_t *status)
00086 {
00087      fsal_status_t fsal_status = {0, 0};
00088      bool_t srcattrlock = FALSE;
00089      bool_t destattrlock = FALSE;
00090      bool_t destdirlock = FALSE;
00091      fsal_accessflags_t access_mask = 0;
00092 #ifdef _USE_NFS4_ACL
00093      fsal_acl_t *saved_acl = NULL;
00094      fsal_acl_status_t acl_status = 0;
00095 #endif /* _USE_NFS4_ACL */
00096 
00097 
00098      /* Set the return default to CACHE_INODE_SUCCESS */
00099      *status = CACHE_INODE_SUCCESS;
00100 
00101      /* The file to be hardlinked can't be a DIRECTORY */
00102      if (entry->type == DIRECTORY) {
00103           *status = CACHE_INODE_BAD_TYPE;
00104           goto out;
00105      }
00106 
00107 
00108      /* Is the destination a directory? */
00109      if ((dest_dir->type != DIRECTORY) &&
00110          (dest_dir->type != FS_JUNCTION)) {
00111           *status = CACHE_INODE_BAD_TYPE;
00112           goto out;
00113      }
00114 
00115      /* Acquire the attribute lock */
00116      pthread_rwlock_wrlock(&dest_dir->attr_lock);
00117      destattrlock = TRUE;
00118 
00119      /* Check if caller is allowed to perform the operation */
00120      access_mask = (FSAL_MODE_MASK_SET(FSAL_W_OK) |
00121                     FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_FILE));
00122 
00123      if ((*status = cache_inode_access_sw(dest_dir,
00124                                           access_mask,
00125                                           context,
00126                                           status,
00127                                           FALSE))
00128          != CACHE_INODE_SUCCESS) {
00129           goto out;
00130      }
00131 
00132      /* Rather than performing a lookup first, just try to make the
00133         link and return the FSAL's error if it fails. */
00134 
00135      pthread_rwlock_wrlock(&entry->attr_lock);
00136      srcattrlock = TRUE;
00137 
00138      if ((entry->type == UNASSIGNED) ||
00139          (entry->type == RECYCLED)) {
00140           LogCrit(COMPONENT_CACHE_INODE,
00141                   "Invalid source type: type=%d, line %d in file %s",
00142                   entry->type, __LINE__, __FILE__);
00143           goto out;
00144      }
00145 
00146      /* Acquire the directory entry lock */
00147      pthread_rwlock_wrlock(&dest_dir->content_lock);
00148      destdirlock = TRUE;
00149 
00150      /* Do the link at FSAL level */
00151 #ifdef _USE_NFS4_ACL
00152      saved_acl = entry->attributes.acl;
00153 #endif /* _USE_NFS4_ACL */
00154      fsal_status =
00155           FSAL_link(&entry->handle, &dest_dir->handle,
00156                     name, context, &entry->attributes);
00157      if (FSAL_IS_ERROR(fsal_status)) {
00158           *status = cache_inode_error_convert(fsal_status);
00159           if (fsal_status.major == ERR_FSAL_STALE) {
00160                fsal_attrib_list_t attrs;
00161                attrs.asked_attributes = cache_inode_params.attrmask;
00162                fsal_status = FSAL_getattrs(&entry->handle,
00163                                            context,
00164                                            &attrs);
00165                if (fsal_status.major == ERR_FSAL_STALE) {
00166                     cache_inode_kill_entry(entry);
00167                }
00168                attrs.asked_attributes = cache_inode_params.attrmask;
00169                fsal_status = FSAL_getattrs(&dest_dir->handle,
00170                                            context,
00171                                            &attrs);
00172                if (fsal_status.major == ERR_FSAL_STALE) {
00173                     cache_inode_kill_entry(dest_dir);
00174                }
00175           }
00176           goto out;
00177      } else {
00178 #ifdef _USE_NFS4_ACL
00179           /* Decrement refcount on saved ACL */
00180          nfs4_acl_release_entry(saved_acl, &acl_status);
00181          if (acl_status != NFS_V4_ACL_SUCCESS) {
00182               LogCrit(COMPONENT_CACHE_INODE,
00183                       "Failed to release old acl, status=%d",
00184                       acl_status);
00185          }
00186 #endif /* _USE_NFS4_ACL */
00187      }
00188 
00189      cache_inode_fixup_md(entry);
00190      *attr = entry->attributes;
00191      pthread_rwlock_unlock(&entry->attr_lock);
00192      srcattrlock = FALSE;
00193 
00194      /* Reload the destination directory's attributes so the caller
00195         will have an updated changeid. */
00196      cache_inode_refresh_attrs(dest_dir, context);
00197      pthread_rwlock_unlock(&dest_dir->attr_lock);
00198      destattrlock = FALSE;
00199 
00200      /* Add the new entry in the destination directory */
00201      if (cache_inode_add_cached_dirent(dest_dir,
00202                                        name,
00203                                        entry,
00204                                        NULL,
00205                                        status) != CACHE_INODE_SUCCESS) {
00206           goto out;
00207      }
00208 
00209      pthread_rwlock_unlock(&dest_dir->content_lock);
00210      destdirlock = FALSE;
00211 
00212 out:
00213 
00214      if (srcattrlock) {
00215           pthread_rwlock_unlock(&entry->attr_lock);
00216      }
00217 
00218      if (destattrlock) {
00219           pthread_rwlock_unlock(&dest_dir->attr_lock);
00220      }
00221 
00222      if (destdirlock) {
00223           pthread_rwlock_unlock(&dest_dir->content_lock);
00224      }
00225 
00226      return *status;
00227 }