LCOV - code coverage report
Current view: top level - home/snorch/criu - fsnotify.c (source / functions) Hit Total Coverage
Test: coverage3.info Lines: 191 241 79.3 %
Date: 2014-04-22 Functions: 25 25 100.0 %
Branches: 65 118 55.1 %

           Branch data     Line data    Source code
       1                 :            : #include <unistd.h>
       2                 :            : #include <stdio.h>
       3                 :            : #include <stdlib.h>
       4                 :            : #include <errno.h>
       5                 :            : #include <fcntl.h>
       6                 :            : #include <stdlib.h>
       7                 :            : #include <signal.h>
       8                 :            : #include <string.h>
       9                 :            : #include <utime.h>
      10                 :            : #include <dirent.h>
      11                 :            : #include <limits.h>
      12                 :            : #include <sys/stat.h>
      13                 :            : #include <sys/types.h>
      14                 :            : #include <sys/inotify.h>
      15                 :            : #include <sys/vfs.h>
      16                 :            : #include <linux/magic.h>
      17                 :            : #include <sys/wait.h>
      18                 :            : #include <sys/poll.h>
      19                 :            : #include <sys/mman.h>
      20                 :            : #include <sys/mount.h>
      21                 :            : #include <aio.h>
      22                 :            : 
      23                 :            : #include <linux/fanotify.h>
      24                 :            : 
      25                 :            : #include "compiler.h"
      26                 :            : #include "asm/types.h"
      27                 :            : #include "fdset.h"
      28                 :            : #include "fsnotify.h"
      29                 :            : #include "proc_parse.h"
      30                 :            : #include "syscall.h"
      31                 :            : #include "mount.h"
      32                 :            : #include "image.h"
      33                 :            : #include "util.h"
      34                 :            : #include "files.h"
      35                 :            : #include "files-reg.h"
      36                 :            : #include "file-ids.h"
      37                 :            : #include "log.h"
      38                 :            : #include "list.h"
      39                 :            : #include "lock.h"
      40                 :            : #include "irmap.h"
      41                 :            : #include "cr_options.h"
      42                 :            : 
      43                 :            : #include "protobuf.h"
      44                 :            : #include "protobuf/fsnotify.pb-c.h"
      45                 :            : #include "protobuf/mnt.pb-c.h"
      46                 :            : 
      47                 :            : #undef  LOG_PREFIX
      48                 :            : #define LOG_PREFIX "fsnotify: "
      49                 :            : 
      50                 :            : struct fsnotify_mark_info {
      51                 :            :         struct list_head                list;
      52                 :            :         union {
      53                 :            :                 InotifyWdEntry          *iwe;
      54                 :            :                 FanotifyMarkEntry       *fme;
      55                 :            :         };
      56                 :            :         struct file_remap               *remap;
      57                 :            : };
      58                 :            : 
      59                 :            : struct fsnotify_file_info {
      60                 :            :         struct list_head                list;
      61                 :            :         union {
      62                 :            :                 InotifyFileEntry        *ife;
      63                 :            :                 FanotifyFileEntry       *ffe;
      64                 :            :         };
      65                 :            :         struct list_head                marks;
      66                 :            :         struct file_desc                d;
      67                 :            : };
      68                 :            : 
      69                 :            : /* File handle */
      70                 :            : typedef struct {
      71                 :            :         u32 bytes;
      72                 :            :         u32 type;
      73                 :            :         u64 __handle[16];
      74                 :            : } fh_t;
      75                 :            : 
      76                 :            : static LIST_HEAD(inotify_info_head);
      77                 :            : static LIST_HEAD(fanotify_info_head);
      78                 :            : 
      79                 :            : /* Checks if file descriptor @lfd is inotify */
      80                 :      17067 : int is_inotify_link(char *link)
      81                 :            : {
      82                 :      17067 :         return is_anon_link_type(link, "inotify");
      83                 :            : }
      84                 :            : 
      85                 :            : /* Checks if file descriptor @lfd is fanotify */
      86                 :      17051 : int is_fanotify_link(char *link)
      87                 :            : {
      88                 :      17051 :         return is_anon_link_type(link, "[fanotify]");
      89                 :            : }
      90                 :            : 
      91                 :         52 : static void decode_handle(fh_t *handle, FhEntry *img)
      92                 :            : {
      93                 :            :         memzero(handle, sizeof(*handle));
      94                 :            : 
      95                 :         52 :         handle->type = img->type;
      96                 :         52 :         handle->bytes        = img->bytes;
      97                 :            : 
      98                 :         52 :         memcpy(handle->__handle, img->handle,
      99                 :         52 :                         min(pb_repeated_size(img, handle),
     100                 :            :                                 sizeof(handle->__handle)));
     101                 :         52 : }
     102                 :            : 
     103                 :         52 : static int open_handle(unsigned int s_dev, unsigned long i_ino,
     104                 :            :                 FhEntry *f_handle)
     105                 :            : {
     106                 :            :         int mntfd, fd = -1;
     107                 :            :         fh_t handle;
     108                 :            : 
     109                 :         52 :         decode_handle(&handle, f_handle);
     110                 :            : 
     111                 :         52 :         pr_debug("Opening fhandle %x:%Lx...\n",
     112                 :            :                         s_dev, (unsigned long long)handle.__handle[0]);
     113                 :            : 
     114                 :         52 :         mntfd = open_mount(s_dev);
     115         [ -  + ]:         52 :         if (mntfd < 0) {
     116                 :          0 :                 pr_perror("Mount root for 0x%08x not found\n", s_dev);
     117                 :          0 :                 goto out;
     118                 :            :         }
     119                 :            : 
     120                 :         52 :         fd = sys_open_by_handle_at(mntfd, (void *)&handle, O_PATH);
     121         [ -  + ]:         52 :         if (fd < 0) {
     122                 :          0 :                 errno = -fd;
     123                 :          0 :                 pr_perror("Can't open file handle for 0x%08x:0x%016lx",
     124                 :            :                                 s_dev, i_ino);
     125                 :            :         }
     126                 :            : 
     127                 :         52 :         close(mntfd);
     128                 :            : out:
     129                 :         52 :         return fd;
     130                 :            : }
     131                 :            : 
     132                 :         48 : int check_open_handle(unsigned int s_dev, unsigned long i_ino,
     133                 :            :                 FhEntry *f_handle)
     134                 :            : {
     135                 :         48 :         int fd = -1;
     136                 :            :         char *path;
     137                 :            : 
     138                 :         48 :         fd = open_handle(s_dev, i_ino, f_handle);
     139         [ +  - ]:         48 :         if (fd >= 0) {
     140                 :            :                 struct mount_info *mi;
     141                 :            : 
     142                 :         48 :                 pr_debug("\tHandle %x:%lx is openable\n", s_dev, i_ino);
     143                 :            : 
     144                 :         48 :                 mi = lookup_mnt_sdev(s_dev);
     145         [ -  + ]:         48 :                 if (mi == NULL) {
     146                 :          0 :                         pr_err("Unable to lookup a mount by dev %x\n", s_dev);
     147                 :          0 :                         goto err;
     148                 :            :                 }
     149                 :            : 
     150                 :            :                 /*
     151                 :            :                  * Inode numbers are not restored for tmpfs content, but we can
     152                 :            :                  * get file names, becasue tmpfs cache is not pruned.
     153                 :            :                  */
     154         [ -  + ]:         48 :                 if ((mi->fstype->code == FSTYPE__TMPFS) ||
     155                 :            :                                 (mi->fstype->code == FSTYPE__DEVTMPFS)) {
     156                 :            :                         char p[PATH_MAX];
     157                 :            : 
     158         [ #  # ]:          0 :                         if (read_fd_link(fd, p, sizeof(p)) < 0)
     159                 :            :                                 goto err;
     160                 :            : 
     161         [ #  # ]:          0 :                         path = xstrdup(p);
     162         [ #  # ]:          0 :                         if (path == NULL)
     163                 :            :                                 goto err;
     164                 :            : 
     165                 :          0 :                         goto out;
     166                 :            :                 }
     167                 :            : 
     168         [ -  + ]:         48 :                 if (!opts.force_irmap)
     169                 :            :                         /*
     170                 :            :                          * If we're not forced to do irmap, then
     171                 :            :                          * say we have no path for watch. Otherwise
     172                 :            :                          * do irmap scan even if the handle is
     173                 :            :                          * working.
     174                 :            :                          *
     175                 :            :                          * FIXME -- no need to open-by-handle if
     176                 :            :                          * we are in force-irmap and not on tempfs
     177                 :            :                          */
     178                 :            :                         goto out_nopath;
     179                 :            :         }
     180                 :            : 
     181                 :          0 :         pr_warn("\tHandle %x:%lx cannot be opened\n", s_dev, i_ino);
     182                 :          0 :         path = irmap_lookup(s_dev, i_ino);
     183         [ #  # ]:          0 :         if (!path) {
     184                 :          0 :                 pr_err("\tCan't dump that handle\n");
     185                 :          0 :                 return -1;
     186                 :            :         }
     187                 :            : out:
     188                 :          0 :         pr_debug("\tDumping %s as path for handle\n", path);
     189                 :          0 :         f_handle->path = path;
     190                 :            : out_nopath:
     191                 :         48 :         close_safe(&fd);
     192                 :         48 :         return 0;
     193                 :            : err:
     194                 :          0 :         close_safe(&fd);
     195                 :          0 :         return -1;
     196                 :            : }
     197                 :            : 
     198                 :          8 : static int dump_inotify_entry(union fdinfo_entries *e, void *arg)
     199                 :            : {
     200                 :          8 :         InotifyWdEntry *we = &e->ify;
     201                 :            : 
     202                 :          8 :         we->id = *(u32 *)arg;
     203                 :          8 :         pr_info("wd: wd 0x%08x s_dev 0x%08x i_ino 0x%16"PRIx64" mask 0x%08x\n",
     204                 :            :                         we->wd, we->s_dev, we->i_ino, we->mask);
     205                 :          8 :         pr_info("\t[fhandle] bytes 0x%08x type 0x%08x __handle 0x%016"PRIx64":0x%016"PRIx64"\n",
     206                 :            :                         we->f_handle->bytes, we->f_handle->type,
     207                 :            :                         we->f_handle->handle[0], we->f_handle->handle[1]);
     208                 :            : 
     209         [ +  - ]:          8 :         if (check_open_handle(we->s_dev, we->i_ino, we->f_handle))
     210                 :            :                 return -1;
     211                 :            : 
     212                 :          8 :         return pb_write_one(fdset_fd(glob_fdset, CR_FD_INOTIFY_WD), we, PB_INOTIFY_WD);
     213                 :            : }
     214                 :            : 
     215                 :          4 : static int dump_one_inotify(int lfd, u32 id, const struct fd_parms *p)
     216                 :            : {
     217                 :          4 :         InotifyFileEntry ie = INOTIFY_FILE_ENTRY__INIT;
     218                 :            : 
     219                 :          4 :         ie.id = id;
     220                 :          4 :         ie.flags = p->flags;
     221                 :          4 :         ie.fown = (FownEntry *)&p->fown;
     222                 :            : 
     223                 :          4 :         pr_info("id 0x%08x flags 0x%08x\n", ie.id, ie.flags);
     224         [ +  - ]:          4 :         if (pb_write_one(fdset_fd(glob_fdset, CR_FD_INOTIFY_FILE), &ie, PB_INOTIFY_FILE))
     225                 :            :                 return -1;
     226                 :            : 
     227                 :          4 :         return parse_fdinfo(lfd, FD_TYPES__INOTIFY, dump_inotify_entry, &id);
     228                 :            : }
     229                 :            : 
     230                 :         24 : static int pre_dump_inotify_entry(union fdinfo_entries *e, void *arg)
     231                 :            : {
     232                 :            :         InotifyWdEntry *we = &e->ify;
     233                 :         24 :         return irmap_queue_cache(we->s_dev, we->i_ino, we->f_handle);
     234                 :            : }
     235                 :            : 
     236                 :         12 : static int pre_dump_one_inotify(int pid, int lfd)
     237                 :            : {
     238                 :         12 :         return parse_fdinfo_pid(pid, lfd, FD_TYPES__INOTIFY, pre_dump_inotify_entry, NULL);
     239                 :            : }
     240                 :            : 
     241                 :            : const struct fdtype_ops inotify_dump_ops = {
     242                 :            :         .type           = FD_TYPES__INOTIFY,
     243                 :            :         .dump           = dump_one_inotify,
     244                 :            :         .pre_dump       = pre_dump_one_inotify,
     245                 :            : };
     246                 :            : 
     247                 :          8 : static int dump_fanotify_entry(union fdinfo_entries *e, void *arg)
     248                 :            : {
     249                 :            :         struct fsnotify_params *fsn_params = arg;
     250                 :          8 :         FanotifyMarkEntry *fme = &e->ffy;
     251                 :            : 
     252                 :          8 :         fme->id = fsn_params->id;
     253                 :            : 
     254         [ +  + ]:          8 :         if (fme->type == MARK_TYPE__INODE) {
     255                 :            : 
     256         [ -  + ]:          4 :                 BUG_ON(!fme->ie);
     257                 :            : 
     258                 :          4 :                 pr_info("mark: s_dev 0x%08x i_ino 0x%016"PRIx64" mask 0x%08x\n",
     259                 :            :                         fme->s_dev, fme->ie->i_ino, fme->mask);
     260                 :            : 
     261                 :          4 :                 pr_info("\t[fhandle] bytes 0x%08x type 0x%08x __handle 0x%016"PRIx64":0x%016"PRIx64"\n",
     262                 :            :                         fme->ie->f_handle->bytes, fme->ie->f_handle->type,
     263                 :            :                         fme->ie->f_handle->handle[0], fme->ie->f_handle->handle[1]);
     264                 :            : 
     265         [ +  - ]:          4 :                 if (check_open_handle(fme->s_dev, fme->ie->i_ino, fme->ie->f_handle))
     266                 :            :                         return -1;
     267                 :            :         }
     268                 :            : 
     269         [ +  + ]:          8 :         if (fme->type == MARK_TYPE__MOUNT) {
     270                 :            :                 struct mount_info *m;
     271                 :            : 
     272         [ -  + ]:          4 :                 BUG_ON(!fme->me);
     273                 :            : 
     274                 :          4 :                 m = lookup_mnt_id(fme->me->mnt_id);
     275         [ -  + ]:          4 :                 if (!m) {
     276                 :          0 :                         pr_err("Can't find mnt_id %x\n", fme->me->mnt_id);
     277                 :          0 :                         return -1;
     278                 :            :                 }
     279                 :          4 :                 fme->s_dev = m->s_dev;
     280                 :            : 
     281                 :          4 :                 pr_info("mark: s_dev 0x%08x mnt_id  0x%08x mask 0x%08x\n",
     282                 :            :                         fme->s_dev, fme->me->mnt_id, fme->mask);
     283                 :            : 
     284                 :            :         }
     285                 :            : 
     286                 :          8 :         return pb_write_one(fdset_fd(glob_fdset, CR_FD_FANOTIFY_MARK), fme, PB_FANOTIFY_MARK);
     287                 :            : }
     288                 :            : 
     289                 :          4 : static int dump_one_fanotify(int lfd, u32 id, const struct fd_parms *p)
     290                 :            : {
     291                 :          4 :         FanotifyFileEntry fe = FANOTIFY_FILE_ENTRY__INIT;
     292                 :          4 :         struct fsnotify_params fsn_params = { .id = id, };
     293                 :            : 
     294                 :          4 :         fe.id = id;
     295                 :          4 :         fe.flags = p->flags;
     296                 :          4 :         fe.fown = (FownEntry *)&p->fown;
     297                 :            : 
     298         [ +  - ]:          4 :         if (parse_fdinfo(lfd, FD_TYPES__FANOTIFY,
     299                 :            :                          dump_fanotify_entry, &fsn_params) < 0)
     300                 :            :                 return -1;
     301                 :            : 
     302                 :          4 :         pr_info("id 0x%08x flags 0x%08x\n", fe.id, fe.flags);
     303                 :            : 
     304                 :          4 :         fe.faflags = fsn_params.faflags;
     305                 :          4 :         fe.evflags = fsn_params.evflags;
     306                 :            : 
     307                 :          4 :         return pb_write_one(fdset_fd(glob_fdset, CR_FD_FANOTIFY_FILE), &fe, PB_FANOTIFY_FILE);
     308                 :            : }
     309                 :            : 
     310                 :         24 : static int pre_dump_fanotify_entry(union fdinfo_entries *e, void *arg)
     311                 :            : {
     312                 :            :         FanotifyMarkEntry *fme = &e->ffy;
     313                 :            : 
     314         [ +  + ]:         24 :         if (fme->type == MARK_TYPE__INODE)
     315                 :         12 :                 return irmap_queue_cache(fme->s_dev, fme->ie->i_ino,
     316                 :         12 :                                 fme->ie->f_handle);
     317                 :            :         else
     318                 :            :                 return 0;
     319                 :            : }
     320                 :            : 
     321                 :         12 : static int pre_dump_one_fanotify(int pid, int lfd)
     322                 :            : {
     323                 :         12 :         struct fsnotify_params fsn_params = { };
     324                 :         12 :         return parse_fdinfo_pid(pid, lfd, FD_TYPES__FANOTIFY, pre_dump_fanotify_entry, &fsn_params);
     325                 :            : }
     326                 :            : 
     327                 :            : const struct fdtype_ops fanotify_dump_ops = {
     328                 :            :         .type           = FD_TYPES__FANOTIFY,
     329                 :            :         .dump           = dump_one_fanotify,
     330                 :            :         .pre_dump       = pre_dump_one_fanotify,
     331                 :            : };
     332                 :            : 
     333                 :          6 : static char *get_mark_path(const char *who, struct file_remap *remap,
     334                 :            :                            FhEntry *f_handle, unsigned long i_ino,
     335                 :            :                            unsigned int s_dev, char *buf, int *target)
     336                 :            : {
     337                 :            :         char *path = NULL;
     338                 :            : 
     339         [ +  + ]:          6 :         if (remap) {
     340                 :          2 :                 pr_debug("\t\tRestore %s watch for 0x%08x:0x%016lx (via %s)\n",
     341                 :            :                          who, s_dev, i_ino, remap->path);
     342                 :          2 :                 return remap->path;
     343                 :            :         }
     344                 :            : 
     345         [ -  + ]:          4 :         if (f_handle->path) {
     346                 :          0 :                 pr_debug("\t\tRestore with path hint %s\n", f_handle->path);
     347                 :          0 :                 return f_handle->path;
     348                 :            :         }
     349                 :            : 
     350                 :          4 :         *target = open_handle(s_dev, i_ino, f_handle);
     351         [ +  - ]:          4 :         if (*target < 0)
     352                 :            :                 goto err;
     353                 :            : 
     354                 :            :         /*
     355                 :            :          * fanotify/inotify open syscalls want path to attach
     356                 :            :          * watch to. But the only thing we have is an FD obtained
     357                 :            :          * via fhandle. Fortunatelly, when trying to attach the
     358                 :            :          * /proc/pid/fd/ link, we will watch the inode the link
     359                 :            :          * points to, i.e. -- just what we want.
     360                 :            :          */
     361                 :            : 
     362                 :            :         sprintf(buf, "/proc/self/fd/%d", *target);
     363                 :            :         path = buf;
     364                 :            : 
     365         [ +  - ]:          4 :         if (log_get_loglevel() >= LOG_DEBUG) {
     366                 :            :                 char link[PATH_MAX];
     367                 :            : 
     368         [ -  + ]:          4 :                 if (read_fd_link(*target, link, sizeof(link)) < 0)
     369                 :          0 :                         link[0] = '\0';
     370                 :            : 
     371                 :          4 :                 pr_debug("\t\tRestore %s watch for 0x%08x:0x%016lx (via %s -> %s)\n",
     372                 :            :                                 who, s_dev, i_ino, path, link);
     373                 :            :         }
     374                 :            : err:
     375                 :          4 :         return path;
     376                 :            : }
     377                 :            : 
     378                 :          8 : static int restore_one_inotify(int inotify_fd, struct fsnotify_mark_info *info)
     379                 :            : {
     380                 :          4 :         InotifyWdEntry *iwe = info->iwe;
     381                 :          4 :         int ret = -1, target = -1;
     382                 :            :         char buf[PSFDS], *path;
     383                 :            : 
     384                 :          4 :         path = get_mark_path("inotify", info->remap, iwe->f_handle,
     385                 :            :                              iwe->i_ino, iwe->s_dev, buf, &target);
     386         [ +  - ]:          4 :         if (!path)
     387                 :            :                 goto err;
     388                 :            : 
     389                 :            :         /*
     390                 :            :          * FIXME The kernel allocates wd-s sequentially,
     391                 :            :          * this is suboptimal, but the kernel doesn't
     392                 :            :          * provide and API for this yet :(
     393                 :            :          */
     394                 :            :         while (1) {
     395                 :            :                 int wd;
     396                 :            : 
     397                 :          4 :                 wd = inotify_add_watch(inotify_fd, path, iwe->mask);
     398         [ -  + ]:          4 :                 if (wd < 0) {
     399                 :          0 :                         pr_perror("Can't add watch for %d with %d", inotify_fd, iwe->wd);
     400                 :            :                         break;
     401         [ -  + ]:          4 :                 } else if (wd == iwe->wd) {
     402                 :            :                         ret = 0;
     403                 :            :                         break;
     404         [ #  # ]:          0 :                 } else if (wd > iwe->wd) {
     405                 :          0 :                         pr_err("Unsorted watch %d found for %d with %d", wd, inotify_fd, iwe->wd);
     406                 :            :                         break;
     407                 :            :                 }
     408                 :            : 
     409                 :          0 :                 pr_debug("\t\tWatch got %d but %d expected\n", wd, iwe->wd);
     410                 :          0 :                 inotify_rm_watch(inotify_fd, wd);
     411                 :            :         }
     412                 :            : 
     413                 :            : err:
     414         [ +  + ]:          4 :         if (info->remap)
     415                 :          2 :                 remap_put(info->remap);
     416                 :            : 
     417                 :          4 :         close_safe(&target);
     418                 :          4 :         return ret;
     419                 :            : }
     420                 :            : 
     421                 :          8 : static int restore_one_fanotify(int fd, struct fsnotify_mark_info *mark)
     422                 :            : {
     423                 :          4 :         FanotifyMarkEntry *fme = mark->fme;
     424                 :            :         unsigned int flags = FAN_MARK_ADD;
     425                 :          4 :         int ret = -1, target = -1;
     426                 :            :         char buf[PSFDS], *path = NULL;
     427                 :            : 
     428         [ +  + ]:          4 :         if (fme->type == MARK_TYPE__MOUNT) {
     429                 :            :                 struct mount_info *m;
     430                 :            : 
     431                 :          2 :                 m = lookup_mnt_sdev(fme->s_dev);
     432         [ -  + ]:          2 :                 if (!m) {
     433                 :          0 :                         pr_err("Can't find mount s_dev %x\n", fme->s_dev);
     434                 :            :                         return -1;
     435                 :            :                 }
     436                 :            : 
     437                 :            :                 flags |= FAN_MARK_MOUNT;
     438                 :          2 :                 path = m->mountpoint;
     439         [ +  - ]:          2 :         } else if (fme->type == MARK_TYPE__INODE) {
     440                 :          2 :                 path = get_mark_path("fanotify", mark->remap,
     441                 :          2 :                                      fme->ie->f_handle, fme->ie->i_ino,
     442                 :            :                                      fme->s_dev, buf, &target);
     443         [ +  - ]:          2 :                 if (!path)
     444                 :            :                         goto err;
     445                 :            :         } else {
     446                 :          0 :                 pr_err("Bad fsnotify mark type %d\n", fme->type);
     447                 :            :                 goto err;
     448                 :            :         }
     449                 :            : 
     450                 :          4 :         flags |= fme->mflags;
     451                 :            : 
     452         [ +  - ]:          4 :         if (mark->fme->mask) {
     453                 :          4 :                 ret = sys_fanotify_mark(fd, flags, fme->mask, AT_FDCWD, path);
     454         [ -  + ]:          4 :                 if (ret) {
     455                 :          0 :                         pr_err("Adding fanotify mask %x on %x/%s failed (%d)\n",
     456                 :            :                                fme->mask, fme->id, path, ret);
     457                 :            :                         goto err;
     458                 :            :                 }
     459                 :            :         }
     460                 :            : 
     461         [ +  - ]:          4 :         if (fme->ignored_mask) {
     462                 :          4 :                 ret = sys_fanotify_mark(fd, flags | FAN_MARK_IGNORED_MASK,
     463                 :            :                                         fme->ignored_mask, AT_FDCWD, path);
     464         [ -  + ]:          4 :                 if (ret) {
     465                 :          0 :                         pr_err("Adding fanotify ignored-mask %x on %x/%s failed (%d)\n",
     466                 :            :                                fme->ignored_mask, fme->id, path, ret);
     467                 :            :                         goto err;
     468                 :            :                 }
     469                 :            :         }
     470                 :            : 
     471         [ -  + ]:          4 :         if (mark->remap)
     472                 :          0 :                 remap_put(mark->remap);
     473                 :            : 
     474                 :            : err:
     475                 :          4 :         close_safe(&target);
     476                 :            :         return ret;
     477                 :            : }
     478                 :            : 
     479                 :          2 : static int open_inotify_fd(struct file_desc *d)
     480                 :            : {
     481                 :            :         struct fsnotify_file_info *info;
     482                 :          4 :         struct fsnotify_mark_info *wd_info;
     483                 :            :         int tmp;
     484                 :            : 
     485                 :            :         info = container_of(d, struct fsnotify_file_info, d);
     486                 :            : 
     487                 :          2 :         tmp = inotify_init1(info->ife->flags);
     488         [ -  + ]:          2 :         if (tmp < 0) {
     489                 :          0 :                 pr_perror("Can't create inotify for 0x%08x", info->ife->id);
     490                 :          0 :                 return -1;
     491                 :            :         }
     492                 :            : 
     493         [ +  + ]:          6 :         list_for_each_entry(wd_info, &info->marks, list) {
     494                 :          4 :                 pr_info("\tRestore %d wd for 0x%08x\n", wd_info->iwe->wd, wd_info->iwe->id);
     495         [ -  + ]:          4 :                 if (restore_one_inotify(tmp, wd_info)) {
     496                 :          0 :                         close_safe(&tmp);
     497                 :          0 :                         break;
     498                 :            :                 }
     499                 :            :         }
     500                 :            : 
     501         [ -  + ]:          2 :         if (restore_fown(tmp, info->ife->fown))
     502                 :          0 :                 close_safe(&tmp);
     503                 :            : 
     504                 :          2 :         return tmp;
     505                 :            : }
     506                 :            : 
     507                 :          2 : static int open_fanotify_fd(struct file_desc *d)
     508                 :            : {
     509                 :            :         struct fsnotify_file_info *info;
     510                 :            :         struct fsnotify_mark_info *mark;
     511                 :            :         unsigned int flags = 0;
     512                 :            :         int ret;
     513                 :            : 
     514                 :            :         info = container_of(d, struct fsnotify_file_info, d);
     515                 :            : 
     516                 :          2 :         flags = info->ffe->faflags;
     517         [ -  + ]:          2 :         if (info->ffe->flags & O_CLOEXEC)
     518                 :          0 :                 flags |= FAN_CLOEXEC;
     519         [ +  - ]:          2 :         if (info->ffe->flags & O_NONBLOCK)
     520                 :          2 :                 flags |= FAN_NONBLOCK;
     521                 :            : 
     522                 :          2 :         ret = sys_fanotify_init(flags, info->ffe->evflags);
     523         [ -  + ]:          2 :         if (ret < 0) {
     524                 :          0 :                 errno = -ret;
     525                 :          0 :                 pr_perror("Can't init fanotify mark (%d)", ret);
     526                 :          0 :                 return -1;
     527                 :            :         }
     528                 :            : 
     529         [ +  + ]:          6 :         list_for_each_entry(mark, &info->marks, list) {
     530                 :          4 :                 pr_info("\tRestore fanotify for 0x%08x\n", mark->fme->id);
     531         [ -  + ]:          4 :                 if (restore_one_fanotify(ret, mark)) {
     532                 :          0 :                         close_safe(&ret);
     533                 :          0 :                         break;
     534                 :            :                 }
     535                 :            :         }
     536                 :            : 
     537         [ -  + ]:          2 :         if (restore_fown(ret, info->ffe->fown))
     538                 :          0 :                 close_safe(&ret);
     539                 :            : 
     540                 :          2 :         return ret;
     541                 :            : }
     542                 :            : 
     543                 :            : static struct file_desc_ops inotify_desc_ops = {
     544                 :            :         .type = FD_TYPES__INOTIFY,
     545                 :            :         .open = open_inotify_fd,
     546                 :            : };
     547                 :            : 
     548                 :            : static struct file_desc_ops fanotify_desc_ops = {
     549                 :            :         .type = FD_TYPES__FANOTIFY,
     550                 :            :         .open = open_fanotify_fd,
     551                 :            : };
     552                 :            : 
     553                 :          4 : static struct fsnotify_file_info *find_inotify_info(unsigned id)
     554                 :            : {
     555                 :            :         struct fsnotify_file_info *p;
     556                 :            :         static struct fsnotify_file_info *last = NULL;
     557                 :            : 
     558 [ +  + ][ +  - ]:          4 :         if (last && last->ife->id == id) {
     559                 :            :                 /*
     560                 :            :                  * An optimization for clean dump image -- criu puts
     561                 :            :                  * wd-s for one inotify in one row, thus sometimes
     562                 :            :                  * we can avoid scanning the inotify_info_head.
     563                 :            :                  */
     564                 :          2 :                 pr_debug("\t\tlast ify for %u found\n", id);
     565                 :          2 :                 return last;
     566                 :            :         }
     567                 :            : 
     568         [ +  - ]:          2 :         list_for_each_entry(p, &inotify_info_head, list)
     569         [ +  - ]:          2 :                 if (p->ife->id == id) {
     570                 :          2 :                         last = p;
     571                 :          2 :                         return p;
     572                 :            :                 }
     573                 :            : 
     574                 :          0 :         pr_err("Can't find inotify with id 0x%08x\n", id);
     575                 :          0 :         return NULL;
     576                 :            : }
     577                 :            : 
     578                 :          4 : static int collect_inotify_mark(struct fsnotify_mark_info *mark)
     579                 :            : {
     580                 :            :         struct fsnotify_file_info *p;
     581                 :            :         struct fsnotify_mark_info *m;
     582                 :            : 
     583                 :          4 :         p = find_inotify_info(mark->iwe->id);
     584         [ +  - ]:          4 :         if (!p)
     585                 :            :                 return -1;
     586                 :            : 
     587                 :            :         /*
     588                 :            :          * We should put marks in wd ascending order. See comment
     589                 :            :          * in restore_one_inotify() for explanation.
     590                 :            :          */
     591         [ +  + ]:          4 :         list_for_each_entry(m, &p->marks, list)
     592         [ -  + ]:          2 :                 if (m->iwe->wd > mark->iwe->wd)
     593                 :            :                         break;
     594                 :            : 
     595                 :          4 :         list_add_tail(&mark->list, &m->list);
     596                 :          4 :         mark->remap = lookup_ghost_remap(mark->iwe->s_dev, mark->iwe->i_ino);
     597                 :          4 :         return 0;
     598                 :            : }
     599                 :            : 
     600                 :          4 : static int collect_fanotify_mark(struct fsnotify_mark_info *mark)
     601                 :            : {
     602                 :            :         struct fsnotify_file_info *p;
     603                 :            : 
     604         [ +  - ]:          4 :         list_for_each_entry(p, &fanotify_info_head, list) {
     605         [ +  - ]:          4 :                 if (p->ffe->id == mark->fme->id) {
     606                 :          4 :                         list_add(&mark->list, &p->marks);
     607         [ +  + ]:          4 :                         if (mark->fme->type == MARK_TYPE__INODE)
     608                 :          2 :                                 mark->remap = lookup_ghost_remap(mark->fme->s_dev,
     609                 :          2 :                                                                  mark->fme->ie->i_ino);
     610                 :            :                         return 0;
     611                 :            :                 }
     612                 :            :         }
     613                 :            : 
     614                 :          0 :         pr_err("Can't find fanotify with id 0x%08x\n", mark->fme->id);
     615                 :          0 :         return -1;
     616                 :            : }
     617                 :            : 
     618                 :          2 : static int collect_one_inotify(void *o, ProtobufCMessage *msg)
     619                 :            : {
     620                 :            :         struct fsnotify_file_info *info = o;
     621                 :            : 
     622                 :          2 :         info->ife = pb_msg(msg, InotifyFileEntry);
     623                 :          2 :         INIT_LIST_HEAD(&info->marks);
     624                 :          2 :         list_add(&info->list, &inotify_info_head);
     625                 :          2 :         pr_info("Collected id 0x%08x flags 0x%08x\n", info->ife->id, info->ife->flags);
     626                 :          2 :         return file_desc_add(&info->d, info->ife->id, &inotify_desc_ops);
     627                 :            : }
     628                 :            : 
     629                 :            : struct collect_image_info inotify_cinfo = {
     630                 :            :         .fd_type        = CR_FD_INOTIFY_FILE,
     631                 :            :         .pb_type        = PB_INOTIFY_FILE,
     632                 :            :         .priv_size      = sizeof(struct fsnotify_file_info),
     633                 :            :         .collect        = collect_one_inotify,
     634                 :            :         .flags          = COLLECT_OPTIONAL,
     635                 :            : };
     636                 :            : 
     637                 :          2 : static int collect_one_fanotify(void *o, ProtobufCMessage *msg)
     638                 :            : {
     639                 :            :         struct fsnotify_file_info *info = o;
     640                 :            : 
     641                 :          2 :         info->ffe = pb_msg(msg, FanotifyFileEntry);
     642                 :          2 :         INIT_LIST_HEAD(&info->marks);
     643                 :          2 :         list_add(&info->list, &fanotify_info_head);
     644                 :          2 :         pr_info("Collected id 0x%08x flags 0x%08x\n", info->ffe->id, info->ffe->flags);
     645                 :          2 :         return file_desc_add(&info->d, info->ffe->id, &fanotify_desc_ops);
     646                 :            : }
     647                 :            : 
     648                 :            : struct collect_image_info fanotify_cinfo = {
     649                 :            :         .fd_type        = CR_FD_FANOTIFY_FILE,
     650                 :            :         .pb_type        = PB_FANOTIFY_FILE,
     651                 :            :         .priv_size      = sizeof(struct fsnotify_file_info),
     652                 :            :         .collect        = collect_one_fanotify,
     653                 :            :         .flags          = COLLECT_OPTIONAL,
     654                 :            : };
     655                 :            : 
     656                 :          4 : static int collect_one_inotify_mark(void *o, ProtobufCMessage *msg)
     657                 :            : {
     658                 :            :         struct fsnotify_mark_info *mark = o;
     659                 :            : 
     660                 :          4 :         mark->iwe = pb_msg(msg, InotifyWdEntry);
     661                 :          4 :         INIT_LIST_HEAD(&mark->list);
     662                 :          4 :         mark->remap = NULL;
     663                 :            : 
     664                 :          4 :         return collect_inotify_mark(mark);
     665                 :            : }
     666                 :            : 
     667                 :            : struct collect_image_info inotify_mark_cinfo = {
     668                 :            :         .fd_type        = CR_FD_INOTIFY_WD,
     669                 :            :         .pb_type        = PB_INOTIFY_WD,
     670                 :            :         .priv_size      = sizeof(struct fsnotify_mark_info),
     671                 :            :         .collect        = collect_one_inotify_mark,
     672                 :            :         .flags          = COLLECT_OPTIONAL,
     673                 :            : };
     674                 :            : 
     675                 :          4 : static int collect_one_fanotify_mark(void *o, ProtobufCMessage *msg)
     676                 :            : {
     677                 :            :         struct fsnotify_mark_info *mark = o;
     678                 :            : 
     679                 :          4 :         mark->fme = pb_msg(msg, FanotifyMarkEntry);
     680                 :          4 :         INIT_LIST_HEAD(&mark->list);
     681                 :          4 :         mark->remap = NULL;
     682                 :            : 
     683                 :          4 :         return collect_fanotify_mark(mark);
     684                 :            : }
     685                 :            : 
     686                 :            : struct collect_image_info fanotify_mark_cinfo = {
     687                 :            :         .fd_type        = CR_FD_FANOTIFY_MARK,
     688                 :            :         .pb_type        = PB_FANOTIFY_MARK,
     689                 :            :         .priv_size      = sizeof(struct fsnotify_mark_info),
     690                 :            :         .collect        = collect_one_fanotify_mark,
     691                 :            :         .flags          = COLLECT_OPTIONAL,
     692                 :            : };

Generated by: LCOV version 1.9