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 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 */