Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open control FD in gofer server (and directfs gofer client) with O_PATH. #10385

Open
ayushr2 opened this issue May 4, 2024 · 1 comment
Open
Labels
type: bug Something isn't working

Comments

@ayushr2
Copy link
Collaborator

ayushr2 commented May 4, 2024

Description

          > mountpoint_s3::fuse: open failed: inode error: inode 3 (full key "synmon/test_file.txt") is not writable while being read

The issue is that gVisor's gofer client (pkg/fsimpl/gofer/) opens the file read-only first and then opens it for writing, but mountpoint_s3::fuse refuses to support that. The gofer client first caches the dentry for the file being opened. It holds a "control FD" for all the dentries it caches. This control FD is opened with O_RDONLY|O_NONBLOCK:

// tryOpen tries to open() with different modes in the following order:
// 1. RDONLY | NONBLOCK: for all files, directories, ro mounts, FIFOs.
// Use non-blocking to prevent getting stuck inside open(2) for
// FIFOs. This option has no effect on regular files.
// 2. PATH: for symlinks, sockets.
func tryOpen(open func(int) (int, error)) (int, error) {
flags := []int{
unix.O_RDONLY | unix.O_NONBLOCK,
unix.O_PATH,
}

I think we should change that logic to open regular files with O_PATH only. Directories and FIFOs can continue to be opened with O_RDONLY.

Originally posted by @ayushr2 in awslabs/mountpoint-s3#862 (comment)

@ayushr2 ayushr2 added the type: bug Something isn't working label May 4, 2024
@ayushr2
Copy link
Collaborator Author

ayushr2 commented May 4, 2024

This work may be more involved. The control FD is used to perform various operations on a file (see usages). Some of those operations will fail with EBADF if the control FD is a O_PATH FD. For instance: fchmod(2), fchown(2) and fgetxattr(2). See Linux kernel source code for these syscalls; they use fdget(fd) => __fget_light(fd, FMODE_PATH) which returns NULL for O_PATH FDs. So we will need to open all files with O_PATH and upgrade to a readable FD when needed OR use f*at(2) syscall variant with AT_EMPTY_PATH (which effectively bypasses this issue).

Some questions:

  • How is fchmod(2) working for symlinks?
    func (d *directfsDentry) chmod(ctx context.Context, mode uint16) error {
    if !d.isSocket() {
    return unix.Fchmod(d.controlFD, uint32(mode))
    }
  • How is fgetxattr(2) working for symlinks and sockets?
    func (d *directfsDentry) getXattr(name string, size uint64) (string, error) {
    data := make([]byte, size)
    if _, err := unix.Fgetxattr(d.controlFD, name, data); err != nil {
    return "", err
    }
  • Can we open FIFOs with O_PATH?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant