src/xcalls/x_rename.c

Go to the documentation of this file.
00001 
00007 #include <fcntl.h>
00008 #include <unistd.h>
00009 #include <errno.h>
00010 #include <string.h>
00011 #include <stdlib.h>
00012 #include <misc/debug.h>
00013 #include <misc/errno.h>
00014 #include <core/tx.h>
00015 #include <core/config.h>
00016 #include <core/koa.h>
00017 #include <core/buffer.h>
00018 #include <core/txdesc.h>
00019 #include <core/stats.h>
00020 #include <libc/syscalls.h>
00021 #include <xcalls/xcalls.h>
00022 
00023 
00024 typedef struct x_rename_commit_undo_args_s x_rename_commit_undo_args_t;
00025 
00026 struct x_rename_commit_undo_args_s {
00027         txc_koa_t *oldpath_koa;
00028         txc_koa_t *newpath_koa;
00029         int       newpath_koa_is_valid;
00030         char      oldpath[TXC_MAX_LEN_PATHNAME];
00031         char      newpath[TXC_MAX_LEN_PATHNAME];
00032         char      temppath[TXC_MAX_LEN_PATHNAME];
00033 };
00034 
00035 
00036 static
00037 void
00038 x_rename_commit(void *args, int *result)
00039 {
00040         int                         local_errno = 0; 
00041         x_rename_commit_undo_args_t *myargs = (x_rename_commit_undo_args_t *) args;
00042         txc_koamgr_t                *koamgr;
00043 
00044         koamgr = txc_koa_get_koamgr(myargs->oldpath_koa);
00045         txc_koa_lock_alias_cache(koamgr);
00046         txc_koa_lock_fds_refby_koa(myargs->oldpath_koa);
00047         if (myargs->newpath_koa_is_valid) {
00048                 txc_koa_lock_fds_refby_koa(myargs->newpath_koa);
00049         }       
00050         txc_koa_detach(myargs->oldpath_koa);
00051         if (myargs->newpath_koa_is_valid) {
00052                 txc_koa_detach(myargs->newpath_koa);
00053         }
00054         if (txc_libc_unlink(myargs->oldpath) < 0) {
00055                 local_errno = errno;
00056         }       
00057         if (myargs->newpath_koa_is_valid) {
00058                 txc_koa_unlock_fds_refby_koa(myargs->newpath_koa);
00059         }       
00060         txc_koa_unlock_fds_refby_koa(myargs->oldpath_koa);
00061         txc_koa_unlock_alias_cache(koamgr);
00062         if (result) {
00063                 *result = local_errno;
00064         }
00065 }
00066 
00067 
00068 static
00069 void
00070 x_rename_undo(void *args, int *result)
00071 {
00072         int                         local_errno = 0; 
00073         x_rename_commit_undo_args_t *myargs = (x_rename_commit_undo_args_t *) args;
00074         txc_koamgr_t                *koamgr;
00075 
00076         koamgr = txc_koa_get_koamgr(myargs->oldpath_koa);
00077         txc_koa_lock_alias_cache(koamgr);
00078         txc_koa_lock_fds_refby_koa(myargs->oldpath_koa);
00079         if (myargs->newpath_koa_is_valid) {
00080                 txc_koa_lock_fds_refby_koa(myargs->newpath_koa);
00081         }       
00082         txc_koa_detach(myargs->oldpath_koa);
00083         if (myargs->newpath_koa_is_valid) {
00084                 txc_koa_detach(myargs->newpath_koa);
00085         }
00086         if (txc_libc_unlink(myargs->newpath) < 0) {
00087                 local_errno = errno;
00088         }       
00089         if (myargs->newpath_koa_is_valid) {
00090                 if (txc_libc_rename(myargs->temppath, myargs->newpath) < 0) {
00091                         local_errno = errno;
00092                 }       
00093         }
00094         if (myargs->newpath_koa_is_valid) {
00095                 txc_koa_unlock_fds_refby_koa(myargs->newpath_koa);
00096         }       
00097         txc_koa_unlock_fds_refby_koa(myargs->oldpath_koa);
00098         txc_koa_unlock_alias_cache(koamgr);
00099         if (result) {
00100                 *result = local_errno;
00101         }
00102 }
00103 
00104 
00105 
00123 int
00124 XCALL_DEF(x_rename)(const char *oldpath, const char *newpath, int *result) 
00125 {
00126         txc_tx_t                    *txd;
00127         txc_koamgr_t                *koamgr = txc_g_koamgr;
00128         txc_koa_t                   *oldpath_koa;
00129         txc_koa_t                   *newpath_koa;
00130         txc_sentinel_t              *sentinel;
00131         txc_result_t                xret;
00132         int                         ret;
00133         int                         newpath_koa_is_valid = 0;
00134         ino_t                       oldpath_inode;
00135         ino_t                       newpath_inode;
00136         char                        temppath[128]; 
00137         x_rename_commit_undo_args_t *args_commit_undo; 
00138         int                         local_result = 0;
00139 
00140         txd = txc_tx_get_txd();
00141 
00142         switch(txc_tx_get_xactstate(txd)) {
00143                 case TXC_XACTSTATE_TRANSACTIONAL_RETRYABLE:
00144                         txc_koa_lock_alias_cache(koamgr);
00145 
00146                         txc_koa_path2inode(oldpath, &oldpath_inode);
00147                         if (oldpath_inode == 0) {
00148                                 txc_koa_unlock_alias_cache(koamgr);
00149                                 local_result = ENOENT;
00150                                 ret = -1;
00151                                 goto done;
00152                         }
00153 
00154                         /* Get the sentinel on the oldpath */
00155                         if (txc_koa_alias_cache_lookup_inode(koamgr, oldpath_inode, &oldpath_koa) 
00156                             == TXC_R_SUCCESS) 
00157                         {
00158                                 txc_koa_lock_fds_refby_koa(oldpath_koa);
00159                                 txc_koa_attach(oldpath_koa);
00160                                 sentinel = txc_koa_get_sentinel(oldpath_koa);
00161                                 xret = txc_sentinel_tryacquire(txd, sentinel, 
00162                                                                TXC_SENTINEL_ACQUIREONRETRY);
00163                                 if (xret == TXC_R_BUSYSENTINEL) {
00164                                         txc_koa_detach(oldpath_koa);
00165                                         txc_koa_unlock_fds_refby_koa(oldpath_koa);
00166                                         txc_koa_unlock_alias_cache(koamgr);
00167                                         txc_tx_abort_transaction(txd, TXC_ABORTREASON_BUSYSENTINEL);
00168                                         TXC_INTERNALERROR("Never gets here. Transaction abort failed.\n");
00169                                 }
00170                                 txc_koa_unlock_fds_refby_koa(oldpath_koa);
00171                         } else {
00172                                 /* No KOA for oldpath; create it */
00173                                 txc_koa_create(koamgr, &oldpath_koa, TXC_KOA_IS_FILE, (void *) oldpath_inode);
00174                                 txc_koa_attach(oldpath_koa);
00175                                 sentinel = txc_koa_get_sentinel(oldpath_koa);
00176                                 xret = txc_sentinel_tryacquire(txd, sentinel, 0);
00177                                 if (xret != TXC_R_SUCCESS) {
00178                                         TXC_INTERNALERROR("Cannot acquire the sentinel of the KOA I've just created!\n");
00179                                 }
00180                         }
00181 
00182                         /* Get the sentinel on the newpath */
00183                         txc_koa_path2inode(newpath, &newpath_inode);
00184                         if (newpath_inode == 0) {
00185                                 /* 
00186                                  * Newpath does not exist so we don't need to acquire a sentinel
00187                                  * on it. When we do the rename of the oldpath to the newpath 
00188                                  * the sentinel we already got on oldpath will also protect the 
00189                                  * newpath because we acquire sentinels on inodes and inodes don't
00190                                  * change on rename operations.
00191                                  */
00192                         } else {
00193                                 if (txc_koa_alias_cache_lookup_inode(koamgr, newpath_inode, &newpath_koa) 
00194                                     == TXC_R_SUCCESS) 
00195                                 {
00196                                         txc_koa_lock_fds_refby_koa(newpath_koa);
00197                                         txc_koa_attach(newpath_koa);
00198                                         sentinel = txc_koa_get_sentinel(newpath_koa);
00199                                         xret = txc_sentinel_tryacquire(txd, sentinel, 0);
00200                                         if (xret == TXC_R_BUSYSENTINEL) {
00201                                                 txc_koa_detach(newpath_koa);
00202                                                 txc_koa_unlock_fds_refby_koa(newpath_koa);
00203                                                 txc_koa_unlock_alias_cache(koamgr);
00204                                                 txc_tx_abort_transaction(txd, TXC_ABORTREASON_BUSYSENTINEL);
00205                                                 TXC_INTERNALERROR("Never gets here. Transaction abort failed.\n");
00206                                         } else {
00207                                                 txc_koa_unlock_fds_refby_koa(newpath_koa);
00208                                         }
00209                                 } else {
00210                                         /* No KOA for newpath; create it */
00211                                         txc_koa_create(koamgr, &newpath_koa, TXC_KOA_IS_FILE, (void *) newpath_inode);
00212                                         txc_koa_attach(newpath_koa);
00213                                         sentinel = txc_koa_get_sentinel(newpath_koa);
00214                                         xret = txc_sentinel_tryacquire(txd, sentinel, 0);
00215                                         if (xret != TXC_R_SUCCESS) {
00216                                                 TXC_INTERNALERROR("Cannot acquire the sentinel of the KOA I've just created!\n");
00217                                         }
00218                                 }
00219                                 /* 
00220                                  * Rename the newpath to a temp name to be able to restore it
00221                                  * in case of abort
00222                                  */
00223                                 strcpy(temppath, "/tmp/libtxc.tmp.XXXXXX");
00224                                 mktemp(temppath); 
00225                                 txc_libc_rename(newpath, temppath);
00226                                 newpath_koa_is_valid = 1;
00227                         }
00228                         /* OK. We have isolation. Now, proceed with the renaming */
00229 
00230                         /* 
00231                          * We need to keep oldpath pointing to the file's inode so that 
00232                          * sentinel conflict detection can work properly. So we don't use 
00233                          * the rename syscall, but rather we create a new hard link named
00234                          * newpath. Later on commit we drop the oldpath link to complete
00235                          * the rename.
00236                          */
00237                         txc_libc_link(oldpath, newpath);
00238 
00239                         args_commit_undo = (x_rename_commit_undo_args_t *)
00240                                            txc_buffer_linear_malloc(txd->buffer_linear, 
00241                                                                     sizeof(x_rename_commit_undo_args_t));
00242                         if (args_commit_undo == NULL) {
00243                                 TXC_INTERNALERROR("Allocation failed. Linear buffer out of space.\n");
00244                         }
00245 
00246                         strcpy(args_commit_undo->temppath, temppath);
00247                         strcpy(args_commit_undo->newpath, newpath);
00248                         strcpy(args_commit_undo->oldpath, oldpath);
00249                         args_commit_undo->newpath_koa = newpath_koa;
00250                         args_commit_undo->oldpath_koa = oldpath_koa;
00251                         args_commit_undo->newpath_koa_is_valid = newpath_koa_is_valid;
00252 
00253                         txc_tx_register_commit_action(txd, x_rename_commit, 
00254                                                       (void *) args_commit_undo, result,
00255                                                       TXC_KOA_CREATE_COMMIT_ACTION_ORDER);
00256                         txc_tx_register_undo_action  (txd, x_rename_undo, 
00257                                                       (void *) args_commit_undo, result,
00258                                                       TXC_KOA_CREATE_UNDO_ACTION_ORDER);
00259 
00260                         txc_koa_unlock_alias_cache(koamgr);
00261                         ret = 0;
00262                         txc_stats_txstat_increment(txd, XCALL, x_rename, 1);
00263                         break;
00264                 case TXC_XACTSTATE_TRANSACTIONAL_IRREVOCABLE:
00265                 case TXC_XACTSTATE_NONTRANSACTIONAL:
00266                         if ((ret = txc_libc_rename(oldpath, newpath)) < 0) { 
00267                                 local_result = errno;
00268                         }
00269                         ret = 0;
00270         }       
00271 done:
00272         if (result) {
00273                 *result = local_result;
00274         }
00275         return ret;
00276 }

Generated on Wed Dec 9 20:32:39 2009 for xCalls by  doxygen 1.4.7