|
73 | 73 | static bool dsm_impl_posix(dsm_op op, dsm_handle handle, Size request_size,
|
74 | 74 | void **impl_private, void **mapped_address,
|
75 | 75 | Size *mapped_size, int elevel);
|
| 76 | +static int dsm_impl_posix_resize(int fd, off_t size); |
76 | 77 | #endif
|
77 | 78 | #ifdef USE_DSM_SYSV
|
78 | 79 | static bool dsm_impl_sysv(dsm_op op, dsm_handle handle, Size request_size,
|
@@ -319,7 +320,8 @@ dsm_impl_posix(dsm_op op, dsm_handle handle, Size request_size,
|
319 | 320 | }
|
320 | 321 | request_size = st.st_size;
|
321 | 322 | }
|
322 |
| - else if (*mapped_size != request_size && ftruncate(fd, request_size)) |
| 323 | + else if (*mapped_size != request_size && |
| 324 | + dsm_impl_posix_resize(fd, request_size) != 0) |
323 | 325 | {
|
324 | 326 | int save_errno;
|
325 | 327 |
|
@@ -392,7 +394,55 @@ dsm_impl_posix(dsm_op op, dsm_handle handle, Size request_size,
|
392 | 394 |
|
393 | 395 | return true;
|
394 | 396 | }
|
395 |
| -#endif |
| 397 | + |
| 398 | +/* |
| 399 | + * Set the size of a virtual memory region associated with a file descriptor. |
| 400 | + * If necessary, also ensure that virtual memory is actually allocated by the |
| 401 | + * operating system, to avoid nasty surprises later. |
| 402 | + * |
| 403 | + * Returns non-zero if either truncation or allocation fails, and sets errno. |
| 404 | + */ |
| 405 | +static int |
| 406 | +dsm_impl_posix_resize(int fd, off_t size) |
| 407 | +{ |
| 408 | + int rc; |
| 409 | + |
| 410 | + /* Truncate (or extend) the file to the requested size. */ |
| 411 | + rc = ftruncate(fd, size); |
| 412 | + |
| 413 | + /* |
| 414 | + * On Linux, a shm_open fd is backed by a tmpfs file. After resizing with |
| 415 | + * ftruncate, the file may contain a hole. Accessing memory backed by a |
| 416 | + * hole causes tmpfs to allocate pages, which fails with SIGBUS if there |
| 417 | + * is no more tmpfs space available. So we ask tmpfs to allocate pages |
| 418 | + * here, so we can fail gracefully with ENOSPC now rather than risking |
| 419 | + * SIGBUS later. |
| 420 | + */ |
| 421 | +#if defined(HAVE_POSIX_FALLOCATE) && defined(__linux__) |
| 422 | + if (rc == 0) |
| 423 | + { |
| 424 | + /* We may get interrupted, if so just retry. */ |
| 425 | + do |
| 426 | + { |
| 427 | + rc = posix_fallocate(fd, 0, size); |
| 428 | + } while (rc == -1 && errno == EINTR); |
| 429 | + |
| 430 | + if (rc != 0 && errno == ENOSYS) |
| 431 | + { |
| 432 | + /* |
| 433 | + * Kernel too old (< 2.6.23). Rather than fail, just trust that |
| 434 | + * we won't hit the problem (it typically doesn't show up without |
| 435 | + * many-GB-sized requests, anyway). |
| 436 | + */ |
| 437 | + rc = 0; |
| 438 | + } |
| 439 | + } |
| 440 | +#endif /* HAVE_POSIX_FALLOCATE && __linux__ */ |
| 441 | + |
| 442 | + return rc; |
| 443 | +} |
| 444 | + |
| 445 | +#endif /* USE_DSM_POSIX */ |
396 | 446 |
|
397 | 447 | #ifdef USE_DSM_SYSV
|
398 | 448 | /*
|
|
0 commit comments