Commit c089b229dfdd09d59a11d8bc2344bf8196d575ce

Authored by Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml

Pull UML fixes from Richard Weinberger:
 "Assorted fixes for UML"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml:
  um: Memory corruption on startup
  um: Missing pipe handling
  uml: Simplify tempdir logic.

Showing 5 changed files Side-by-side Diff

arch/um/include/shared/os.h
... ... @@ -136,6 +136,7 @@
136 136 extern int os_get_ifname(int fd, char *namebuf);
137 137 extern int os_set_slip(int fd);
138 138 extern int os_mode_fd(int fd, int mode);
  139 +extern int os_fsync_file(int fd);
139 140  
140 141 extern int os_seek_file(int fd, unsigned long long offset);
141 142 extern int os_open_file(const char *file, struct openflags flags, int mode);
arch/um/kernel/physmem.c
... ... @@ -103,6 +103,7 @@
103 103 */
104 104 os_seek_file(physmem_fd, __pa(&__syscall_stub_start));
105 105 os_write_file(physmem_fd, &__syscall_stub_start, PAGE_SIZE);
  106 + os_fsync_file(physmem_fd);
106 107  
107 108 bootmap_size = init_bootmem(pfn, pfn + delta);
108 109 free_bootmem(__pa(reserve_end) + bootmap_size,
arch/um/os-Linux/file.c
... ... @@ -237,6 +237,12 @@
237 237 {
238 238 close(fd);
239 239 }
  240 +int os_fsync_file(int fd)
  241 +{
  242 + if (fsync(fd) < 0)
  243 + return -errno;
  244 + return 0;
  245 +}
240 246  
241 247 int os_seek_file(int fd, unsigned long long offset)
242 248 {
arch/um/os-Linux/main.c
... ... @@ -151,6 +151,7 @@
151 151 #endif
152 152  
153 153 do_uml_initcalls();
  154 + change_sig(SIGPIPE, 0);
154 155 ret = linux_main(argc, argv);
155 156  
156 157 /*
arch/um/os-Linux/mem.c
... ... @@ -12,337 +12,117 @@
12 12 #include <string.h>
13 13 #include <sys/stat.h>
14 14 #include <sys/mman.h>
15   -#include <sys/param.h>
  15 +#include <sys/vfs.h>
  16 +#include <linux/magic.h>
16 17 #include <init.h>
17 18 #include <os.h>
18 19  
19   -/* Modified by which_tmpdir, which is called during early boot */
20   -static char *default_tmpdir = "/tmp";
21   -
22   -/*
23   - * Modified when creating the physical memory file and when checking
24   - * the tmp filesystem for usability, both happening during early boot.
25   - */
  20 +/* Set by make_tempfile() during early boot. */
26 21 static char *tempdir = NULL;
27 22  
28   -static void __init find_tempdir(void)
  23 +/* Check if dir is on tmpfs. Return 0 if yes, -1 if no or error. */
  24 +static int __init check_tmpfs(const char *dir)
29 25 {
30   - const char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL };
31   - int i;
32   - char *dir = NULL;
  26 + struct statfs st;
33 27  
34   - if (tempdir != NULL)
35   - /* We've already been called */
36   - return;
37   - for (i = 0; dirs[i]; i++) {
38   - dir = getenv(dirs[i]);
39   - if ((dir != NULL) && (*dir != '\0'))
40   - break;
  28 + printf("Checking if %s is on tmpfs...", dir);
  29 + if (statfs(dir, &st) < 0) {
  30 + printf("%s\n", strerror(errno));
  31 + } else if (st.f_type != TMPFS_MAGIC) {
  32 + printf("no\n");
  33 + } else {
  34 + printf("OK\n");
  35 + return 0;
41 36 }
42   - if ((dir == NULL) || (*dir == '\0'))
43   - dir = default_tmpdir;
44   -
45   - tempdir = malloc(strlen(dir) + 2);
46   - if (tempdir == NULL) {
47   - fprintf(stderr, "Failed to malloc tempdir, "
48   - "errno = %d\n", errno);
49   - return;
50   - }
51   - strcpy(tempdir, dir);
52   - strcat(tempdir, "/");
  37 + return -1;
53 38 }
54 39  
55 40 /*
56   - * Remove bytes from the front of the buffer and refill it so that if there's a
57   - * partial string that we care about, it will be completed, and we can recognize
58   - * it.
  41 + * Choose the tempdir to use. We want something on tmpfs so that our memory is
  42 + * not subject to the host's vm.dirty_ratio. If a tempdir is specified in the
  43 + * environment, we use that even if it's not on tmpfs, but we warn the user.
  44 + * Otherwise, we try common tmpfs locations, and if no tmpfs directory is found
  45 + * then we fall back to /tmp.
59 46 */
60   -static int pop(int fd, char *buf, size_t size, size_t npop)
  47 +static char * __init choose_tempdir(void)
61 48 {
62   - ssize_t n;
63   - size_t len = strlen(&buf[npop]);
64   -
65   - memmove(buf, &buf[npop], len + 1);
66   - n = read(fd, &buf[len], size - len - 1);
67   - if (n < 0)
68   - return -errno;
69   -
70   - buf[len + n] = '\0';
71   - return 1;
72   -}
73   -
74   -/*
75   - * This will return 1, with the first character in buf being the
76   - * character following the next instance of c in the file. This will
77   - * read the file as needed. If there's an error, -errno is returned;
78   - * if the end of the file is reached, 0 is returned.
79   - */
80   -static int next(int fd, char *buf, size_t size, char c)
81   -{
82   - ssize_t n;
83   - char *ptr;
84   -
85   - while ((ptr = strchr(buf, c)) == NULL) {
86   - n = read(fd, buf, size - 1);
87   - if (n == 0)
88   - return 0;
89   - else if (n < 0)
90   - return -errno;
91   -
92   - buf[n] = '\0';
93   - }
94   -
95   - return pop(fd, buf, size, ptr - buf + 1);
96   -}
97   -
98   -/*
99   - * Decode an octal-escaped and space-terminated path of the form used by
100   - * /proc/mounts. May be used to decode a path in-place. "out" must be at least
101   - * as large as the input. The output is always null-terminated. "len" gets the
102   - * length of the output, excluding the trailing null. Returns 0 if a full path
103   - * was successfully decoded, otherwise an error.
104   - */
105   -static int decode_path(const char *in, char *out, size_t *len)
106   -{
107   - char *first = out;
108   - int c;
  49 + static const char * const vars[] = {
  50 + "TMPDIR",
  51 + "TMP",
  52 + "TEMP",
  53 + NULL
  54 + };
  55 + static const char fallback_dir[] = "/tmp";
  56 + static const char * const tmpfs_dirs[] = {
  57 + "/dev/shm",
  58 + fallback_dir,
  59 + NULL
  60 + };
109 61 int i;
110   - int ret = -EINVAL;
111   - while (1) {
112   - switch (*in) {
113   - case '\0':
114   - goto out;
  62 + const char *dir;
115 63  
116   - case ' ':
117   - ret = 0;
118   - goto out;
119   -
120   - case '\\':
121   - in++;
122   - c = 0;
123   - for (i = 0; i < 3; i++) {
124   - if (*in < '0' || *in > '7')
125   - goto out;
126   - c = (c << 3) | (*in++ - '0');
127   - }
128   - *(unsigned char *)out++ = (unsigned char) c;
129   - break;
130   -
131   - default:
132   - *out++ = *in++;
133   - break;
  64 + printf("Checking environment variables for a tempdir...");
  65 + for (i = 0; vars[i]; i++) {
  66 + dir = getenv(vars[i]);
  67 + if ((dir != NULL) && (*dir != '\0')) {
  68 + printf("%s\n", dir);
  69 + if (check_tmpfs(dir) >= 0)
  70 + goto done;
  71 + else
  72 + goto warn;
134 73 }
135 74 }
  75 + printf("none found\n");
136 76  
137   -out:
138   - *out = '\0';
139   - *len = out - first;
140   - return ret;
141   -}
142   -
143   -/*
144   - * Computes the length of s when encoded with three-digit octal escape sequences
145   - * for the characters in chars.
146   - */
147   -static size_t octal_encoded_length(const char *s, const char *chars)
148   -{
149   - size_t len = strlen(s);
150   - while ((s = strpbrk(s, chars)) != NULL) {
151   - len += 3;
152   - s++;
  77 + for (i = 0; tmpfs_dirs[i]; i++) {
  78 + dir = tmpfs_dirs[i];
  79 + if (check_tmpfs(dir) >= 0)
  80 + goto done;
153 81 }
154 82  
155   - return len;
  83 + dir = fallback_dir;
  84 +warn:
  85 + printf("Warning: tempdir %s is not on tmpfs\n", dir);
  86 +done:
  87 + /* Make a copy since getenv results may not remain valid forever. */
  88 + return strdup(dir);
156 89 }
157 90  
158   -enum {
159   - OUTCOME_NOTHING_MOUNTED,
160   - OUTCOME_TMPFS_MOUNT,
161   - OUTCOME_NON_TMPFS_MOUNT,
162   -};
163   -
164   -/* Read a line of /proc/mounts data looking for a tmpfs mount at "path". */
165   -static int read_mount(int fd, char *buf, size_t bufsize, const char *path,
166   - int *outcome)
167   -{
168   - int found;
169   - int match;
170   - char *space;
171   - size_t len;
172   -
173   - enum {
174   - MATCH_NONE,
175   - MATCH_EXACT,
176   - MATCH_PARENT,
177   - };
178   -
179   - found = next(fd, buf, bufsize, ' ');
180   - if (found != 1)
181   - return found;
182   -
183   - /*
184   - * If there's no following space in the buffer, then this path is
185   - * truncated, so it can't be the one we're looking for.
186   - */
187   - space = strchr(buf, ' ');
188   - if (space) {
189   - match = MATCH_NONE;
190   - if (!decode_path(buf, buf, &len)) {
191   - if (!strcmp(buf, path))
192   - match = MATCH_EXACT;
193   - else if (!strncmp(buf, path, len)
194   - && (path[len] == '/' || !strcmp(buf, "/")))
195   - match = MATCH_PARENT;
196   - }
197   -
198   - found = pop(fd, buf, bufsize, space - buf + 1);
199   - if (found != 1)
200   - return found;
201   -
202   - switch (match) {
203   - case MATCH_EXACT:
204   - if (!strncmp(buf, "tmpfs", strlen("tmpfs")))
205   - *outcome = OUTCOME_TMPFS_MOUNT;
206   - else
207   - *outcome = OUTCOME_NON_TMPFS_MOUNT;
208   - break;
209   -
210   - case MATCH_PARENT:
211   - /* This mount obscures any previous ones. */
212   - *outcome = OUTCOME_NOTHING_MOUNTED;
213   - break;
214   - }
215   - }
216   -
217   - return next(fd, buf, bufsize, '\n');
218   -}
219   -
220   -/* which_tmpdir is called only during early boot */
221   -static int checked_tmpdir = 0;
222   -
223 91 /*
224   - * Look for a tmpfs mounted at /dev/shm. I couldn't find a cleaner
225   - * way to do this than to parse /proc/mounts. statfs will return the
226   - * same filesystem magic number and fs id for both /dev and /dev/shm
227   - * when they are both tmpfs, so you can't tell if they are different
228   - * filesystems. Also, there seems to be no other way of finding the
229   - * mount point of a filesystem from within it.
230   - *
231   - * If a /dev/shm tmpfs entry is found, then we switch to using it.
232   - * Otherwise, we stay with the default /tmp.
  92 + * Create an unlinked tempfile in a suitable tempdir. template must be the
  93 + * basename part of the template with a leading '/'.
233 94 */
234   -static void which_tmpdir(void)
  95 +static int __init make_tempfile(const char *template)
235 96 {
  97 + char *tempname;
236 98 int fd;
237   - int found;
238   - int outcome;
239   - char *path;
240   - char *buf;
241   - size_t bufsize;
242 99  
243   - if (checked_tmpdir)
244   - return;
245   -
246   - checked_tmpdir = 1;
247   -
248   - printf("Checking for tmpfs mount on /dev/shm...");
249   -
250   - path = realpath("/dev/shm", NULL);
251   - if (!path) {
252   - printf("failed to check real path, errno = %d\n", errno);
253   - return;
254   - }
255   - printf("%s...", path);
256   -
257   - /*
258   - * The buffer needs to be able to fit the full octal-escaped path, a
259   - * space, and a trailing null in order to successfully decode it.
260   - */
261   - bufsize = octal_encoded_length(path, " \t\n\\") + 2;
262   -
263   - if (bufsize < 128)
264   - bufsize = 128;
265   -
266   - buf = malloc(bufsize);
267   - if (!buf) {
268   - printf("malloc failed, errno = %d\n", errno);
269   - goto out;
270   - }
271   - buf[0] = '\0';
272   -
273   - fd = open("/proc/mounts", O_RDONLY);
274   - if (fd < 0) {
275   - printf("failed to open /proc/mounts, errno = %d\n", errno);
276   - goto out1;
277   - }
278   -
279   - outcome = OUTCOME_NOTHING_MOUNTED;
280   - while (1) {
281   - found = read_mount(fd, buf, bufsize, path, &outcome);
282   - if (found != 1)
283   - break;
284   - }
285   -
286   - if (found < 0) {
287   - printf("read returned errno %d\n", -found);
288   - } else {
289   - switch (outcome) {
290   - case OUTCOME_TMPFS_MOUNT:
291   - printf("OK\n");
292   - default_tmpdir = "/dev/shm";
293   - break;
294   -
295   - case OUTCOME_NON_TMPFS_MOUNT:
296   - printf("not tmpfs\n");
297   - break;
298   -
299   - default:
300   - printf("nothing mounted on /dev/shm\n");
301   - break;
  100 + if (tempdir == NULL) {
  101 + tempdir = choose_tempdir();
  102 + if (tempdir == NULL) {
  103 + fprintf(stderr, "Failed to choose tempdir: %s\n",
  104 + strerror(errno));
  105 + return -1;
302 106 }
303 107 }
304 108  
305   - close(fd);
306   -out1:
307   - free(buf);
308   -out:
309   - free(path);
310   -}
311   -
312   -static int __init make_tempfile(const char *template, char **out_tempname,
313   - int do_unlink)
314   -{
315   - char *tempname;
316   - int fd;
317   -
318   - which_tmpdir();
319   - tempname = malloc(MAXPATHLEN);
  109 + tempname = malloc(strlen(tempdir) + strlen(template) + 1);
320 110 if (tempname == NULL)
321 111 return -1;
322 112  
323   - find_tempdir();
324   - if ((tempdir == NULL) || (strlen(tempdir) >= MAXPATHLEN))
325   - goto out;
326   -
327   - if (template[0] != '/')
328   - strcpy(tempname, tempdir);
329   - else
330   - tempname[0] = '\0';
331   - strncat(tempname, template, MAXPATHLEN-1-strlen(tempname));
  113 + strcpy(tempname, tempdir);
  114 + strcat(tempname, template);
332 115 fd = mkstemp(tempname);
333 116 if (fd < 0) {
334 117 fprintf(stderr, "open - cannot create %s: %s\n", tempname,
335 118 strerror(errno));
336 119 goto out;
337 120 }
338   - if (do_unlink && (unlink(tempname) < 0)) {
  121 + if (unlink(tempname) < 0) {
339 122 perror("unlink");
340 123 goto close;
341 124 }
342   - if (out_tempname) {
343   - *out_tempname = tempname;
344   - } else
345   - free(tempname);
  125 + free(tempname);
346 126 return fd;
347 127 close:
348 128 close(fd);
349 129  
... ... @@ -351,14 +131,14 @@
351 131 return -1;
352 132 }
353 133  
354   -#define TEMPNAME_TEMPLATE "vm_file-XXXXXX"
  134 +#define TEMPNAME_TEMPLATE "/vm_file-XXXXXX"
355 135  
356 136 static int __init create_tmp_file(unsigned long long len)
357 137 {
358 138 int fd, err;
359 139 char zero;
360 140  
361   - fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1);
  141 + fd = make_tempfile(TEMPNAME_TEMPLATE);
362 142 if (fd < 0)
363 143 exit(1);
364 144  
... ... @@ -402,7 +182,6 @@
402 182 return fd;
403 183 }
404 184  
405   -
406 185 void __init check_tmpexec(void)
407 186 {
408 187 void *addr;
409 188  
410 189  
... ... @@ -410,14 +189,13 @@
410 189  
411 190 addr = mmap(NULL, UM_KERN_PAGE_SIZE,
412 191 PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0);
413   - printf("Checking PROT_EXEC mmap in %s...",tempdir);
414   - fflush(stdout);
  192 + printf("Checking PROT_EXEC mmap in %s...", tempdir);
415 193 if (addr == MAP_FAILED) {
416 194 err = errno;
417   - perror("failed");
  195 + printf("%s\n", strerror(err));
418 196 close(fd);
419 197 if (err == EPERM)
420   - printf("%s must be not mounted noexec\n",tempdir);
  198 + printf("%s must be not mounted noexec\n", tempdir);
421 199 exit(1);
422 200 }
423 201 printf("OK\n");