From: Mark Vitale Date: Wed, 13 Mar 2013 02:13:20 +0000 (-0400) Subject: dafs: prevent corruption in large fsstate.dat files X-Git-Tag: openafs-stable-1_8_0pre1~1268 X-Git-Url: https://git.openafs.org/?p=openafs.git;a=commitdiff_plain;h=42351db75e04e46012208d38f80dc17be7ab776d dafs: prevent corruption in large fsstate.dat files If while writing to the fsstate.dat file, it exceeds the current size of the file (multiples of FS_STATE_INIT_FILESIZE (8MiB)), we call fs_stateResizeFile. This un-mmaps, truncates, and re-mmaps the file. Unfortunately, fs_stateMapFile() resets the state->mmap.offset and .cursor, so any writes in flight over the resize will overwrite the first bytes of the file (and leave zeros in the file where the data should have been written). Upon return from the write that caused a file resize, the offset is eventually corrected and the state dump continues with a silent failure. Eventually the state dump completes and the file header is rewritten; this may conceal some or all of the overwrite damage at offset 0. However, any zeros near the 8MiB offset (and its multiples) remain as corruption. Add a flag to fs_stateMapFile() to allow the caller to specify if the offset and cursor should be preserved. Modify fs_stateResizeFile() to use this capability. testing note: temporarily reduced FS_STATE_INIT_FILESIZE to 256 bytes during testing in order to make the problem easier to reproduce. This problem would normally occur only on relatively large/active DAFS fileservers. Change-Id: I9b6c57ef7727837ae7cfc00d02192983355dad2b Reviewed-on: http://gerrit.openafs.org/9599 Tested-by: BuildBot Reviewed-by: Derrick Brashear --- diff --git a/src/viced/serialize_state.c b/src/viced/serialize_state.c index 154dcc7..aaf4988 100644 --- a/src/viced/serialize_state.c +++ b/src/viced/serialize_state.c @@ -74,7 +74,7 @@ static int fs_stateSizeFile(struct fs_dump_state * state); static int fs_stateResizeFile(struct fs_dump_state * state, size_t min_add); static int fs_stateTruncateFile(struct fs_dump_state * state); -static int fs_stateMapFile(struct fs_dump_state * state); +static int fs_stateMapFile(struct fs_dump_state * state, int preserve_flag); static int fs_stateUnmapFile(struct fs_dump_state * state); static int fs_stateIncCursor(struct fs_dump_state * state, size_t len); @@ -340,7 +340,7 @@ fs_stateCreateDump(struct fs_dump_state * state) goto done; } - if (fs_stateMapFile(state)) { + if (fs_stateMapFile(state, 0)) { ViceLog(0, ("fs_stateCreateDump: failed to memory map state dump file '%s'\n", state->fn)); ret = 1; @@ -465,7 +465,7 @@ fs_stateLoadDump(struct fs_dump_state * state) state->file_len = status.st_size; #ifdef FS_STATE_USE_MMAP - if (fs_stateMapFile(state)) { + if (fs_stateMapFile(state, 0)) { ViceLog(0, ("fs_stateLoadDump: failed to memory map state dump file '%s'\n", state->fn)); ret = 1; @@ -734,7 +734,7 @@ fs_stateResizeFile(struct fs_dump_state * state, size_t min_add) goto done; } - if (fs_stateMapFile(state)) { + if (fs_stateMapFile(state, 1)) { ViceLog(0, ("fs_stateResizeFile: remapping memory mapped file failed\n")); ret = 1; goto done; @@ -757,7 +757,7 @@ fs_stateTruncateFile(struct fs_dump_state * state) } static int -fs_stateMapFile(struct fs_dump_state * state) +fs_stateMapFile(struct fs_dump_state * state, int preserve_flag ) { int ret = 0, flags; @@ -791,8 +791,16 @@ fs_stateMapFile(struct fs_dump_state * state) state->mmap.size = state->file_len; state->mmap.cursor = state->mmap.map; - state->mmap.offset = 0; + if (preserve_flag) { + /* don't lose track of where we are during a file resize */ + afs_foff_t curr_offset = state->mmap.offset; + + state->mmap.offset = 0; + fs_stateIncCursor(state, curr_offset); + } else { /* reset offset */ + state->mmap.offset = 0; + } /* for state loading, accesses will be sequential, so let's give * the VM subsystem a heads up */ if (state->mode == FS_STATE_LOAD_MODE) {