]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/readahead/readahead-common.c
relicense to LGPLv2.1 (with exceptions)
[thirdparty/systemd.git] / src / readahead / readahead-common.c
CommitLineData
22be093f
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
22be093f
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
22be093f 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
22be093f
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
22be093f
LP
23#include <stdlib.h>
24#include <string.h>
41a598e2 25#include <sys/sysinfo.h>
6624768c 26#include <sys/inotify.h>
d9c7a87b
LP
27#include <fcntl.h>
28#include <sys/mman.h>
29#include <unistd.h>
de58283f 30#include <libudev.h>
22be093f
LP
31
32#include "log.h"
33#include "readahead-common.h"
34#include "util.h"
35
8260358d 36int file_verify(int fd, const char *fn, off_t file_size_max, struct stat *st) {
22be093f
LP
37 assert(fd >= 0);
38 assert(fn);
39 assert(st);
40
41 if (fstat(fd, st) < 0) {
42 log_warning("fstat(%s) failed: %m", fn);
43 return -errno;
44 }
45
46 if (!S_ISREG(st->st_mode)) {
47 log_debug("Not preloading special file %s", fn);
48 return 0;
49 }
50
8260358d 51 if (st->st_size <= 0 || st->st_size > file_size_max) {
7607fea6 52 log_debug("Not preloading file %s with size out of bounds %llu", fn, (unsigned long long) st->st_size);
22be093f
LP
53 return 0;
54 }
55
56 return 1;
57}
58
59int fs_on_ssd(const char *p) {
60 struct stat st;
61 struct udev *udev = NULL;
62 struct udev_device *udev_device = NULL, *look_at = NULL;
63 bool b = false;
64 const char *devtype, *rotational, *model, *id;
65
66 assert(p);
67
68 if (stat(p, &st) < 0)
69 return -errno;
70
de58283f
LP
71 if (major(st.st_dev) == 0)
72 return false;
73
22be093f
LP
74 if (!(udev = udev_new()))
75 return -ENOMEM;
76
77 if (!(udev_device = udev_device_new_from_devnum(udev, 'b', st.st_dev)))
78 goto finish;
79
80 if ((devtype = udev_device_get_property_value(udev_device, "DEVTYPE")) &&
81 streq(devtype, "partition"))
82 look_at = udev_device_get_parent(udev_device);
83 else
84 look_at = udev_device;
85
86 if (!look_at)
87 goto finish;
88
89 /* First, try high-level property */
90 if ((id = udev_device_get_property_value(look_at, "ID_SSD"))) {
91 b = streq(id, "1");
92 goto finish;
93 }
94
95 /* Second, try kernel attribute */
96 if ((rotational = udev_device_get_sysattr_value(look_at, "queue/rotational")))
97 if ((b = streq(rotational, "0")))
98 goto finish;
99
100 /* Finally, fallback to heuristics */
101 if (!(look_at = udev_device_get_parent(look_at)))
102 goto finish;
103
104 if ((model = udev_device_get_sysattr_value(look_at, "model")))
105 b = !!strstr(model, "SSD");
106
107finish:
108 if (udev_device)
109 udev_device_unref(udev_device);
110
111 if (udev)
112 udev_unref(udev);
113
114 return b;
115}
41a598e2 116
2b590e13
LP
117int fs_on_read_only(const char *p) {
118 struct stat st;
119 struct udev *udev = NULL;
120 struct udev_device *udev_device = NULL;
121 bool b = false;
122 const char *read_only;
123
124 assert(p);
125
126 if (stat(p, &st) < 0)
127 return -errno;
128
129 if (major(st.st_dev) == 0)
130 return false;
131
132 if (!(udev = udev_new()))
133 return -ENOMEM;
134
135 if (!(udev_device = udev_device_new_from_devnum(udev, 'b', st.st_dev)))
136 goto finish;
137
138 if ((read_only = udev_device_get_sysattr_value(udev_device, "ro")))
139 if ((b = streq(read_only, "1")))
140 goto finish;
141
142finish:
143 if (udev_device)
144 udev_device_unref(udev_device);
145
146 if (udev)
147 udev_unref(udev);
148
149 return b;
150}
151
41a598e2
LP
152bool enough_ram(void) {
153 struct sysinfo si;
154
155 assert_se(sysinfo(&si) >= 0);
156
597b99b0
MS
157 /* Enable readahead only with at least 128MB memory */
158 return si.totalram > 127 * 1024*1024 / si.mem_unit;
41a598e2 159}
6624768c
LP
160
161int open_inotify(void) {
162 int fd;
163
164 if ((fd = inotify_init1(IN_CLOEXEC|IN_NONBLOCK)) < 0) {
165 log_error("Failed to create inotify handle: %m");
166 return -errno;
167 }
168
2b583ce6
KS
169 mkdir("/run/systemd", 0755);
170 mkdir("/run/systemd/readahead", 0755);
6624768c 171
2b583ce6
KS
172 if (inotify_add_watch(fd, "/run/systemd/readahead", IN_CREATE) < 0) {
173 log_error("Failed to watch /run/systemd/readahead: %m");
6624768c
LP
174 close_nointr_nofail(fd);
175 return -errno;
176 }
177
178 return fd;
179}
d9c7a87b
LP
180
181ReadaheadShared *shared_get(void) {
182 int fd;
183 ReadaheadShared *m = NULL;
184
2b583ce6
KS
185 mkdir("/run/systemd", 0755);
186 mkdir("/run/systemd/readahead", 0755);
43be5351 187
2b583ce6 188 if ((fd = open("/run/systemd/readahead/shared", O_CREAT|O_RDWR|O_CLOEXEC, 0644)) < 0) {
d9c7a87b
LP
189 log_error("Failed to create shared memory segment: %m");
190 goto finish;
191 }
192
193 if (ftruncate(fd, sizeof(ReadaheadShared)) < 0) {
194 log_error("Failed to truncate shared memory segment: %m");
195 goto finish;
196 }
197
198 if ((m = mmap(NULL, sizeof(ReadaheadShared), PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
199 log_error("Failed to mmap shared memory segment: %m");
200 m = NULL;
201 goto finish;
202 }
203
204finish:
205 if (fd >= 0)
206 close_nointr_nofail(fd);
207
208 return m;
209}
de58283f 210
de58283f
LP
211#define BUMP_REQUEST_NR (16*1024)
212
213int bump_request_nr(const char *p) {
214 struct stat st;
de58283f 215 uint64_t u;
b4454c5e 216 char *ap = NULL, *line = NULL;
de58283f 217 int r;
b4454c5e 218 dev_t d;
de58283f
LP
219
220 assert(p);
221
222 if (stat(p, &st) < 0)
223 return -errno;
224
225 if (major(st.st_dev) == 0)
226 return 0;
227
b4454c5e
LP
228 d = st.st_dev;
229 block_get_whole_disk(d, &d);
de58283f 230
b4454c5e
LP
231 if (asprintf(&ap, "/sys/dev/block/%u:%u/queue/nr_requests", major(d), minor(d)) < 0) {
232 r= -ENOMEM;
de58283f
LP
233 goto finish;
234 }
235
b4454c5e
LP
236 r = read_one_line_file(ap, &line);
237 if (r < 0) {
238 if (r == -ENOENT)
239 r = 0;
de58283f
LP
240 goto finish;
241 }
242
b4454c5e
LP
243 r = safe_atou64(line, &u);
244 if (r >= 0 && u >= BUMP_REQUEST_NR) {
de58283f
LP
245 r = 0;
246 goto finish;
247 }
248
b4454c5e
LP
249 free(line);
250 line = NULL;
251
252 if (asprintf(&line, "%lu", (unsigned long) BUMP_REQUEST_NR) < 0) {
de58283f
LP
253 r = -ENOMEM;
254 goto finish;
255 }
256
b4454c5e
LP
257 r = write_one_line_file(ap, line);
258 if (r < 0)
de58283f
LP
259 goto finish;
260
b4454c5e 261 log_info("Bumped block_nr parameter of %u:%u to %lu. This is a temporary hack and should be removed one day.", major(d), minor(d), (unsigned long) BUMP_REQUEST_NR);
de58283f
LP
262 r = 1;
263
264finish:
de58283f 265 free(ap);
b4454c5e 266 free(line);
de58283f
LP
267
268 return r;
269}