author | Alberto Bertogli
<albertito@blitiri.com.ar> 2009-07-11 03:33:07 UTC |
committer | Alberto Bertogli
<albertito@blitiri.com.ar> 2009-07-11 03:34:13 UTC |
parent | 31cc89586bb819134113ea47a3053021f83cf9ea |
libjio/journal.c | +25 | -60 |
libjio/journal.h | +5 | -3 |
libjio/trans.c | +72 | -25 |
diff --git a/libjio/journal.c b/libjio/journal.c index 324a8f9..b823b5d 100644 --- a/libjio/journal.c +++ b/libjio/journal.c @@ -205,7 +205,7 @@ static int fsync_dir(int fd) /** Create a new transaction in the journal. Returns a pointer to an opaque * jop_t (that is freed using journal_free), or NULL if there was an error. */ -struct journal_op *journal_new(struct jtrans *ts) +struct journal_op *journal_new(struct jfs *fs, unsigned int flags) { int fd, id; ssize_t rv; @@ -221,35 +221,33 @@ struct journal_op *journal_new(struct jtrans *ts) if (name == NULL) goto error; - id = get_tid(ts->fs); + id = get_tid(fs); if (id == 0) goto error; /* open the transaction file */ - get_jtfile(ts->fs, id, name); + get_jtfile(fs, id, name); fd = open(name, O_RDWR | O_CREAT | O_TRUNC, 0600); if (fd < 0) goto error; jop->id = id; jop->fd = fd; + jop->numops = 0; jop->name = name; jop->curpos = 0; jop->csum = 0; - jop->ts = ts; - jop->fs = ts->fs; + jop->fs = fs; fiu_exit_on("jio/commit/created_tf"); /* and lock it, just in case */ plockf(fd, F_LOCKW, 0, 0); - ts->id = id; - /* save the header */ hdr.ver = 1; hdr.trans_id = id; - hdr.flags = ts->flags; + hdr.flags = flags; hdr_hton(&hdr); rv = spwrite(fd, &hdr, sizeof(hdr), 0); @@ -266,7 +264,7 @@ struct journal_op *journal_new(struct jtrans *ts) unlink_error: unlink(name); - free_tid(ts->fs, ts->id); + free_tid(fs, id); close(fd); error: @@ -276,38 +274,16 @@ error: return NULL; } -/** Saves a single joper in the journal file */ -static int save_joper(struct journal_op *jop, const struct jtrans *ts, - struct joper *op) +/** Save a single operation in the journal file */ +int journal_add_op(struct journal_op *jop, unsigned char *buf, size_t len, + off_t offset) { ssize_t rv; struct on_disk_ophdr ophdr; - /* read the current content only if the transaction is not - * marked as NOROLLBACK, and if the data is not there yet, - * which is the normal case, but for rollbacking we fill it - * ourselves */ - if (!(ts->flags & J_NOROLLBACK) && (op->pdata == NULL)) { - op->pdata = malloc(op->len); - if (op->pdata == NULL) - goto error; - - op->plen = op->len; - - rv = spread(ts->fs->fd, op->pdata, op->len, - op->offset); - if (rv < 0) - goto error; - if (rv < op->len) { - /* we are extending the file! */ - /* ftruncate(ts->fs->fd, op->offset + op->len); */ - op->plen = rv; - } - } - - /* save the operation's header */ - ophdr.len = op->len; - ophdr.offset = op->offset; + /* save the operation's header, */ + ophdr.len = len; + ophdr.offset = offset; ophdr_hton(&ophdr); rv = spwrite(jop->fd, &ophdr, sizeof(ophdr), jop->curpos); @@ -321,12 +297,14 @@ static int save_joper(struct journal_op *jop, const struct jtrans *ts, sizeof(ophdr)); /* and save it to the disk */ - rv = spwrite(jop->fd, op->buf, op->len, jop->curpos); - if (rv != op->len) + rv = spwrite(jop->fd, buf, len, jop->curpos); + if (rv != len) goto error; - jop->curpos += op->len; - jop->csum = checksum_buf(jop->csum, op->buf, op->len); + jop->curpos += len; + jop->csum = checksum_buf(jop->csum, buf, len); + + jop->numops++; return 0; @@ -334,26 +312,13 @@ error: return -1; } -/** Save the given transaction in the journal */ -int journal_save(struct journal_op *jop) +/** Commit the journal operation */ +int journal_commit(struct journal_op *jop) { ssize_t rv; - struct joper *op; - const struct jtrans *ts = jop->ts; struct on_disk_ophdr ophdr; struct on_disk_trailer trailer; - /* save each transacion in the file */ - for (op = ts->op; op != NULL; op = op->next) { - rv = save_joper(jop, ts, op); - if (rv != 0) - goto error; - - fiu_exit_on("jio/commit/tf_opdata"); - } - - fiu_exit_on("jio/commit/tf_data"); - /* write the the empty ophdr to mark there are no more operations, and * then the trailer */ ophdr.len = 0; @@ -369,7 +334,7 @@ int journal_save(struct journal_op *jop) sizeof(ophdr)); trailer.checksum = jop->csum; - trailer.numops = ts->numops; + trailer.numops = jop->numops; trailer_hton(&trailer); rv = spwrite(jop->fd, &trailer, sizeof(trailer), jop->curpos); @@ -383,7 +348,7 @@ int journal_save(struct journal_op *jop) * point) so we only flush here (both data and metadata) */ if (fsync(jop->fd) != 0) goto error; - if (fsync_dir(ts->fs->jdirfd) != 0) + if (fsync_dir(jop->fs->jdirfd) != 0) goto error; fiu_exit_on("jio/commit/tf_sync"); @@ -444,7 +409,7 @@ int fill_trans(unsigned char *map, off_t len, struct jtrans *ts) { int rv, numops; unsigned char *p; - struct joper *op, *tmp; + struct operation *op, *tmp; struct on_disk_hdr hdr; struct on_disk_ophdr ophdr; struct on_disk_trailer trailer; @@ -484,7 +449,7 @@ int fill_trans(unsigned char *map, off_t len, struct jtrans *ts) if (p + ophdr.len > map + len) goto error; - op = malloc(sizeof(struct joper)); + op = malloc(sizeof(struct operation)); if (op == NULL) goto error; diff --git a/libjio/journal.h b/libjio/journal.h index 765571b..648fcb9 100644 --- a/libjio/journal.h +++ b/libjio/journal.h @@ -9,17 +9,19 @@ struct journal_op { int id; int fd; + int numops; char *name; off_t curpos; uint32_t csum; - struct jtrans *ts; struct jfs *fs; }; typedef struct journal_op jop_t; -struct journal_op *journal_new(struct jtrans *ts); -int journal_save(struct journal_op *jop); +struct journal_op *journal_new(struct jfs *fs, unsigned int flags); +int journal_add_op(struct journal_op *jop, unsigned char *buf, size_t len, + off_t offset); +int journal_commit(struct journal_op *jop); int journal_free(struct journal_op *jop); int fill_trans(unsigned char *map, off_t len, struct jtrans *ts); diff --git a/libjio/trans.c b/libjio/trans.c index b4ffc42..1d5c1ba 100644 --- a/libjio/trans.c +++ b/libjio/trans.c @@ -43,9 +43,10 @@ struct jtrans *jtrans_new(struct jfs *fs, unsigned int flags) ts->op = NULL; ts->numops = 0; ts->len = 0; + pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); - pthread_mutex_init( &(ts->lock), &attr); + pthread_mutex_init(&(ts->lock), &attr); pthread_mutexattr_destroy(&attr); return ts; @@ -74,6 +75,34 @@ void jtrans_free(struct jtrans *ts) free(ts); } +/** Read the previous information from the disk into the given operation + * structure. Returns 0 on success, -1 on error. */ +static int operation_read_prev(struct jtrans *ts, struct operation *op) +{ + ssize_t rv; + + op->pdata = malloc(op->len); + if (op->pdata == NULL) + return -1; + + rv = spread(ts->fs->fd, op->pdata, op->len, + op->offset); + if (rv < 0) { + free(op->pdata); + op->pdata = NULL; + return -1; + } + + op->plen = op->len; + if (rv < op->len) { + /* we are extending the file! */ + /* ftruncate(ts->fs->fd, op->offset + op->len); */ + op->plen = rv; + } + + return 0; +} + /* Add an operation to a transaction */ int jtrans_add(struct jtrans *ts, const void *buf, size_t count, off_t offset) { @@ -87,7 +116,7 @@ int jtrans_add(struct jtrans *ts, const void *buf, size_t count, off_t offset) return -1; } - /* fail for 0 length transactions */ + /* fail for 0 length operations */ if (count == 0) { pthread_mutex_unlock(&(ts->lock)); return 1; @@ -106,8 +135,8 @@ int jtrans_add(struct jtrans *ts, const void *buf, size_t count, off_t offset) pthread_mutex_unlock(&(ts->lock)); return -1; } - jop = ts->op; - jop->prev = NULL; + op = ts->op; + op->prev = NULL; } else { for (tmpop = ts->op; tmpop->next != NULL; tmpop = tmpop->next) ; @@ -117,34 +146,34 @@ int jtrans_add(struct jtrans *ts, const void *buf, size_t count, off_t offset) return -1; } tmpop->next->prev = tmpop; - jop = tmpop->next; + op = tmpop->next; } - jop->buf = malloc(count); - if (jop->buf == NULL) { + op->buf = malloc(count); + if (op->buf == NULL) { /* remove from the list and fail */ - if (jop->prev == NULL) { + if (op->prev == NULL) { ts->op = NULL; } else { - jop->prev->next = jop->next; + op->prev->next = op->next; } - free(jop); + free(op); pthread_mutex_unlock(&(ts->lock)); return -1; } ts->numops++; ts->len += count; + pthread_mutex_unlock(&(ts->lock)); - /* we copy the buffer because then the caller can reuse it */ - memcpy(jop->buf, buf, count); - jop->len = count; - jop->offset = offset; - jop->next = NULL; - jop->plen = 0; - jop->pdata = NULL; - jop->locked = 0; + memcpy(op->buf, buf, count); + op->len = count; + op->offset = offset; + op->next = NULL; + op->plen = 0; + op->pdata = NULL; + op->locked = 0; if (!(ts->flags & J_NOROLLBACK)) { /* jtrans_commit() will want to read the current data, so we @@ -161,7 +190,7 @@ ssize_t jtrans_commit(struct jtrans *ts) ssize_t r, retval = -1; struct operation *op; struct jlinger *linger; - jop_t *jop; + jop_t *jop = NULL; size_t written = 0; pthread_mutex_lock(&(ts->lock)); @@ -189,16 +218,33 @@ ssize_t jtrans_commit(struct jtrans *ts) } } - jop = journal_new(ts); + /* create and fill the transaction file */ + jop = journal_new(ts->fs, ts->flags); if (jop == NULL) goto unlock_exit; - r = journal_save(jop); - if (r < 0) { - journal_free(jop); - goto unlock_exit; + if (!(ts->flags & J_NOROLLBACK)) { + for (op = ts->op; op != NULL; op = op->next) { + r = operation_read_prev(ts, op); + if (r < 0) + goto unlink_exit; + } } + for (op = ts->op; op != NULL; op = op->next) { + r = journal_add_op(jop, op->buf, op->len, op->offset); + if (r != 0) + goto unlink_exit; + + fiu_exit_on("jio/commit/tf_opdata"); + } + + fiu_exit_on("jio/commit/tf_data"); + + r = journal_commit(jop); + if (r < 0) + goto unlink_exit; + /* now that we have a safe transaction file, let's apply it */ written = 0; for (op = ts->op; op != NULL; op = op->next) { @@ -275,13 +321,14 @@ rollback_exit: } } +unlink_exit: /* If the journal operation is no longer needed, we remove it from the * disk. * * Extreme conditions (filesystem just got read-only, for example) can * cause journal_free() to fail, but there's not much left to do at * that point, and the caller will have to be careful and stop its - * operations. In that case, we will return -1, but the transaction + * operations. In that case, we will return -2, and the transaction * will be marked as J_COMMITTED to indicate that the data was * effectively written to disk. */ if (jop) {