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 #define TXC_WRITE_SEQ 0x1
00025 #define TXC_WRITE_OVR_SAVE 0x2
00026 #define TXC_WRITE_OVR_IGNORE 0x3
00027
00028 typedef struct x_write_undo_args_s x_write_undo_args_t;
00029
00030 struct x_write_undo_args_s {
00031 int fd;
00032 void *buf;
00033 int nbyte_new;
00034 int nbyte_old;
00035 };
00036
00037
00038 static
00039 void
00040 x_write_seq_undo(void *args, int *result)
00041 {
00042 x_write_undo_args_t *args_undo = (x_write_undo_args_t *) args;
00043 off_t offset;
00044 int local_result = 0;
00045
00046 if ((offset = txc_libc_lseek(args_undo->fd,
00047 -(args_undo->nbyte_new), SEEK_CUR)) < 0)
00048 {
00049 local_result = errno;
00050 goto done;
00051 }
00052 if (txc_libc_ftruncate(args_undo->fd, offset) < 0) {
00053 local_result = errno;
00054 }
00055 done:
00056 if (result) {
00057 *result = local_result;
00058 }
00059 }
00060
00061
00062 static
00063 void
00064 x_write_ovr_undo(void *args, int *result)
00065 {
00066 x_write_undo_args_t *args_undo = (x_write_undo_args_t *) args;
00067 off_t offset;
00068 int local_result = 0;
00069
00070 if ((offset = txc_libc_lseek(args_undo->fd,
00071 -(args_undo->nbyte_new), SEEK_CUR)) < 0)
00072 {
00073 local_result = errno;
00074 goto done;
00075 }
00076 if (args_undo->buf) {
00077 if (args_undo->nbyte_old < args_undo->nbyte_new) {
00078
00079
00080
00081
00082
00083
00084
00085
00086 if (txc_libc_ftruncate(args_undo->fd, offset) < 0) {
00087 local_result = errno;
00088 goto done;
00089 }
00090 }
00091 if (txc_libc_pwrite(args_undo->fd, args_undo->buf,
00092 args_undo->nbyte_old, offset) < 0)
00093 {
00094 local_result = errno;
00095 }
00096 }
00097 done:
00098 if (result) {
00099 *result = local_result;
00100 }
00101 }
00102
00103
00104 static
00105 ssize_t
00106 x_write(int fd, const void *buf, size_t nbyte, int *result, int flags)
00107 {
00108 txc_tx_t *txd;
00109 txc_koamgr_t *koamgr = txc_g_koamgr;
00110 txc_koa_t *koa;
00111 txc_sentinel_t *sentinel;
00112 txc_result_t xret;
00113 int ret;
00114 void *old_data;
00115 x_write_undo_args_t *args_write_undo;
00116 int local_result;
00117
00118
00119 txd = txc_tx_get_txd();
00120
00121 switch(txc_tx_get_xactstate(txd)) {
00122 case TXC_XACTSTATE_TRANSACTIONAL_IRREVOCABLE:
00123 case TXC_XACTSTATE_NONTRANSACTIONAL:
00124 if ((ret = txc_libc_write(fd, buf, nbyte)) < 0) {
00125 local_result = errno;
00126 } else {
00127 local_result = 0;
00128 }
00129 goto done;
00130
00131 case TXC_XACTSTATE_TRANSACTIONAL_RETRYABLE:
00132 txc_koa_lock_fd(koamgr, fd);
00133 xret = txc_koa_lookup_fd2koa(koamgr, fd, &koa);
00134 if (xret == TXC_R_FAILURE) {
00135
00136
00137
00138
00139 txc_koa_unlock_fd(koamgr, fd);
00140 local_result = EBADF;
00141 ret = -1;
00142 goto done;
00143 }
00144 sentinel = txc_koa_get_sentinel(koa);
00145 xret = txc_sentinel_tryacquire(txd, sentinel,
00146 TXC_SENTINEL_ACQUIREONRETRY);
00147 txc_koa_unlock_fd(koamgr, fd);
00148 if (xret == TXC_R_BUSYSENTINEL) {
00149 txc_tx_abort_transaction(txd, TXC_ABORTREASON_BUSYSENTINEL);
00150 TXC_INTERNALERROR("Never gets here. Transaction abort failed.\n");
00151 }
00152
00153
00154 switch (flags) {
00155 case TXC_WRITE_SEQ:
00156 if ((args_write_undo = (x_write_undo_args_t *)
00157 txc_buffer_linear_malloc(txd->buffer_linear,
00158 sizeof(x_write_undo_args_t)))
00159 == NULL)
00160 {
00161 local_result = ENOMEM;
00162 ret = -1;
00163 goto error_handler_write_seq_0;
00164 }
00165 args_write_undo->fd = fd;
00166 if ((ret = txc_libc_write(fd, buf, nbyte)) < 0) {
00167 local_result = errno;
00168 goto error_handler_write_seq_1;
00169 }
00170 args_write_undo->nbyte_new = ret;
00171 txc_tx_register_undo_action(txd, x_write_seq_undo,
00172 (void *) args_write_undo, result,
00173 TXC_TX_REGULAR_UNDO_ACTION_ORDER);
00174 local_result = 0;
00175 ret = args_write_undo->nbyte_new;
00176 txc_stats_txstat_increment(txd, XCALL, x_write_seq, 1);
00177 goto done;
00178
00179 case TXC_WRITE_OVR_IGNORE:
00180 case TXC_WRITE_OVR_SAVE:
00181 if ((args_write_undo = (x_write_undo_args_t *)
00182 txc_buffer_linear_malloc(txd->buffer_linear,
00183 sizeof(x_write_undo_args_t)))
00184 == NULL)
00185 {
00186 local_result = ENOMEM;
00187 ret = -1;
00188 goto error_handler_write_ovr_0;
00189 }
00190 if (flags == TXC_WRITE_OVR_SAVE) {
00191 if ((old_data = (void *) txc_buffer_linear_malloc(txd->buffer_linear,
00192 sizeof(char) * nbyte))
00193 == NULL)
00194 {
00195 local_result = ENOMEM;
00196 ret = -1;
00197 goto error_handler_write_ovr_1;
00198 }
00199 if ((ret = txc_libc_read(fd, old_data, nbyte)) < 0) {
00200 local_result = errno;
00201 goto error_handler_write_ovr_2;
00202 }
00203 args_write_undo->nbyte_old = ret;
00204 } else {
00205 args_write_undo->nbyte_old = 0;
00206 old_data = NULL;
00207 }
00208 args_write_undo->buf = old_data;
00209 args_write_undo->fd = fd;
00210 if (args_write_undo->nbyte_old > 0) {
00211 txc_libc_lseek(fd, -args_write_undo->nbyte_old, SEEK_CUR);
00212 }
00213 if ((ret = txc_libc_write(fd, buf, nbyte)) < 0) {
00214 local_result = errno;
00215 goto error_handler_write_ovr_2;
00216 }
00217 args_write_undo->nbyte_new = ret;
00218 txc_tx_register_undo_action(txd, x_write_ovr_undo,
00219 (void *) args_write_undo, result,
00220 TXC_TX_REGULAR_UNDO_ACTION_ORDER);
00221 local_result = 0;
00222 ret = args_write_undo->nbyte_new;
00223 if (flags == TXC_WRITE_OVR_SAVE) {
00224 txc_stats_txstat_increment(txd, XCALL, x_write_ovr, 1);
00225 } else {
00226 txc_stats_txstat_increment(txd, XCALL, x_write_ovr_ignore, 1);
00227 }
00228 goto done;
00229
00230 default:
00231 TXC_INTERNALERROR("Unknown x_write type\n");
00232 }
00233
00234 default:
00235 TXC_INTERNALERROR("Unknown transaction state\n");
00236 }
00237
00238 error_handler_write_ovr_2:
00239 if (old_data) {
00240 txc_buffer_linear_free(txd->buffer_linear,
00241 sizeof(char) *nbyte);
00242 }
00243
00244 error_handler_write_seq_1:
00245 error_handler_write_ovr_1:
00246 txc_buffer_linear_free(txd->buffer_linear,
00247 sizeof(x_write_undo_args_t));
00248
00249 error_handler_write_seq_0:
00250 error_handler_write_ovr_0:
00251 done:
00252 if (result) {
00253 *result = local_result;
00254 }
00255 return ret;
00256 }
00257
00258
00273 ssize_t
00274 XCALL_DEF(x_write_seq)(int fd, const void *buf, size_t nbyte, int *result)
00275 {
00276 return x_write(fd, buf, nbyte, result, TXC_WRITE_SEQ);
00277 }
00278
00279
00294 ssize_t
00295 XCALL_DEF(x_write_ovr_ignore)(int fd, const void *buf, size_t nbyte, int *result)
00296 {
00297 return x_write(fd, buf, nbyte, result, TXC_WRITE_OVR_IGNORE);
00298 }
00299
00300
00304 ssize_t
00305 XCALL_DEF(x_write_ovr_save)(int fd, const void *buf, size_t nbyte, int *result)
00306 {
00307 return x_write(fd, buf, nbyte, result, TXC_WRITE_OVR_SAVE);
00308 }
00309
00310
00325 ssize_t
00326 XCALL_DEF(x_write_ovr)(int fd, const void *buf, size_t nbyte, int *result)
00327 {
00328 return x_write(fd, buf, nbyte, result, TXC_WRITE_OVR_SAVE);
00329 }