nfs-ganesha 1.4

cache_inode_rename.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 
00036 #ifdef HAVE_CONFIG_H
00037 #include "config.h"
00038 #endif
00039 
00040 #ifdef _SOLARIS
00041 #include "solaris_port.h"
00042 #endif                          /* _SOLARIS */
00043 
00044 #include "LRU_List.h"
00045 #include "log.h"
00046 #include "HashData.h"
00047 #include "HashTable.h"
00048 #include "fsal.h"
00049 #include "cache_inode.h"
00050 
00051 #include <unistd.h>
00052 #include <sys/types.h>
00053 #include <sys/param.h>
00054 #include <time.h>
00055 #include <pthread.h>
00056 #include <assert.h>
00057 
00073 cache_inode_status_t
00074 cache_inode_rename_cached_dirent(cache_entry_t *parent,
00075                                  fsal_name_t *oldname,
00076                                  fsal_name_t *newname,
00077                                  cache_inode_status_t *status)
00078 {
00079   /* Set the return default to CACHE_INODE_SUCCESS */
00080   *status = CACHE_INODE_SUCCESS;
00081 
00082   /* Sanity check */
00083   if(parent->type != DIRECTORY)
00084     {
00085       *status = CACHE_INODE_BAD_TYPE;
00086       return *status;
00087     }
00088 
00089   *status = cache_inode_operate_cached_dirent(parent,
00090                                               oldname,
00091                                               newname,
00092                                               CACHE_INODE_DIRENT_OP_RENAME);
00093 
00094   return (*status);
00095 }                               /* cache_inode_rename_cached_dirent */
00096 
00108 static inline void src_dest_lock(cache_entry_t *src,
00109                                  cache_entry_t *dest)
00110 {
00111 
00112   if(src == dest)
00113     pthread_rwlock_wrlock(&src->content_lock);
00114   else
00115     {
00116       if(src < dest)
00117         {
00118           pthread_rwlock_wrlock(&src->content_lock);
00119           pthread_rwlock_wrlock(&dest->content_lock);
00120         }
00121       else
00122         {
00123           pthread_rwlock_wrlock(&dest->content_lock);
00124           pthread_rwlock_wrlock(&src->content_lock);
00125         }
00126     }
00127 }
00128 
00140 static inline void src_dest_unlock(cache_entry_t *src,
00141                                    cache_entry_t *dest)
00142 {
00143   if(src == dest)
00144     {
00145       pthread_rwlock_unlock(&src->content_lock);
00146     }
00147   else
00148     {
00149       if(src < dest)
00150         {
00151           pthread_rwlock_unlock(&dest->content_lock);
00152           pthread_rwlock_unlock(&src->content_lock);
00153         }
00154       else
00155         {
00156           pthread_rwlock_unlock(&src->content_lock);
00157           pthread_rwlock_unlock(&dest->content_lock);
00158         }
00159     }
00160 }
00161 
00185 cache_inode_status_t cache_inode_rename(cache_entry_t *dir_src,
00186                                         fsal_name_t *oldname,
00187                                         cache_entry_t *dir_dest,
00188                                         fsal_name_t *newname,
00189                                         fsal_attrib_list_t *attr_src,
00190                                         fsal_attrib_list_t *attr_dest,
00191                                         fsal_op_context_t *context,
00192                                         cache_inode_status_t *status)
00193 {
00194   fsal_status_t fsal_status = {0, 0};
00195   cache_entry_t *lookup_src = NULL;
00196   cache_entry_t *lookup_dest = NULL;
00197 
00198   /* Set the return default to CACHE_INODE_SUCCESS */
00199   *status = CACHE_INODE_SUCCESS;
00200 
00201   /* Are we working on directories ? */
00202   if ((dir_src->type != DIRECTORY) ||
00203       (dir_dest->type != DIRECTORY))
00204     {
00205       /* Bad type .... */
00206       *status = CACHE_INODE_BAD_TYPE;
00207       goto out;
00208     }
00209 
00210   /* Must take locks on directories now,
00211    * because if another thread checks source and destination existence
00212    * in the same time, it will try to do the same checks...
00213    * and it will have the same conclusion !!!
00214    */
00215 
00216   src_dest_lock(dir_src, dir_dest);
00217 
00218   /* Check for object existence in source directory */
00219   if((lookup_src
00220       = cache_inode_lookup_impl(dir_src,
00221                                 oldname,
00222                                 context,
00223                                 status)) == NULL) {
00224     /* If FSAL FH is stale, then this was managed in cache_inode_lookup */
00225     if(*status != CACHE_INODE_FSAL_ESTALE)
00226       *status = CACHE_INODE_NOT_FOUND;
00227 
00228     src_dest_unlock(dir_src, dir_dest);
00229 
00230     LogDebug(COMPONENT_CACHE_INODE,
00231              "Rename (%p,%s)->(%p,%s) : source doesn't exist",
00232              dir_src, oldname->name,
00233              dir_dest, newname->name);
00234     goto out;
00235   }
00236 
00237   /* Check if an object with the new name exists in the destination
00238      directory */
00239   if((lookup_dest
00240       = cache_inode_lookup_impl(dir_dest,
00241                                 newname,
00242                                 context,
00243                                 status)) != NULL)
00244     {
00245       LogDebug(COMPONENT_CACHE_INODE,
00246                "Rename (%p,%s)->(%p,%s) : destination already exists",
00247                dir_src, oldname->name, dir_dest, newname->name);
00248 
00249       /* If the already existing object is a directory, source object
00250          should be a directory */
00251       if(lookup_dest->type == DIRECTORY &&
00252          lookup_src->type != DIRECTORY)
00253         {
00254           src_dest_unlock(dir_src, dir_dest);
00255           /* Return EISDIR */
00256           *status = CACHE_INODE_IS_A_DIRECTORY;
00257           goto out;
00258         }
00259 
00260       if(lookup_dest->type != DIRECTORY &&
00261          lookup_src->type == DIRECTORY)
00262         {
00263           /* Return ENOTDIR */
00264           *status = CACHE_INODE_NOT_A_DIRECTORY;
00265           src_dest_unlock(dir_src, dir_dest);
00266           goto out;
00267         }
00268 
00269       /* If caller wants to rename a file on himself, let it do it:
00270          return CACHE_INODE_SUCCESS but do nothing */
00271       if(lookup_dest == lookup_src)
00272         {
00273           /* There is in fact only one file (may be one of the
00274              arguments is a hard link to the other) */
00275 
00276           src_dest_unlock(dir_src, dir_dest);
00277           LogDebug(COMPONENT_CACHE_INODE,
00278                    "Rename (%p,%s)->(%p,%s) : rename the object on itself",
00279                    dir_src, oldname->name, dir_dest, newname->name);
00280 
00281           goto out;
00282         }
00283 
00284       /* Entry with the newname exists, if it is a non-empty
00285          directory, operation cannot be performed */
00286       if ((lookup_dest->type == DIRECTORY) &&
00287           (cache_inode_is_dir_empty(lookup_dest)
00288            != CACHE_INODE_SUCCESS))
00289         {
00290           /* The entry is a non-empty directory */
00291           *status = CACHE_INODE_DIR_NOT_EMPTY;
00292 
00293           src_dest_unlock(dir_src, dir_dest);
00294           LogDebug(COMPONENT_CACHE_INODE,
00295                    "Rename (%p,%s)->(%p,%s) : destination is a non-empty "
00296                    "directory",
00297                    dir_src, oldname->name, dir_dest, newname->name);
00298           goto out;
00299         }
00300 
00301       /* get rid of this entry by trying removing it */
00302 
00303       cache_inode_remove_impl(dir_dest,
00304                               newname,
00305                               context,
00306                               status,
00307                               CACHE_INODE_FLAG_CONTENT_HAVE |
00308                               CACHE_INODE_FLAG_CONTENT_HOLD);
00309       if (*status != CACHE_INODE_SUCCESS)
00310         {
00311           LogDebug(COMPONENT_CACHE_INODE,
00312                    "Rename : unable to remove destination");
00313 
00314           src_dest_unlock(dir_src, dir_dest);
00315           goto out;
00316         }
00317     }
00318   else
00319     {
00320       if(*status == CACHE_INODE_FSAL_ESTALE)
00321         {
00322           LogDebug(COMPONENT_CACHE_INODE,
00323                    "Rename : stale destnation");
00324 
00325           src_dest_unlock(dir_src, dir_dest);
00326           goto out;
00327         }
00328     }
00329 
00330   if(dir_src->type != DIRECTORY)
00331     {
00332       *status = CACHE_INODE_BAD_TYPE;
00333       src_dest_unlock(dir_src, dir_dest);
00334       goto out;
00335     }
00336 
00337   if(dir_dest->type != DIRECTORY)
00338     {
00339       src_dest_unlock(dir_src, dir_dest);
00340       *status = CACHE_INODE_BAD_TYPE;
00341       goto out;
00342     }
00343 
00344   /* Perform the rename operation in FSAL,
00345    * before doing anything in the cache.
00346    * Indeed, if the FSAL_rename fails unexpectly,
00347    * the cache would be inconsistent!
00348    */
00349   fsal_status = FSAL_rename(&dir_src->handle, oldname,
00350                             &dir_dest->handle, newname,
00351                             context,
00352                             &dir_src->attributes,
00353                             &dir_dest->attributes);
00354   if(FSAL_IS_ERROR(fsal_status))
00355     {
00356       *status = cache_inode_error_convert(fsal_status);
00357       if (fsal_status.major == ERR_FSAL_STALE)
00358         {
00359           fsal_attrib_list_t attrs;
00360           attrs.asked_attributes = cache_inode_params.attrmask;
00361           fsal_status = FSAL_getattrs(&dir_src->handle,
00362                                       context,
00363                                       &attrs);
00364           if (fsal_status.major == ERR_FSAL_STALE)
00365             {
00366               cache_inode_kill_entry(dir_src);
00367             }
00368           attrs.asked_attributes = cache_inode_params.attrmask;
00369           fsal_status = FSAL_getattrs(&dir_dest->handle,
00370                                       context,
00371                                       &attrs);
00372           if (fsal_status.major == ERR_FSAL_STALE)
00373             {
00374               cache_inode_kill_entry(dir_dest);
00375             }
00376         }
00377       src_dest_unlock(dir_src, dir_dest);
00378       goto out;
00379     }
00380 
00381   /* Manage the returned attributes */
00382   if(attr_src != NULL)
00383     *attr_src = dir_src->attributes;
00384 
00385   if(attr_dest != NULL)
00386     *attr_dest = dir_dest->attributes;
00387 
00388   if(dir_src == dir_dest)
00389     {
00390       /* if the rename operation is made within the same dir, then we
00391        * use an optimization: cache_inode_rename_dirent is used
00392        * instead of adding/removing dirent. This limits the use of
00393        * resource in this case */
00394 
00395       LogDebug(COMPONENT_CACHE_INODE,
00396                "Rename (%p,%s)->(%p,%s) : source and target directory are "
00397                "the same",
00398                dir_src, oldname->name, dir_dest, newname->name);
00399 
00400       cache_inode_rename_cached_dirent(dir_dest, oldname,
00401                                        newname, status);
00402 
00403       if(*status != CACHE_INODE_SUCCESS)
00404         {
00405           /* Unlock the pentry and exits */
00406           src_dest_unlock(dir_src, dir_dest);
00407           goto out;
00408         }
00409     }
00410   else
00411     {
00412       LogDebug(COMPONENT_CACHE_INODE,
00413                "Rename (%p,%s)->(%p,%s) : moving entry",
00414                dir_src, oldname->name,
00415                dir_dest, newname->name);
00416 
00417       /* Add the new entry */
00418       cache_inode_add_cached_dirent(dir_dest,
00419                                     newname,
00420                                     lookup_src,
00421                                     NULL,
00422                                     status);
00423       if(*status != CACHE_INODE_SUCCESS)
00424         {
00425           src_dest_unlock(dir_src, dir_dest);
00426           goto out;
00427         }
00428 
00429       /* Remove the old entry */
00430       if(cache_inode_remove_cached_dirent(dir_src,
00431                                           oldname,
00432                                           status)
00433          != CACHE_INODE_SUCCESS)
00434         {
00435           src_dest_unlock(dir_src, dir_dest);
00436           goto out;
00437         }
00438     }
00439 
00440   /* unlock entries */
00441   src_dest_unlock(dir_src, dir_dest);
00442 
00443 out:
00444 
00445   if (lookup_dest)
00446     {
00447       cache_inode_put(lookup_dest);
00448     }
00449   if (lookup_src)
00450     {
00451       cache_inode_put(lookup_src);
00452     }
00453 
00454   return *status;
00455 } /* cache_inode_rename */