Fix: syscall event rule: emission sites not compared in is_equal
[lttng-tools.git] / src / common / io-hint.cpp
CommitLineData
671e39d7
MJ
1/*
2 * Copyright (C) 2023 Michael Jeanson <mjeanson@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8#include <common/error.hpp>
9#include <common/io-hint.hpp>
10#include <common/scope-exit.hpp>
11
12#include <cinttypes>
13#include <fcntl.h>
14#include <sys/mman.h>
15#include <unistd.h>
16
17/*
18 * Use sync_file_range when available.
19 */
20#ifdef HAVE_SYNC_FILE_RANGE
21
22#include <fcntl.h>
23
24namespace {
25int flush_range(int fd, off_t offset, off_t nbytes, unsigned int flags)
26{
27 int ret;
28
29 ret = sync_file_range(fd, offset, nbytes, flags);
30 if (ret) {
31 PERROR("Failed to sync file range: fd=%i, offset=%" PRIu64 ", nbytes=%" PRIu64
32 ", flags=%i",
33 fd,
34 static_cast<uint64_t>(offset),
35 static_cast<uint64_t>(nbytes),
36 flags);
37 }
38
39 return ret;
40}
41
42int flush_range_sync(int fd, off_t offset, off_t nbytes)
43{
44 return flush_range(fd,
45 offset,
46 nbytes,
47 SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE |
48 SYNC_FILE_RANGE_WAIT_AFTER);
49}
50
51int flush_range_async(int fd, off_t offset, off_t nbytes)
52{
53 return flush_range(fd, offset, nbytes, SYNC_FILE_RANGE_WRITE);
54}
55} /* namespace */
56
e8955cc6 57#else /* HAVE_SYNC_FILE_RANGE */
671e39d7
MJ
58
59namespace {
60/*
61 * Use a memory mapping with msync() to emulate sync_file_range().
62 */
63int flush_range(int fd, off_t offset, off_t nbytes, int flags)
64{
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",
69 fd,
70 static_cast<uint64_t>(offset),
71 static_cast<uint64_t>(nbytes),
72 flags);
73 return -1;
74 }
75
76 const auto munmap_on_exit = lttng::make_scope_exit([&]() noexcept {
77 const auto munmap_ret = munmap(mapped_region, nbytes);
78 if (munmap_ret) {
79 PERROR("Failed to munmap region while flushing range: fd=%i, offset=%" PRIu64
80 ", nbytes=%" PRIu64 ", flags=%i",
81 fd,
82 static_cast<uint64_t>(offset),
83 static_cast<uint64_t>(nbytes),
84 flags);
85 }
86 });
87
88 const auto msync_ret = msync(mapped_region, nbytes, flags);
89 if (msync_ret) {
90 PERROR("Failed to msync region while flushing range: fd=%i, offset=%" PRIu64
91 ", nbytes=%" PRIu64 ", flags=%i",
92 fd,
93 static_cast<uint64_t>(offset),
94 static_cast<uint64_t>(nbytes),
95 flags);
96 return -1;
97 }
98
99 return 0;
100}
101
102int flush_range_sync(int fd, off_t offset, off_t nbytes)
103{
104 return flush_range(fd, offset, nbytes, MS_SYNC);
105}
106
107int flush_range_async(int fd, off_t offset, off_t nbytes)
108{
109 return flush_range(fd, offset, nbytes, MS_ASYNC);
110}
111} /* namespace */
e8955cc6
MJ
112#endif /* !HAVE_SYNC_FILE_RANGE */
113
114/*
115 * Use posix_fadvise when available.
116 */
117#ifdef HAVE_POSIX_FADVISE
118namespace {
119int hint_dont_need(int fd, off_t offset, off_t nbytes)
120{
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
124 ", nbytes=%" PRIu64,
125 fd,
126 static_cast<uint64_t>(offset),
127 static_cast<uint64_t>(nbytes));
128 errno = ret;
129 }
130
131 return ret;
132}
133} /* namespace */
134
135#else /* HAVE_POSIX_FADVISE */
136
137/*
138 * Generic noop compat for platforms wihtout posix_fadvise, this is acceptable
139 * since we are only giving a hint to the kernel.
140 */
141namespace {
142int hint_dont_need(int fd __attribute__((unused)),
143 off_t offset __attribute__((unused)),
144 off_t nbytes __attribute__((unused)))
145{
146 return 0;
147}
148} /* namespace */
149#endif /* !HAVE_POSIX_FADVISE */
671e39d7
MJ
150
151/*
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
154 * disk.
155 */
156void lttng::io::hint_flush_range_dont_need_sync(int fd, off_t offset, off_t nbytes)
157{
158 /* Waited for the page writeback to complete. */
159 flush_range_sync(fd, offset, nbytes);
160
161 /*
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
164 * we write it.
165 *
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
168 * file.
169 *
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
173 * streaming.
174 */
e8955cc6 175 hint_dont_need(fd, offset, nbytes);
671e39d7
MJ
176}
177
178/*
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.
181 */
182void lttng::io::hint_flush_range_sync(int fd, off_t offset, off_t nbytes)
183{
184 flush_range_sync(fd, offset, nbytes);
185}
186
187/*
188 * Give a hint to the kernel that the data at the specified range should be
189 * flushed to disk and return immediatly.
190 */
191void lttng::io::hint_flush_range_async(int fd, off_t offset, off_t nbytes)
192{
193 flush_range_async(fd, offset, nbytes);
194}
This page took 0.03869 seconds and 4 git commands to generate.