Home | History | Annotate | Download | only in libpagemap
      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