Skip to content

Commit 91155b9

Browse files
committed
Hack for potential ext3/ext4 corruption issue
Use regular fsync() if we think this commit grew the DB file.
1 parent e6ac9c2 commit 91155b9

File tree

1 file changed

+38
-5
lines changed

1 file changed

+38
-5
lines changed

libraries/liblmdb/mdb.c

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,7 @@ mdb_sem_wait(sem_t *sem)
333333
*/
334334
#ifndef MDB_FDATASYNC
335335
# define MDB_FDATASYNC fdatasync
336+
# define HAVE_FDATASYNC 1
336337
#endif
337338

338339
#ifndef MDB_MSYNC
@@ -1112,7 +1113,7 @@ struct MDB_env {
11121113
MDB_txn *me_txn; /**< current write transaction */
11131114
MDB_txn *me_txn0; /**< prealloc'd write transaction */
11141115
size_t me_mapsize; /**< size of the data memory map */
1115-
off_t me_size; /**< current file size */
1116+
size_t me_size; /**< current file size */
11161117
pgno_t me_maxpg; /**< me_mapsize / me_psize */
11171118
MDB_dbx *me_dbxs; /**< array of static DB info */
11181119
uint16_t *me_dbflags; /**< array of flags from MDB_db.md_flags */
@@ -2298,10 +2299,19 @@ mdb_page_touch(MDB_cursor *mc)
22982299
return rc;
22992300
}
23002301

2301-
int
2302-
mdb_env_sync(MDB_env *env, int force)
2302+
/* internal env_sync flags: */
2303+
#define FORCE 1 /* as before, force a flush */
2304+
#define FGREW 0x8000 /* file has grown, do a full fsync instead of just
2305+
fdatasync. We shouldn't have to do this, according to the POSIX spec.
2306+
But common Linux FSs violate the spec and won't sync required metadata
2307+
correctly when the file grows. This only makes a difference if the
2308+
platform actually distinguishes fdatasync from fsync.
2309+
http://www.openldap.org/lists/openldap-devel/201411/msg00000.html */
2310+
2311+
static int
2312+
mdb_env_sync0(MDB_env *env, int flag)
23032313
{
2304-
int rc = 0;
2314+
int rc = 0, force = flag & FORCE;
23052315
if (force || !F_ISSET(env->me_flags, MDB_NOSYNC)) {
23062316
if (env->me_flags & MDB_WRITEMAP) {
23072317
int flags = ((env->me_flags & MDB_MAPASYNC) && !force)
@@ -2313,13 +2323,25 @@ mdb_env_sync(MDB_env *env, int force)
23132323
rc = ErrCode();
23142324
#endif
23152325
} else {
2326+
#ifdef HAVE_FDATASYNC
2327+
if (flag & FGREW) {
2328+
if (fsync(env->me_fd)) /* Avoid ext-fs bugs, do full sync */
2329+
rc = ErrCode();
2330+
} else
2331+
#endif
23162332
if (MDB_FDATASYNC(env->me_fd))
23172333
rc = ErrCode();
23182334
}
23192335
}
23202336
return rc;
23212337
}
23222338

2339+
int
2340+
mdb_env_sync(MDB_env *env, int force)
2341+
{
2342+
return mdb_env_sync0(env, force != 0);
2343+
}
2344+
23232345
/** Back up parent txn's cursors, then grab the originals for tracking */
23242346
static int
23252347
mdb_cursor_shadow(MDB_txn *src, MDB_txn *dst)
@@ -3372,8 +3394,15 @@ mdb_txn_commit(MDB_txn *txn)
33723394
mdb_audit(txn);
33733395
#endif
33743396

3397+
i = 0;
3398+
#ifdef HAVE_FDATASYNC
3399+
if (txn->mt_next_pgno * env->me_psize > env->me_size) {
3400+
i |= FGREW;
3401+
env->me_size = txn->mt_next_pgno * env->me_psize;
3402+
}
3403+
#endif
33753404
if ((rc = mdb_page_flush(txn, 0)) ||
3376-
(rc = mdb_env_sync(env, 0)) ||
3405+
(rc = mdb_env_sync(env, i)) ||
33773406
(rc = mdb_env_write_meta(txn)))
33783407
goto fail;
33793408

@@ -3897,6 +3926,10 @@ mdb_env_open2(MDB_env *env)
38973926
env->me_mapsize = minsize;
38983927
}
38993928

3929+
rc = mdb_fsize(env->me_fd, &env->me_size);
3930+
if (rc)
3931+
return rc;
3932+
39003933
rc = mdb_env_map(env, (flags & MDB_FIXEDMAP) ? meta.mm_address : NULL);
39013934
if (rc)
39023935
return rc;

0 commit comments

Comments
 (0)