2 * Copyright (C) 2023 Michael Jeanson <mjeanson@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
8 #include <common/error.hpp>
9 #include <common/io-hint.hpp>
10 #include <common/scope-exit.hpp>
18 * Use sync_file_range when available.
20 #ifdef HAVE_SYNC_FILE_RANGE
25 int flush_range(int fd
, off_t offset
, off_t nbytes
, unsigned int flags
)
29 ret
= sync_file_range(fd
, offset
, nbytes
, flags
);
31 PERROR("Failed to sync file range: fd=%i, offset=%" PRIu64
", nbytes=%" PRIu64
34 static_cast<uint64_t>(offset
),
35 static_cast<uint64_t>(nbytes
),
42 int flush_range_sync(int fd
, off_t offset
, off_t nbytes
)
44 return flush_range(fd
,
47 SYNC_FILE_RANGE_WAIT_BEFORE
| SYNC_FILE_RANGE_WRITE
|
48 SYNC_FILE_RANGE_WAIT_AFTER
);
51 int flush_range_async(int fd
, off_t offset
, off_t nbytes
)
53 return flush_range(fd
, offset
, nbytes
, SYNC_FILE_RANGE_WRITE
);
61 * Use a memory mapping with msync() to emulate sync_file_range().
63 int flush_range(int fd
, off_t offset
, off_t nbytes
, int flags
)
65 void *mapped_region
= mmap(NULL
, nbytes
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, fd
, offset
);
66 if (mapped_region
== MAP_FAILED
) {
67 PERROR("Failed to mmap region to flush range: fd=%i, offset=%" PRIu64
68 ", nbytes=%" PRIu64
", flags=%i",
70 static_cast<uint64_t>(offset
),
71 static_cast<uint64_t>(nbytes
),
76 const auto munmap_on_exit
= lttng::make_scope_exit([&]() noexcept
{
77 const auto munmap_ret
= munmap(mapped_region
, nbytes
);
79 PERROR("Failed to munmap region while flushing range: fd=%i, offset=%" PRIu64
80 ", nbytes=%" PRIu64
", flags=%i",
82 static_cast<uint64_t>(offset
),
83 static_cast<uint64_t>(nbytes
),
88 const auto msync_ret
= msync(mapped_region
, nbytes
, flags
);
90 PERROR("Failed to msync region while flushing range: fd=%i, offset=%" PRIu64
91 ", nbytes=%" PRIu64
", flags=%i",
93 static_cast<uint64_t>(offset
),
94 static_cast<uint64_t>(nbytes
),
102 int flush_range_sync(int fd
, off_t offset
, off_t nbytes
)
104 return flush_range(fd
, offset
, nbytes
, MS_SYNC
);
107 int flush_range_async(int fd
, off_t offset
, off_t nbytes
)
109 return flush_range(fd
, offset
, nbytes
, MS_ASYNC
);
115 * Give a hint to the kernel that we won't need the data at the specified range
116 * so it can be dropped from the page cache and wait for it to be flushed to
119 void lttng::io::hint_flush_range_dont_need_sync(int fd
, off_t offset
, off_t nbytes
)
121 /* Waited for the page writeback to complete. */
122 flush_range_sync(fd
, offset
, nbytes
);
125 * Give hints to the kernel about how we access the file:
126 * POSIX_FADV_DONTNEED : we won't re-access data in a near future after
129 * We need to call fadvise again after the file grows because the
130 * kernel does not seem to apply fadvise to non-existing parts of the
133 * Call fadvise _after_ having waited for the page writeback to
134 * complete because the dirty page writeback semantic is not well
135 * defined. So it can be expected to lead to lower throughput in
138 const int ret
= posix_fadvise(fd
, offset
, nbytes
, POSIX_FADV_DONTNEED
);
139 if (ret
&& ret
!= -ENOSYS
) {
140 PERROR("Failed to mark region as DONTNEED with posix_fadvise: fd=%i, offset=%" PRIu64
143 static_cast<uint64_t>(offset
),
144 static_cast<uint64_t>(nbytes
));
150 * Give a hint to the kernel that the data at the specified range should be
151 * flushed to disk and wait for it to complete.
153 void lttng::io::hint_flush_range_sync(int fd
, off_t offset
, off_t nbytes
)
155 flush_range_sync(fd
, offset
, nbytes
);
159 * Give a hint to the kernel that the data at the specified range should be
160 * flushed to disk and return immediatly.
162 void lttng::io::hint_flush_range_async(int fd
, off_t offset
, off_t nbytes
)
164 flush_range_async(fd
, offset
, nbytes
);