On Wed, May 12, 2021 at 02:55:42PM +0200, Max Reitz wrote:
Mount point directories represent two inodes: On one hand, they are a
normal directory on their parent filesystem. On the other, they are the
root node of the filesystem mounted there. Thus, they have two inode
IDs.
Right now, we only report the latter inode ID (i.e. the inode ID of the
mounted filesystem's root node). This is fine once the guest has
auto-mounted a submount there (so this inode ID goes with a device ID
that is distinct from the parent filesystem), but before the auto-mount,
they have the device ID of the parent and the inode ID for the submount.
This is problematic because this is likely exactly the same
st_dev/st_ino combination as the parent filesystem's root node. This
leads to problems for example with `find`, which will thus complain
about a filesystem loop if it has visited the parent filesystem's root
node before, and then refuse to descend into the submount.
There is a way to find the mount directory's original inode ID, and that
is to readdir(3) the parent directory, look for the mount directory, and
read the dirent.d_ino field. Using this, we can let lookup and
readdirplus return that original inode ID, which the guest will thus
show until the submount is auto-mounted.
(Then, it will invoke getattr
and that stat(2) call will return the inode ID for the submount.)
Hi Max,
How are we sure that GETATTR() will always be called and that will
allow us to return inode number in mounted filesystem (instead of
parent filesystem). I thought GETATTR will be called only if cached
attrs have expired. (1 second default for cache=auto). Otherwise
stat() will fill inode->i_no from cache and return. And I am afraid
that in that case we will return inode number from parent fs,
instead of mounted fs.
Say following sequence of events happens pretty fast one after the
other. Say /mnt/virtiofs/foo is a mount point in server but client
has not created submount yet.
A. stat(/mnt/virtiofs/foo, AT_NO_AUTOMOUNT)
-> This should get inode number in parent filesystem on host and
store in guest inode->i_no and return to user space. Say inode
in guest is called a_ino.
B. stat(/mnt/virtiofs/foo)
-> This should create submount and create new inode (say b_ino), using
properties from a_ino. IOW, this should copy a_ino->i_no to
b_ino->b_ino given current code, IIUC.
-> Assume timeout has not happened and cached attrs have not expired.
-> And now b_ino->i_no (or ->orig_ino) will be returned to user space.