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
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
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
00183 txc_koa_path2inode(newpath, &newpath_inode);
00184 if (newpath_inode == 0) {
00185
00186
00187
00188
00189
00190
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
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
00221
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
00229
00230
00231
00232
00233
00234
00235
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 }