<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Tue, Aug 19, 2014 at 3:03 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:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="">On 08/18/2014 08:43 PM, Saied Kazemi wrote:<br>
<br>
&gt;     &gt; @@ -197,6 +199,20 @@ int fill_fdlink(int lfd, const struct fd_parms *p, struct fd_link *link)<br>
&gt;     &gt;               return -1;<br>
&gt;     &gt;       }<br>
&gt;     &gt;<br>
&gt;     &gt; +     /*<br>
&gt;     &gt; +      * If the link file descriptor (lfd) points to a<br>
&gt;     &gt; +      * file in an AUFS branch, the pathname should be<br>
&gt;     &gt; +      * replaced with a pathname from root.<br>
&gt;     &gt; +      */<br>
&gt;     &gt; +     if (opts.aufs) {<br>
&gt;     &gt; +             int n = sizeof link-&gt;name - 1;<br>
&gt;     &gt; +             n = fixup_aufs_path(&amp;link-&gt;name[1], n, true);<br>
&gt;<br>
&gt;     Since you say, that we only see spoiled paths in map_files, do we need<br>
&gt;     the path fixup here? Isn&#39;t the one performed in parsing the mappings<br>
&gt;     not enough?<br>
&gt;<br>
&gt;<br>
&gt; We need this logic here because the link-&gt;name is in an AUFS branch.  For example, these are the paths that are passed to fill_fdlink() during my test:<br>
&gt;<br>
&gt; /dev/null<br>
&gt; /var/lib/docker/aufs/diff/&lt;ID&gt;/bin/busybox<br>
</div>&gt; /var/lib/docker/aufs/diff/&lt;ID&gt;/lib/<a href="http://libuClibc-0.9.33.2.so" target="_blank">libuClibc-0.9.33.2.so</a> &lt;<a href="http://libuClibc-0.9.33.2.so" target="_blank">http://libuClibc-0.9.33.2.so</a>&gt;<br>

&gt; /var/lib/docker/aufs/diff/&lt;ID&gt;/lib/<a href="http://ld64-uClibc-0.9.33.2.so" target="_blank">ld64-uClibc-0.9.33.2.so</a> &lt;<a href="http://ld64-uClibc-0.9.33.2.so" target="_blank">http://ld64-uClibc-0.9.33.2.so</a>&gt;<br>

&gt; /<br>
<br>
OK, the only way why spoiled paths leak there is through the dump_filemap(),<br>
and the file we want to dump there was already seen in parse_smaps(). Can we<br>
make path fixup only once? I think we can<br>
<br>
* fixup the path in parse_smaps()<br>
* put one on the vma_area() (can be unione-ed with page_bitmap, it&#39;s restore field)<br>
* then in dump_filemap() put one as the link pointer on fdparms<br>
<br>
<br>
after this the if (!p-&gt;link) check in dump_one_reg_file() would avoid calling<br>
the fill_fdlink.<br>
<br>
What do you think?<br></blockquote><div><br></div><div>It&#39;s a good idea and I reworked the code accordingly.  Please see the attached patch to make sure that it&#39;s how you meant.</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<div><div class="h5"><br>
&gt;<br>
&gt;<br>
&gt;     &gt; +             if (n &lt; 0)<br>
&gt;     &gt; +                     return -1;<br>
&gt;     &gt; +             if (n &gt; 0)<br>
&gt;     &gt; +                     len = n;<br>
&gt;     &gt; +     }<br>
&gt;     &gt; +<br>
&gt;     &gt;       link-&gt;len = len + 1;<br>
&gt;     &gt;       return 0;<br>
&gt;     &gt;  }<br>
&gt;<br>
&gt;     &gt; +int fixup_aufs_path(char *path, int size, bool chop)<br>
&gt;     &gt; +{<br>
&gt;     &gt; +     char rpath[PATH_MAX];<br>
&gt;     &gt; +     int n;<br>
&gt;     &gt; +     int blen;<br>
&gt;     &gt; +<br>
&gt;     &gt; +     if (aufs_branches == NULL) {<br>
&gt;     &gt; +             pr_err(&quot;No aufs branches to search for %s\n&quot;, path);<br>
&gt;     &gt; +             return -1;<br>
&gt;<br>
&gt;     Presumably, if we don&#39;t have AUFS we shouldn&#39;t fail :)<br>
&gt;<br>
&gt;<br>
&gt; If we don&#39;t have AUFS, we should not specify --aufs and, therefore, we should not be calling<br>
&gt; fixup_aufs_path().  So, if we get to fixup_aufs_path() but don&#39;t have branch information, it&#39;s<br>
&gt; an error.<br>
&gt;<br>
&gt; Alternatively, we can decide not to specify --aufs and call AUFS code regardless, returning<br>
&gt; without error if there&#39;s no AUFS.  But I added --aufs for performance reasons.  It&#39;s used in<br>
&gt; 3 places:<br>
&gt;<br>
&gt; 1. cr-dump.c/dump_one_task()<br>
&gt;    - to collect AUFS branch pathnames and free them when done<br>
&gt; 2. files.c/fill_fdlink()<br>
&gt;    - to replace pathnames in branches with pathnames from root<br>
&gt; 3. proc_parse.c/parse_smaps()<br>
&gt;    - to get the path for stat() instead of fstat()<br>
&gt;<br>
<br>
</div></div>Ah, I see. I was thinking that we can make CRIU automatically detect, that it<br>
should do paths fixups, but since we&#39;d have to specify --aufs-root anyway, then OK.<br></blockquote><div><br></div><div>When I have a bit more time, I will work on this and send a patch to automatically detect AUFS.</div>
<div><br></div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div class="h5"><br>
&gt;<br>
&gt;     &gt; +     }<br>
&gt;     &gt; +<br>
&gt;<br>
&gt;     &gt; +int parse_mountinfo_aufs_sbinfo(pid_t pid, char *sbinfo, int len)<br>
&gt;     &gt; +{<br>
&gt;     &gt; +     char line[PATH_MAX];<br>
&gt;     &gt; +     char *fstype = NULL;<br>
&gt;     &gt; +     char *opt = NULL;<br>
&gt;     &gt; +     char *cp;<br>
&gt;     &gt; +     int n, ret;<br>
&gt;     &gt; +<br>
&gt;     &gt; +     n = get_mntent_by_mountpoint(pid, &quot;/&quot;, line, sizeof line);<br>
&gt;     &gt; +     if (n &lt; 0)<br>
&gt;     &gt; +             return -1;<br>
&gt;     &gt; +<br>
&gt;<br>
&gt;     Presumably, this would get fixed by rework of mountinfo&#39;s parser, right?<br>
&gt;<br>
&gt;<br>
&gt; I already reworked the callback in mountinfo&#39;s parser which was in the previous patch (see<br>
&gt; proc_parse.c/aufs_parse()).  This is different as it&#39;s not changing anything in the mountinfo<br>
&gt; entry.  It&#39;s just getting the sbinfo string from mountinfo root entry to collect AUFS branch<br>
&gt; information.<br>
&gt;<br>
&gt; dump_one_task()<br>
&gt;    if (opts.aufs) parse_aufs_branches()<br>
&gt;       parse_mountinf_aufs_sbinfo()<br>
&gt;          get_mntent_by_mountpoint()<br>
&gt;<br>
&gt; It may be possible to add another call back, .post_parse, and rework mountinfo parsing.  But<br>
&gt; .post_parse will only be used by used by AUFS and this code is temporary anyway.  It will go<br>
&gt; away as soon as AUFS bug is fixed.  So, if you&#39;re OK, let&#39;s keep it like this.  For non-AUFS<br>
&gt; filesystems, this code isn&#39;t even called.<br>
<br>
</div></div>Yes, I agree. What bothers me is that we do mountinfo-s parsing multiple<br>
times and introduce two independent parser codes for that. I&#39;d prefer if<br>
we make one-pass scanning.<br></blockquote><div><br></div><div>I reworked this part too via the .parse callback so there are no additional mountinfo parsings :)</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<div><div class="h5"><br>
&gt;<br>
&gt;<br>
&gt;     &gt; +int aufs_parse(struct mount_info *new)<br>
&gt;     &gt; +{<br>
&gt;     &gt; +     char *cp;<br>
&gt;     &gt; +<br>
&gt;     &gt; +     if (!opts.aufs_root || strcmp(new-&gt;mountpoint, &quot;./&quot;))<br>
&gt;<br>
&gt;     If we&#39;ve met AUFS, but no --aufs-root specified, shouldn&#39;t we fail the dump?<br>
&gt;<br>
&gt;<br>
&gt; The reason it doesn&#39;t return an error is that as soon as the mountinfo entry for root is<br>
&gt; fixed (i.e., shows the root pathname instead of just /), we won&#39;t have to specify --aufs-root<br>
&gt; anymore and shouldn&#39;t fail in aufs_parse().<br>
&gt;<br>
&gt;<br>
&gt;<br>
&gt;<br>
&gt;     &gt; +             return 0;<br>
&gt;     &gt; +<br>
&gt;     &gt; +     cp = malloc(strlen(opts.aufs_root) + 1);<br>
&gt;     &gt; +     if (!cp) {<br>
&gt;     &gt; +             pr_err(&quot;Cannot allocate memory for %s\n&quot;, opts.aufs_root);<br>
&gt;     &gt; +             return -1;<br>
&gt;     &gt; +     }<br>
&gt;     &gt; +     strcpy(cp, opts.aufs_root);<br>
&gt;     &gt; +<br>
&gt;     &gt; +     pr_debug(&quot;Replacing %s with %s\n&quot;, new-&gt;root, opts.aufs_root);<br>
&gt;     &gt; +     free(new-&gt;root);<br>
&gt;     &gt; +     new-&gt;root = cp;<br>
&gt;<br>
&gt;     What if we have more than one AUFS mountpoint with different roots? I&#39;m<br>
&gt;     OK if we only support one, but then we should fail the 2nd mountpoint met.<br>
&gt;<br>
&gt;<br>
&gt; Here, we&#39;re replacing the root of the container which by definition is only 1.  But if different<br>
&gt; processes in the process tree have different AUFS mounts, their respective branch pathnames will<br>
&gt; be handed one by one in parse_aufs_branches() when called from dump_one_task().<br>
<br>
</div></div>I meant -- what if one process sees two different AUFS mounts.<br></blockquote><div><br></div><div>I think it should work because the branches are set for each nsid.  This is another thing that we can address as time allows going forward.</div>
<div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class=""><br>
&gt;     &gt; +<br>
&gt;     &gt; +     return 0;<br>
&gt;     &gt; +}<br>
&gt;<br>
&gt;<br>
&gt;     Thanks,<br>
&gt;     Pavel<br>
&gt;<br>
&gt;<br>
&gt; Thanks again for your feedback.  I hope the answers are clear.  If it&#39;s easier or more productive,<br>
&gt; I am available on video chat to discuss in greater detail.  My schedule is flexible, so time<br>
&gt; difference shouldn&#39;t be a problem.<br>
<br>
</div>OK, I&#39;ll keep that in mind :) Your timezone is US Pacific one, right?<br></blockquote><div><br></div><div>Yes, I am in Mountain View.</div><div><br></div><div>Looking forward to your comments on this patch which I think has addressed everything above.</div>
<div><br></div><div>Cheers!</div><div><br></div><div>--Saied</div><div><br></div></div></div></div>