<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Wed, Aug 13, 2014 at 1:13 AM, Pavel Emelyanov <span dir="ltr">&lt;<a href="mailto:xemul@parallels.com" target="_blank">xemul@parallels.com</a>&gt;</span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">On 08/13/2014 04:29 AM, Saied Kazemi wrote:<br>
<br>
Hi, Saied.<br>
<div><br>
&gt; Here is a new patch. Â I rebased to the head (commit ded04267f8) and cleaned up the code a<br>
&gt; bit more. Â Please use the attached patch instead of the one I sent yesterday.<br>
&gt;<br>
&gt; Note that I had to delete 3 lines from cgroup.c for properties that I don&#39;t have on my<br>
&gt; Ubuntu 14.04. Â Also, please note that you have to add --manage-cgroups to criu command<br>
&gt; line for both dump and restore.<br>
<br>
</div>Thank you for looking into this. I&#39;m not familiar with AUFS at all, thus I<br>
only have comments about the way AUFS parsing/fixing code is integrated into<br>
the rest of the criu code.<br></blockquote><div><br></div><div>I am not familiar with AUFS internals either. Â I just looked at how it&#39;s set up and what information it passes through /proc.</div><div><br></div><div> </div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
Please, see my comments inline.<br>
<br>
&gt; @@ -197,6 +199,19 @@ int fill_fdlink(int lfd, const struct fd_parms *p, struct fd_link *link)<br>
&gt; Â  Â  Â  Â  Â  Â  Â  return -1;<br>
&gt; Â  Â  Â  }<br>
&gt;<br>
&gt; + Â  Â  /*<br>
&gt; + Â  Â  Â * For AUFS support, we need to replace absolute<br>
&gt; + Â  Â  Â * branch pathnames with relative pathnames from root.<br>
&gt; + Â  Â  Â */<br>
&gt; + Â  Â  if (opts.aufs) {<br>
<br>
At this point we have the statfs() information. Can we rely on the<br>
fs_type being aufs magic to check that the file is aufs one?<br></blockquote><div><br></div><div>No, because depending on how we end up in fill_fdlink(), p-&gt;fstype may be NULL. Â Besides, even when set, its fstyp isn&#39;t aufs. Â It&#39;d be something like ext4 because the branch is in ext4.</div>

<div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
&gt; + Â  Â  Â  Â  Â  Â  int n = sizeof link-&gt;name - 1;<br>
&gt; + Â  Â  Â  Â  Â  Â  n = fixup_aufs_path(&amp;link-&gt;name[1], n, true);<br>
&gt; + Â  Â  Â  Â  Â  Â  if (n &lt; 0)<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  return -1;<br>
&gt; + Â  Â  Â  Â  Â  Â  if (n &gt; 0)<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  len = n;<br>
&gt; + Â  Â  }<br>
&gt; +<br>
&gt; Â  Â  Â  link-&gt;len = len + 1;<br>
&gt; Â  Â  Â  return 0;<br>
<br>
&gt; @@ -450,12 +453,24 @@ int parse_smaps(pid_t pid, struct vm_area_list *vma_area_list, bool use_map_file<br>
&gt; Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  vma_area-&gt;st = prev-&gt;st;<br>
&gt; Â  Â  Â  Â  Â  Â  Â  } else if (vma_area-&gt;vm_file_fd &gt;= 0) {<br>
&gt; Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  struct stat *st_buf;<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  char *f;<br>
&gt;<br>
&gt; Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  st_buf = vma_area-&gt;st = xmalloc(sizeof(*st_buf));<br>
&gt; Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  if (!st_buf)<br>
&gt; Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  goto err;<br>
&gt;<br>
&gt; - Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  if (fstat(vma_area-&gt;vm_file_fd, st_buf) &lt; 0) {<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  /*<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â * For AUFS support, we cannot fstat() file a descriptor that<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â * is a symbolic link to a branch. Â Instead, we obtain the<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â * pathname of the file from the root and use stat().<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â */<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  if (opts.aufs &amp;&amp; (f = fixup_aufs_fd_path(vma_area-&gt;vm_file_fd))) {<br>
<br>
Would this work if the vm_file_fd sits in another mount namespace? Or<br>
the path reported by fixup_aufs_fd_path() is always in the criu&#39;s one?<br></blockquote><div><br></div><div>I think it should work, although I don&#39;t know how to force it in a different mount namespace in the tests that I am running. Â Can you whip up an example?</div>

<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
And another question -- do we need the fixed stat buffer that early?<br></blockquote><div><br></div><div>I am doing this exactly at the same time that CRIU is doing it (i.e., the fstat() is original code). Â I&#39;m just using stat() instead of fstat(), so effectively it&#39;s the same logic/time as before. </div>

<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
The vma fd is dumped in dump_filemap() and in that place we call<br>
get_fd_mntid() for missing mount ID. Can we fixup the device there too?<br></blockquote><div><br></div><div>The way I handle it is like this: Â If the link file descriptor points to an AUFS branch name, we replace it with a pathname from root. Â Here is the call sequence from dump_filemap():</div>

<div><br></div><div>dump_filemap()</div><div>  Â dump_one_reg_file(lfd)<br></div><div>  Â  Â  fill_fdlink(lfd)</div><div>  Â  Â  Â  Â read_fd_link(lfd)</div><div>  Â  Â  Â  Â  Â  readlink(lfd) Â  Â  Â  Â  Â  Â  Â  // returns path in branch</div>

<div>  Â  Â  Â  Â fixup_aufs_brnach() Â  Â  // replaces path in branch with path from root</div><div>  Â  Â  check_path_remap()</div><div><br></div><div>In other words, when we see a pathname in a branch, we replace it with a pathname from root as if we never saw the branch pathname. Â When using a link file descriptor in fstat(), because the kernel returns the stat info of the pathname in branch, we use stat() with a pathname from the root instead of fstat(). Â If we didn&#39;t do this, we&#39;d get different device/inode values and CRIU fails with an error message like &quot;Unaccessible path opened 33:23, need 2049:53764&quot;.</div>
<div><br></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><br>

&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  if (stat(f, st_buf) &lt; 0) {<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  pr_perror(&quot;Failed fstat on %d&#39;s map %lu (%s)&quot;,<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  pid, start, f);<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  goto err;<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  }<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  } else if (fstat(vma_area-&gt;vm_file_fd, st_buf) &lt; 0) {<br>
&gt; Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  pr_perror(&quot;Failed fstat on %d&#39;s map %lu&quot;, pid, start);<br>
&gt; Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  goto err;<br>
&gt; Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  }<br>
<br>
&gt; @@ -921,6 +942,16 @@ static int parse_mountinfo_ent(char *str, struct mount_info *new)<br>
&gt; Â  Â  Â  if (ret != 3)<br>
&gt; Â  Â  Â  Â  Â  Â  Â  return -1;<br>
&gt;<br>
&gt; + Â  Â  /* see comments in sysfs_parse.c */<br>
&gt; + Â  Â  if (opts.aufs &amp;&amp; !strcmp(new-&gt;mountpoint, &quot;./&quot;)) {<br>
&gt; + Â  Â  Â  Â  Â  Â  if (strcmp(fstype, &quot;aufs&quot;)) {<br>
<br>
Can we reuse the fstype-&gt;parse() callback for this? This one gets called<br>
in parse_mountinfo() in a loop after parse_mountinfo_ent().<br></blockquote><div><br></div><div>Yes, we can and I changed the code accordingly (added aufs to fstypes[]). Â Please use the new patch.</div><div><br></div><div>
 <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  pr_err(&quot;Expected fstype aufs got %s\n&quot;, fstype);<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  return -1;<br>
&gt; + Â  Â  Â  Â  Â  Â  }<br>
&gt; + Â  Â  Â  Â  Â  Â  if (fixup_src_opt(&amp;new-&gt;source, &amp;opt) &lt; 0)<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  return -1;<br>
&gt; + Â  Â  }<br>
&gt; +<br>
&gt; Â  Â  Â  ret = -1;<br>
&gt; Â  Â  Â  new-&gt;fstype = find_fstype_by_name(fstype);<br>
&gt;<br>
<br>
&gt; +/*<br>
&gt; + * Copy the line in process&#39;s mountinfo file that corresponds<br>
&gt; + * to the mountpoint specified by the mntpoint argument. Â Return<br>
&gt; + * the number of characters parsed in the line, or -1 on error.<br>
&gt; + */<br>
&gt; +int get_mountinfo_by_mountpoint(pid_t pid, char *mntpoint, char *line, int linelen)<br>
<br>
I do not fully understand why this mountpoint-&gt;something-else parser<br>
is required. Can we put all the code parsing aufs-specific stuff into<br>
the fstype-&gt;parse() callback I mentioned above? When criu starts<br>
parsing mount namespaces (it does this before doing anything else)<br>
this info will be parsed and stored into mount_info-&gt;private. Later,<br>
when we need to e.g. fixup file paths we can get file-&gt;mnt_id, get<br>
mount_info by it, then check the fs being aufs and fix the path<br>
according to the mount_info-&gt;private data we have. Would this work?<br></blockquote><div><br></div><div>I am now using the parse callback that you suggested but we need the &quot;reference&quot; values *before* parse_mountinfo() is called. Â Otherwise, when we call the parse callback, we won&#39;t know what values to replace with.<br>
</div><div><br></div><div>That said, I noticed that with my latest rebase there is apparently no longer a need to specify --aufs-ref. Â This is great as we can get rid of the code fixing up the mountinfo root entry (note that we&#39;d still need to replace / with the --aufs-root).</div>
<div><br></div><div>Since I am not familiar with the internals of CRIU as to how it builds its bind mount list, could you please review this part of the code? Â As mentioned before, it used to be that without --aufs-ref, mounts_equal() would return false, in my test cases, for /etc/hosts, /etc/hostname, and /etc/resolv.conf because their dev, fstype, source, and options were different. Â  As a result, these files would not be added to the mnt_bind list in collect_shared() and restore would fail with the error message &quot;A few mount points can&#39;t be mounted.&quot; Â I am puzzled that restore is now successful without --aufs-ref. Â I need to look into this deeper myself but would really appreciate your thoughts and feedback.</div>
<div><br></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
&gt; +{<br>
&gt; + Â  Â  char buf[PATH_MAX];<br>
&gt; + Â  Â  int n, ret;<br>
&gt; + Â  Â  FILE *f;<br>
<br>
&gt; +<br>
&gt; + Â  Â  snprintf(buf, sizeof buf, &quot;/proc/%d/mountinfo&quot;, pid);<br>
&gt; + Â  Â  f = fopen(buf, &quot;r&quot;);<br>
&gt; + Â  Â  if (!f) {<br>
&gt; + Â  Â  Â  Â  Â  Â  pr_perror(&quot;Cannot fopen %s&quot;, buf);<br>
&gt; + Â  Â  Â  Â  Â  Â  return -1;<br>
&gt; + Â  Â  }<br>
&gt; +<br>
&gt; + Â  Â  do {<br>
&gt; + Â  Â  Â  Â  Â  Â  n = linelen - 2;<br>
&gt; + Â  Â  Â  Â  Â  Â  line[n] = &#39;\0&#39;; Â  Â  Â  Â  /* detect long input */<br>
&gt; + Â  Â  Â  Â  Â  Â  if (fgets(line, linelen, f) == NULL) {<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  ret = 0;<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  break;<br>
&gt; + Â  Â  Â  Â  Â  Â  }<br>
&gt; + Â  Â  Â  Â  Â  Â  if (line[n] &amp;&amp; line[n] != &#39;\n&#39;) {<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  pr_err(&quot;Line in mountinfo too long\n&quot;);<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  ret = -1;<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  goto out;<br>
&gt; + Â  Â  Â  Â  Â  Â  }<br>
&gt; +<br>
&gt; + Â  Â  Â  Â  Â  Â  ret = sscanf(line, &quot;%*i %*i %*u:%*u %*s %s %*s - %n&quot;, buf, &amp;n);<br>
<br>
Wow. Doesn&#39;t gcc prints a warning about &quot;too few arguments for format&quot;?<br></blockquote><div><br></div><div>No, because * means discard what&#39;s scanned.</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">

<br>
&gt; + Â  Â  Â  Â  Â  Â  if (ret != 1) {<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  pr_err(&quot;Cannot parse mountpoint (%s)\n&quot;, line);<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  ret = -1;<br>
&gt; + Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  goto out;<br>
&gt; + Â  Â  Â  Â  Â  Â  }<br>
&gt; + Â  Â  } while (strcmp(buf, mntpoint));<br>
&gt; +<br>
&gt; + Â  Â  if (!ret) {<br>
&gt; + Â  Â  Â  Â  Â  Â  pr_err(&quot;Did not find %s in mountinfo\n&quot;, mntpoint);<br>
&gt; + Â  Â  Â  Â  Â  Â  ret = -1;<br>
&gt; + Â  Â  } else<br>
&gt; + Â  Â  Â  Â  Â  Â  ret = n;<br>
&gt; +<br>
&gt; +out:<br>
&gt; + Â  Â  fclose(f);<br>
&gt; + Â  Â  return ret;<br>
&gt; +}<br>
<br>
Thanks,<br>
Pavel<br>
<br>
</blockquote></div></div><div><br></div>Cheers!<div><br><div>--Saied</div><div><br></div></div></div>