author | Alberto Bertogli
<albertito@gmail.com> 2004-07-13 21:16:38 UTC |
committer | Alberto Bertogli
<albertito@gmail.com> 2007-07-15 13:09:18 UTC |
parent | b60413ad4ff5761764f5503f45b04c1f636530af |
libjio.h | +1 | -0 |
trans.c | +21 | -2 |
diff --git a/libjio.h b/libjio.h index 8204f46..83a95fe 100644 --- a/libjio.h +++ b/libjio.h @@ -24,6 +24,7 @@ extern "C" { struct jfs { int fd; /* main file descriptor */ char *name; /* and its name */ + int jdirfd; /* journal directory file descriptor */ int jfd; /* journal's lock file descriptor */ int flags; /* journal flags */ pthread_mutex_t lock; /* a soft lock used in some operations */ diff --git a/trans.c b/trans.c index c121bb2..d2a7a2d 100644 --- a/trans.c +++ b/trans.c @@ -324,8 +324,21 @@ int jtrans_commit(struct jtrans *ts) * everything O_SYNC, we sync at this point only, this way we avoid * doing a lot of very small writes; in case of a crash the * transaction file is only useful if it's complete (ie. after this - * point) so we only flush here */ - fsync(fd); + * point) so we only flush here (both data and metadata) */ + if (fsync(fd) != 0) + goto exit; + if (fsync(ts->fs->jdirfd) != 0) { + /* it seems to be legal that fsync() on directories is not + * implemented, so if this fails with EINVAL or EBADF, just + * call a global sync(); which is awful (and might still + * return before metadata is done) but it seems to be the + * saner choice; otherwise we just fail */ + if (errno == EINVAL || errno == EBADF) { + sync(); + } else { + goto exit; + } + } /* now that we have a safe transaction file, let's apply it */ written = 0; @@ -473,6 +486,12 @@ int jopen(struct jfs *fs, const char *name, int flags, int mode, int jflags) if (rv < 0 || !S_ISDIR(sinfo.st_mode)) return -1; + /* open the directory, we will use it to flush transaction files' + * metadata in jtrans_commit() */ + fs->jdirfd = open(jdir, O_RDONLY); + if (fs->jdirfd < 0) + return -1; + snprintf(jlockfile, PATH_MAX, "%s/%s", jdir, "lock"); jfd = open(jlockfile, O_RDWR | O_CREAT, 0600); if (jfd < 0)