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
);
57 #else /* HAVE_SYNC_FILE_RANGE */
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
);
112 #endif /* !HAVE_SYNC_FILE_RANGE */
115 * Use posix_fadvise when available.
117 #ifdef HAVE_POSIX_FADVISE
119 int hint_dont_need(int fd
, off_t offset
, off_t nbytes
)
121 const int ret
= posix_fadvise(fd
, offset
, nbytes
, POSIX_FADV_DONTNEED
);
122 if (ret
&& ret
!= -ENOSYS
) {
123 PERROR("Failed to mark region as DONTNEED with posix_fadvise: fd=%i, offset=%" PRIu64
126 static_cast<uint64_t>(offset
),
127 static_cast<uint64_t>(nbytes
));
135 #else /* HAVE_POSIX_FADVISE */
138 * Generic noop compat for platforms wihtout posix_fadvise, this is acceptable
139 * since we are only giving a hint to the kernel.
142 int hint_dont_need(int fd
__attribute__((unused
)),
143 off_t offset
__attribute__((unused
)),
144 off_t nbytes
__attribute__((unused
)))
149 #endif /* !HAVE_POSIX_FADVISE */
152 * Give a hint to the kernel that we won't need the data at the specified range
153 * so it can be dropped from the page cache and wait for it to be flushed to
156 void lttng::io::hint_flush_range_dont_need_sync(int fd
, off_t offset
, off_t nbytes
)
158 /* Waited for the page writeback to complete. */
159 flush_range_sync(fd
, offset
, nbytes
);
162 * Give hints to the kernel about how we access the file:
163 * POSIX_FADV_DONTNEED : we won't re-access data in a near future after
166 * We need to call fadvise again after the file grows because the
167 * kernel does not seem to apply fadvise to non-existing parts of the
170 * Call fadvise _after_ having waited for the page writeback to
171 * complete because the dirty page writeback semantic is not well
172 * defined. So it can be expected to lead to lower throughput in
175 hint_dont_need(fd
, offset
, nbytes
);
179 * Give a hint to the kernel that the data at the specified range should be
180 * flushed to disk and wait for it to complete.
182 void lttng::io::hint_flush_range_sync(int fd
, off_t offset
, off_t nbytes
)
184 flush_range_sync(fd
, offset
, nbytes
);
188 * Give a hint to the kernel that the data at the specified range should be
189 * flushed to disk and return immediatly.
191 void lttng::io::hint_flush_range_async(int fd
, off_t offset
, off_t nbytes
)
193 flush_range_async(fd
, offset
, nbytes
);