Skip to content
Permalink
Browse files
MDEV-14244 MariaDB 10.2.10 fails to run on Debian Stretch with ext3 a…
…nd O_DIRECT

os_file_set_size(): If posix_fallocate() returns EINVAL, fall back
to writing zero bytes to the file. Also, remove some error log output,
and make it possible for a server shutdown to interrupt the fall-back
code.

MariaDB 10.2 used to handle the EINVAL return value from posix_fallocate()
before commit b731a5b
which refactored os_file_set_size() to try posix_fallocate().

Why is the EINVAL returned? The GNU posix_fallocate() function
would first try the fallocate() system call, which would return
-EOPNOTSUPP for many file systems (notably, not ext4). Then, it
would fall back to extending the file one block at a time by invoking
pwrite(fd, "", 1, offset) where offset is 1 less than a multiple of
the file block size. This would fail with EINVAL if the file is in
O_DIRECT mode, because O_DIRECT requires aligned operation.
  • Loading branch information
dr-m committed Nov 2, 2017
1 parent 0f4e005 commit 19733ef
Showing 1 changed file with 15 additions and 29 deletions.
@@ -5382,13 +5382,21 @@ os_file_set_size(
} while (err == EINTR
&& srv_shutdown_state == SRV_SHUTDOWN_NONE);

if (err) {
switch (err) {
case 0:
return true;
default:
ib::error() << "preallocating "
<< size << " bytes for file " << name
<< " failed with error " << err;
/* fall through */
case EINTR:
errno = err;
return false;
case EINVAL:
/* fall back to the code below */
break;
}
errno = err;
return(!err);
# endif /* HAVE_POSIX_ALLOCATE */
#endif /* _WIN32*/

@@ -5410,14 +5418,9 @@ os_file_set_size(
memset(buf, 0, buf_size);

os_offset_t current_size = os_file_get_size(file);
bool write_progress_info =
(size - current_size >= (os_offset_t) 100 << 20);

if (write_progress_info) {
ib::info() << "Progress in MB:";
}

while (current_size < size) {
while (current_size < size
&& srv_shutdown_state == SRV_SHUTDOWN_NONE) {
ulint n_bytes;

if (size - current_size < (os_offset_t) buf_size) {
@@ -5433,32 +5436,15 @@ os_file_set_size(
request, name, file, buf, current_size, n_bytes);

if (err != DB_SUCCESS) {

ut_free(buf2);
return(false);
}

/* Print about progress for each 100 MB written */
if (write_progress_info &&
((current_size + n_bytes) / (100 << 20)
!= current_size / (100 << 20))) {

fprintf(stderr, " %lu00",
(ulong) ((current_size + n_bytes)
/ (100 << 20)));
break;
}

current_size += n_bytes;
}

if (write_progress_info) {

fprintf(stderr, "\n");
}

ut_free(buf2);

return(os_file_flush(file));
return(current_size >= size && os_file_flush(file));
}

/** Truncates a file to a specified size in bytes.

0 comments on commit 19733ef

Please sign in to comment.