1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <dirent.h> 18 #include <errno.h> 19 #include <fcntl.h> 20 #include <stdint.h> 21 #include <stdlib.h> 22 #include <sys/stat.h> 23 #include <sys/types.h> 24 #include <unistd.h> 25 26 #include <pagemap/pagemap.h> 27 28 int pm_kernel_create(pm_kernel_t **ker_out) { 29 pm_kernel_t *ker; 30 int error; 31 32 if (!ker_out) 33 return 1; 34 35 ker = calloc(1, sizeof(*ker)); 36 if (!ker) 37 return errno; 38 39 ker->kpagecount_fd = open("/proc/kpagecount", O_RDONLY); 40 if (ker->kpagecount_fd < 0) { 41 error = errno; 42 free(ker); 43 return error; 44 } 45 46 ker->kpageflags_fd = open("/proc/kpageflags", O_RDONLY); 47 if (ker->kpageflags_fd < 0) { 48 error = errno; 49 close(ker->kpagecount_fd); 50 free(ker); 51 return error; 52 } 53 54 ker->pagesize = getpagesize(); 55 56 *ker_out = ker; 57 58 return 0; 59 } 60 61 #define INIT_PIDS 20 62 int pm_kernel_pids(pm_kernel_t *ker, pid_t **pids_out, size_t *len) { 63 DIR *proc; 64 struct dirent *dir; 65 pid_t pid, *pids, *new_pids; 66 size_t pids_count, pids_size; 67 int error; 68 69 proc = opendir("/proc"); 70 if (!proc) 71 return errno; 72 73 pids = malloc(INIT_PIDS * sizeof(pid_t)); 74 if (!pids) { 75 closedir(proc); 76 return errno; 77 } 78 pids_count = 0; pids_size = INIT_PIDS; 79 80 while ((dir = readdir(proc))) { 81 if (sscanf(dir->d_name, "%d", &pid) < 1) 82 continue; 83 84 if (pids_count >= pids_size) { 85 new_pids = realloc(pids, 2 * pids_size * sizeof(pid_t)); 86 if (!new_pids) { 87 error = errno; 88 free(pids); 89 closedir(proc); 90 return error; 91 } 92 pids = new_pids; 93 pids_size = 2 * pids_size; 94 } 95 96 pids[pids_count] = pid; 97 98 pids_count++; 99 } 100 101 closedir(proc); 102 103 new_pids = realloc(pids, pids_count * sizeof(pid_t)); 104 if (!new_pids) { 105 error = errno; 106 free(pids); 107 return error; 108 } 109 110 *pids_out = new_pids; 111 *len = pids_count; 112 113 return 0; 114 } 115 116 int pm_kernel_count(pm_kernel_t *ker, unsigned long pfn, uint64_t *count_out) { 117 off_t off; 118 119 if (!ker || !count_out) 120 return -1; 121 122 off = lseek(ker->kpagecount_fd, pfn * sizeof(uint64_t), SEEK_SET); 123 if (off == (off_t)-1) 124 return errno; 125 if (read(ker->kpagecount_fd, count_out, sizeof(uint64_t)) < 126 (ssize_t)sizeof(uint64_t)) 127 return errno; 128 129 return 0; 130 } 131 132 int pm_kernel_flags(pm_kernel_t *ker, unsigned long pfn, uint64_t *flags_out) { 133 off_t off; 134 135 if (!ker || !flags_out) 136 return -1; 137 138 off = lseek(ker->kpageflags_fd, pfn * sizeof(uint64_t), SEEK_SET); 139 if (off == (off_t)-1) 140 return errno; 141 if (read(ker->kpageflags_fd, flags_out, sizeof(uint64_t)) < 142 (ssize_t)sizeof(uint64_t)) 143 return errno; 144 145 return 0; 146 } 147 148 int pm_kernel_destroy(pm_kernel_t *ker) { 149 if (!ker) 150 return -1; 151 152 close(ker->kpagecount_fd); 153 close(ker->kpageflags_fd); 154 155 free(ker); 156 157 return 0; 158 } 159