[dovecot-cvs] dovecot: Fixes to mail_transaction_log_file_map() error handling.
dovecot at dovecot.org
dovecot at dovecot.org
Wed Jun 13 19:49:56 EEST 2007
details: http://hg.dovecot.org/dovecot/rev/4a08705e97f5
changeset: 5716:4a08705e97f5
user: Timo Sirainen <tss at iki.fi>
date: Wed Jun 13 19:49:51 2007 +0300
description:
Fixes to mail_transaction_log_file_map() error handling.
diffstat:
2 files changed, 129 insertions(+), 96 deletions(-)
src/lib-index/mail-transaction-log-file.c | 223 ++++++++++++++------------
src/lib-index/mail-transaction-log-private.h | 2
diffs (truncated from 359 to 300 lines):
diff -r 11d39b7f07ff -r 4a08705e97f5 src/lib-index/mail-transaction-log-file.c
--- a/src/lib-index/mail-transaction-log-file.c Wed Jun 13 19:49:06 2007 +0300
+++ b/src/lib-index/mail-transaction-log-file.c Wed Jun 13 19:49:51 2007 +0300
@@ -22,13 +22,14 @@ mail_transaction_log_file_set_corrupted(
file->hdr.indexid = 0;
if (!MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
- /*FIXME:if (pwrite_full(file->fd, &file->hdr.indexid,
+ /* indexid=0 marks the log file as corrupted */
+ if (pwrite_full(file->fd, &file->hdr.indexid,
sizeof(file->hdr.indexid),
offsetof(struct mail_transaction_log_header,
indexid)) < 0) {
mail_index_file_set_syscall_error(file->log->index,
file->filepath, "pwrite()");
- }*/
+ }
}
va_start(va, fmt);
@@ -38,12 +39,6 @@ mail_transaction_log_file_set_corrupted(
file->filepath, t_strdup_vprintf(fmt, va));
t_pop();
va_end(va);
-
- if (file->log->index->log != NULL && file->log->index->map != NULL) {
- /* this may have happened because of broken index.
- make sure it's ok. */
- (void)mail_index_fsck(file->log->index);
- }
}
struct mail_transaction_log_file *
@@ -116,7 +111,14 @@ mail_transaction_log_file_add_to_list(st
/* we can get a valid log offset from index file. initialize
sync_offset from it so we don't have to read the whole log
file from beginning. */
- file->sync_offset = map->hdr.log_file_index_int_offset;
+ if (map->hdr.log_file_index_int_offset >= file->hdr.hdr_size)
+ file->sync_offset = map->hdr.log_file_index_int_offset;
+ else {
+ mail_index_set_error(log->index,
+ "%s: log_file_index_int_offset too small",
+ log->index->filepath);
+ file->sync_offset = file->hdr.hdr_size;
+ }
file->mailbox_sync_saved_offset =
map->hdr.log_file_mailbox_offset;
} else {
@@ -372,9 +374,11 @@ mail_transaction_log_file_read_hdr(struc
corrupted. */
for (f = file->log->files; f != NULL; f = f->next) {
if (f->hdr.file_seq == file->hdr.file_seq) {
- mail_transaction_log_file_set_corrupted(file,
- "old transaction log already opened (%u == %u)",
- f->hdr.file_seq, file->hdr.file_seq);
+ /* mark the old file corrupted. we can't safely remove
+ it from the list however, so return failure. */
+ mail_transaction_log_file_set_corrupted(f,
+ "duplicate transaction log sequence (%u)",
+ f->hdr.file_seq);
return 0;
}
}
@@ -743,8 +747,44 @@ mail_transaction_log_file_sync(struct ma
}
static int
+mail_transaction_log_file_insert_read(struct mail_transaction_log_file *file,
+ uoff_t offset)
+{
+ void *data;
+ size_t size;
+ ssize_t ret;
+
+ size = file->buffer_offset - offset;
+ buffer_copy(file->buffer, size, file->buffer, 0, (size_t)-1);
+
+ data = buffer_get_space_unsafe(file->buffer, 0, size);
+ ret = pread_full(file->fd, data, size, offset);
+ if (ret > 0) {
+ /* success */
+ file->buffer_offset -= size;
+ return 1;
+ }
+
+ /* failure. don't leave ourself to inconsistent state */
+ buffer_copy(file->buffer, 0, file->buffer, size, (size_t)-1);
+ buffer_set_used_size(file->buffer, file->buffer->used - size);
+
+ if (ret == 0) {
+ mail_transaction_log_file_set_corrupted(file, "file shrinked");
+ return 0;
+ } else if (errno == ESTALE) {
+ /* log file was deleted in NFS server, fail silently */
+ return 0;
+ } else {
+ mail_index_file_set_syscall_error(file->log->index,
+ file->filepath, "pread()");
+ return -1;
+ }
+}
+
+static int
mail_transaction_log_file_read(struct mail_transaction_log_file *file,
- uoff_t offset)
+ uoff_t start_offset)
{
void *data;
size_t size;
@@ -753,36 +793,17 @@ mail_transaction_log_file_read(struct ma
i_assert(file->mmap_base == NULL);
- if (file->buffer != NULL && file->buffer_offset > offset) {
+ if (file->buffer != NULL && file->buffer_offset > start_offset) {
/* we have to insert missing data to beginning of buffer */
- size = file->buffer_offset - offset;
- buffer_copy(file->buffer, size, file->buffer, 0, (size_t)-1);
- file->buffer_offset -= size;
-
- data = buffer_get_space_unsafe(file->buffer, 0, size);
- ret = pread_full(file->fd, data, size, offset);
- if (ret == 0) {
- mail_transaction_log_file_set_corrupted(file,
- "Unexpected end of file");
- return 0;
- }
- if (ret < 0) {
- if (errno == ESTALE) {
- /* log file was deleted in NFS server,
- fail silently */
- return 0;
- }
- mail_index_file_set_syscall_error(file->log->index,
- file->filepath,
- "pread()");
- return -1;
- }
+ ret = mail_transaction_log_file_insert_read(file, start_offset);
+ if (ret <= 0)
+ return ret;
}
if (file->buffer == NULL) {
file->buffer =
buffer_create_dynamic(default_pool, LOG_PREFETCH);
- file->buffer_offset = offset;
+ file->buffer_offset = start_offset;
}
/* read all records */
@@ -801,7 +822,7 @@ mail_transaction_log_file_read(struct ma
file->last_size = read_offset;
if (mail_transaction_log_file_sync(file) < 0)
- return -1;
+ return 0;
if (ret == 0) {
/* EOF */
@@ -821,6 +842,29 @@ mail_transaction_log_file_read(struct ma
return -1;
}
+static int
+log_file_map_check_offsets(struct mail_transaction_log_file *file,
+ uoff_t start_offset, uoff_t end_offset)
+{
+ if (start_offset > file->sync_offset) {
+ /* broken start offset */
+ mail_index_set_error(file->log->index,
+ "%s: start_offset (%"PRIuUOFF_T") > "
+ "current sync_offset (%"PRIuUOFF_T")",
+ file->filepath, start_offset, file->sync_offset);
+ return 0;
+ }
+ if (end_offset != (uoff_t)-1 && end_offset > file->sync_offset) {
+ mail_index_set_error(file->log->index,
+ "%s: end_offset (%"PRIuUOFF_T") > "
+ "current sync_offset (%"PRIuUOFF_T")",
+ file->filepath, start_offset, file->sync_offset);
+ return 0;
+ }
+
+ return 1;
+}
+
int mail_transaction_log_file_map(struct mail_transaction_log_file *file,
uoff_t start_offset, uoff_t end_offset)
{
@@ -829,22 +873,13 @@ int mail_transaction_log_file_map(struct
struct stat st;
int ret;
- i_assert(start_offset <= end_offset);
-
if (file->hdr.indexid == 0) {
/* corrupted */
return 0;
}
- if (start_offset < file->hdr.hdr_size) {
- mail_transaction_log_file_set_corrupted(file,
- "offset (%"PRIuUOFF_T") < header size (%u)",
- start_offset, file->hdr.hdr_size);
- return -1;
- }
-
- if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file))
- return 1;
+ i_assert(start_offset >= file->hdr.hdr_size);
+ i_assert(start_offset <= end_offset);
if (index->log_locked && file == file->log->head &&
end_offset == (uoff_t)-1) {
@@ -860,7 +895,25 @@ int mail_transaction_log_file_map(struct
return 1;
}
+ if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
+ if (start_offset < file->buffer_offset) {
+ /* we had moved the log to memory but failed to read
+ the beginning of the log file */
+ mail_index_set_error(index,
+ "%s: Beginning of the log isn't available",
+ file->filepath);
+ return 0;
+ }
+ return log_file_map_check_offsets(file, start_offset,
+ end_offset);
+ }
+
if (!index->mmap_disable) {
+ /* we are going to mmap() this file, but it's not necessarily
+ mmaped currently. */
+ i_assert(file->buffer_offset == 0 || file->mmap_base == NULL);
+ i_assert(file->mmap_size == 0 || file->mmap_base != NULL);
+
if (fstat(file->fd, &st) < 0) {
mail_index_file_set_syscall_error(index, file->filepath,
"fstat()");
@@ -868,55 +921,46 @@ int mail_transaction_log_file_map(struct
}
file->last_size = st.st_size;
- if (start_offset > (uoff_t)st.st_size) {
+ if ((uoff_t)st.st_size < file->sync_offset) {
mail_transaction_log_file_set_corrupted(file,
- "start_offset (%"PRIuUOFF_T") > file size "
- "(%"PRIuUOFF_T")", start_offset,
- (uoff_t)st.st_size);
- return -1;
- }
-
- if (file->mmap_base != NULL &&
- (uoff_t)st.st_size == file->mmap_size &&
- file->buffer_offset <= start_offset &&
- end_offset == (uoff_t)-1) {
- /* it's all mmaped already */
+ "file size shrinked");
+ return 0;
+ }
+
+ if ((uoff_t)st.st_size == file->mmap_size) {
+ /* we already have the whole file mmaped */
if (mail_transaction_log_file_sync(file) < 0)
- return -1;
- return 1;
- }
- }
-
- if (file->buffer != NULL &&
- (file->mmap_base != NULL || !index->mmap_disable)) {
- buffer_free(file->buffer);
- file->buffer = NULL;
- }
+ return 0;
+ return log_file_map_check_offsets(file, start_offset,
+ end_offset);
+ }
+ }
+
if (file->mmap_base != NULL) {
if (munmap(file->mmap_base, file->mmap_size) < 0) {
mail_index_file_set_syscall_error(index, file->filepath,
"munmap()");
}
file->mmap_base = NULL;
+ file->mmap_size = 0;
+ buffer_free(file->buffer);
}
if (index->mmap_disable) {
ret = mail_transaction_log_file_read(file, start_offset);
- if (ret <= 0) {
- /* make sure we don't leave ourself in
- inconsistent state */
- if (file->buffer != NULL) {
- buffer_free(file->buffer);
More information about the dovecot-cvs
mailing list