+++ This bug was initially created as a clone of Bug #892291 +++ Description of problem: My project ostree uses hardlinks extensively; I have a bit of code which tries link() and falls back to a copy if it gets EXDEV. Unfortunately, something in the guestmount/fuse/kernel chain is giving me ENOENT, when it should be EXDEV. I've added a workaround to ostree, but this is suboptimal. Version-Release number of selected component (if applicable): libguestfs-1.16.34-2.el6.x86_64 fuse-2.8.3-4.el6.x86_64 kernel-2.6.32-350.el6.x86_64 How reproducible: Always. Steps to Reproduce: 1. guestmount --rw -o allow_root --pid-file guestmount.pid -a test.img -m /dev/sda3 -m /dev/sda1:/boot mnt 2. cd mnt 3. touch foo 4. ln foo boot/foo Actual results: ENOENT Expected results: EXDEV --- Additional comment from RHEL Product and Program Management on 2013-01-06 06:13:09 EST --- Since this bug report was entered in bugzilla, the release flag has been set to ? to ensure that it is properly evaluated for this release. --- Additional comment from RHEL Product and Program Management on 2013-01-11 01:47:31 EST --- This request was not resolved in time for the current release. Red Hat invites you to ask your support representative to propose this request, if still desired, for consideration in the next release of Red Hat Enterprise Linux.
Cloning this bug to check whether it happens upstream too.
Created attachment 684279 [details] test script Simple self-contained test script demonstrating the problem. The output is: [...] + mkdir -p /tmp/mnt + guestmount -a test1.img -m /dev/sda1:/ -m /dev/sda2:/boot /tmp/mnt + touch /tmp/mnt/foo + cd /tmp/mnt + ln foo boot/foo ln: failed to create hard link ‘boot/foo’ => ‘foo’: No such file or directory (The error message should be "Invalid cross-device link")
Created attachment 684284 [details] API-level link test This is a test script to see what the guestfs_ln API returns. Note that the current implementation of guestfs_ln runs the external 'ln' binary. This has two obvious problems: (a) it's slow (b) it doesn't capture errno There's no obvious reason why we could not replace this impl with a direct call to link(2).
Two commits are needed to fix this fully: https://github.com/libguestfs/libguestfs/commit/533082e28240522df51e6615d99794d726c8e1f0 https://github.com/libguestfs/libguestfs/commit/28e34290ff0dc11e9c5d8b8a1e5992cd0cc941fb The first commit changes guestfs_ln to use link(2) directly instead of the external 'ln' program, ensuring that we can capture the errno. That commit on its own does fix the whole bug (including guestmount), but ... When I looked closely at the code to guestmount to try to work out why ENOENT was being returned (ENOENT appears nowhere along any relevant codepaths), I realized there is a second bug in guestmount which affects lots of things. The current guestmount code returns errnos to FUSE by just doing: return -guestfs_last_errno(g); That works, in the cases where the previous guestfs_* API call captured the errno. In other cases, guestfs_last_errno returns 0, and thus 0 (no error) is passed back to FUSE. Ooops. What was in fact happening in the ln-over-guestmount case was that the link call was *succeeding*, but a subsequent open was failing with ENOENT. The second commit fixes this.