Red Hat Bugzilla – Bug 895905
guestmount: link() incorrectly returns ENOENT, when it should be EXDEV
Last modified: 2013-01-21 09:46:13 EST
+++ 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):
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
--- 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]
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
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:
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:
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.
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.