Remove fcntl wrapper
[lttng-tools.git] / src / common / io-hint.cpp
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
24 namespace {
25 int 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
42 int 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
51 int 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
57 #else
58
59 namespace {
60 /*
61 * Use a memory mapping with msync() to emulate sync_file_range().
62 */
63 int 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
102 int flush_range_sync(int fd, off_t offset, off_t nbytes)
103 {
104 return flush_range(fd, offset, nbytes, MS_SYNC);
105 }
106
107 int flush_range_async(int fd, off_t offset, off_t nbytes)
108 {
109 return flush_range(fd, offset, nbytes, MS_ASYNC);
110 }
111 } /* namespace */
112 #endif
113
114 /*
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
117 * disk.
118 */
119 void lttng::io::hint_flush_range_dont_need_sync(int fd, off_t offset, off_t nbytes)
120 {
121 /* Waited for the page writeback to complete. */
122 flush_range_sync(fd, offset, nbytes);
123
124 /*
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
127 * we write it.
128 *
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
131 * file.
132 *
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
136 * streaming.
137 */
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
141 ", nbytes=%" PRIu64,
142 fd,
143 static_cast<uint64_t>(offset),
144 static_cast<uint64_t>(nbytes));
145 errno = ret;
146 }
147 }
148
149 /*
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.
152 */
153 void lttng::io::hint_flush_range_sync(int fd, off_t offset, off_t nbytes)
154 {
155 flush_range_sync(fd, offset, nbytes);
156 }
157
158 /*
159 * Give a hint to the kernel that the data at the specified range should be
160 * flushed to disk and return immediatly.
161 */
162 void lttng::io::hint_flush_range_async(int fd, off_t offset, off_t nbytes)
163 {
164 flush_range_async(fd, offset, nbytes);
165 }
This page took 0.039591 seconds and 4 git commands to generate.