root/arch/um/os-Linux/mem.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. check_tmpfs
  2. choose_tempdir
  3. make_tempfile
  4. create_tmp_file
  5. create_mem_file
  6. check_tmpexec

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
   4  */
   5 
   6 #include <stdio.h>
   7 #include <stddef.h>
   8 #include <stdlib.h>
   9 #include <unistd.h>
  10 #include <errno.h>
  11 #include <fcntl.h>
  12 #include <string.h>
  13 #include <sys/stat.h>
  14 #include <sys/mman.h>
  15 #include <sys/vfs.h>
  16 #include <linux/magic.h>
  17 #include <init.h>
  18 #include <os.h>
  19 
  20 /* Set by make_tempfile() during early boot. */
  21 static char *tempdir = NULL;
  22 
  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)
  25 {
  26         struct statfs st;
  27 
  28         os_info("Checking if %s is on tmpfs...", dir);
  29         if (statfs(dir, &st) < 0) {
  30                 os_info("%s\n", strerror(errno));
  31         } else if (st.f_type != TMPFS_MAGIC) {
  32                 os_info("no\n");
  33         } else {
  34                 os_info("OK\n");
  35                 return 0;
  36         }
  37         return -1;
  38 }
  39 
  40 /*
  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.
  46  */
  47 static char * __init choose_tempdir(void)
  48 {
  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         };
  61         int i;
  62         const char *dir;
  63 
  64         os_info("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                         os_info("%s\n", dir);
  69                         if (check_tmpfs(dir) >= 0)
  70                                 goto done;
  71                         else
  72                                 goto warn;
  73                 }
  74         }
  75         os_info("none found\n");
  76 
  77         for (i = 0; tmpfs_dirs[i]; i++) {
  78                 dir = tmpfs_dirs[i];
  79                 if (check_tmpfs(dir) >= 0)
  80                         goto done;
  81         }
  82 
  83         dir = fallback_dir;
  84 warn:
  85         os_warn("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);
  89 }
  90 
  91 /*
  92  * Create an unlinked tempfile in a suitable tempdir. template must be the
  93  * basename part of the template with a leading '/'.
  94  */
  95 static int __init make_tempfile(const char *template)
  96 {
  97         char *tempname;
  98         int fd;
  99 
 100         if (tempdir == NULL) {
 101                 tempdir = choose_tempdir();
 102                 if (tempdir == NULL) {
 103                         os_warn("Failed to choose tempdir: %s\n",
 104                                 strerror(errno));
 105                         return -1;
 106                 }
 107         }
 108 
 109 #ifdef O_TMPFILE
 110         fd = open(tempdir, O_CLOEXEC | O_RDWR | O_EXCL | O_TMPFILE, 0700);
 111         /*
 112          * If the running system does not support O_TMPFILE flag then retry
 113          * without it.
 114          */
 115         if (fd != -1 || (errno != EINVAL && errno != EISDIR &&
 116                         errno != EOPNOTSUPP))
 117                 return fd;
 118 #endif
 119 
 120         tempname = malloc(strlen(tempdir) + strlen(template) + 1);
 121         if (tempname == NULL)
 122                 return -1;
 123 
 124         strcpy(tempname, tempdir);
 125         strcat(tempname, template);
 126         fd = mkstemp(tempname);
 127         if (fd < 0) {
 128                 os_warn("open - cannot create %s: %s\n", tempname,
 129                         strerror(errno));
 130                 goto out;
 131         }
 132         if (unlink(tempname) < 0) {
 133                 perror("unlink");
 134                 goto close;
 135         }
 136         free(tempname);
 137         return fd;
 138 close:
 139         close(fd);
 140 out:
 141         free(tempname);
 142         return -1;
 143 }
 144 
 145 #define TEMPNAME_TEMPLATE "/vm_file-XXXXXX"
 146 
 147 static int __init create_tmp_file(unsigned long long len)
 148 {
 149         int fd, err;
 150         char zero;
 151 
 152         fd = make_tempfile(TEMPNAME_TEMPLATE);
 153         if (fd < 0)
 154                 exit(1);
 155 
 156         /*
 157          * Seek to len - 1 because writing a character there will
 158          * increase the file size by one byte, to the desired length.
 159          */
 160         if (lseek64(fd, len - 1, SEEK_SET) < 0) {
 161                 perror("lseek64");
 162                 exit(1);
 163         }
 164 
 165         zero = 0;
 166 
 167         err = write(fd, &zero, 1);
 168         if (err != 1) {
 169                 perror("write");
 170                 exit(1);
 171         }
 172 
 173         return fd;
 174 }
 175 
 176 int __init create_mem_file(unsigned long long len)
 177 {
 178         int err, fd;
 179 
 180         fd = create_tmp_file(len);
 181 
 182         err = os_set_exec_close(fd);
 183         if (err < 0) {
 184                 errno = -err;
 185                 perror("exec_close");
 186         }
 187         return fd;
 188 }
 189 
 190 void __init check_tmpexec(void)
 191 {
 192         void *addr;
 193         int err, fd = create_tmp_file(UM_KERN_PAGE_SIZE);
 194 
 195         addr = mmap(NULL, UM_KERN_PAGE_SIZE,
 196                     PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0);
 197         os_info("Checking PROT_EXEC mmap in %s...", tempdir);
 198         if (addr == MAP_FAILED) {
 199                 err = errno;
 200                 os_warn("%s\n", strerror(err));
 201                 close(fd);
 202                 if (err == EPERM)
 203                         os_warn("%s must be not mounted noexec\n", tempdir);
 204                 exit(1);
 205         }
 206         os_info("OK\n");
 207         munmap(addr, UM_KERN_PAGE_SIZE);
 208 
 209         close(fd);
 210 }

/* [<][>][^][v][top][bottom][index][help] */