1

I'm recently working on fuse, but yet still cant have a grasp of how it works since i have very little knowledge about filesystem in linux. One of the most confusing thing is that what will happen if i use syscall open() to open a file within the function for the fuse_operation "open", like the code below

int bb_open(const char *path, struct fuse_file_info *fi)
{
    int retstat = 0;
    int fd;
    char fpath[PATH_MAX];

    bb_fullpath(fpath, path);
    
    log_msg("bb_open(fpath\"%s\", fi=0x%08x)\n",
        fpath,  (int) fi);
    
    fd = open(fpath, fi->flags);
    if (fd < 0)
    retstat = bb_error("bb_open open");
    
    fi->fh = fd;
    log_fi(fi);
    
    return retstat;
}

My assumption was:

  1. A file within this filesystem("myfilesystem") is being opened, the request eventually gets accepted by fuse and the bb_open() is invoked.
  2. When the execution reaches "fd = open(fpath, fi->flags)", it is going to open() a file within this filesystem again which goes back to step one, then comes a loop.

BUT after trying the code, it actually end up opening the file successfully, which confuses me. Did i miss something important? Hope i make this problem understandable, and thanks in advance!


EDIT

thanks for the help guys! but i still couldnt get the deadlock that user253751 have metioned, i think i should post more details here:

static int hello_getattr(const char *path, struct stat *stbuf,
                         struct fuse_file_info *fi)
{
        (void) fi;
        int res = 0;
        memset(stbuf, 0, sizeof(struct stat));
        if (strcmp(path, "/") == 0) {
                stbuf->st_mode = S_IFDIR | 0755;
                stbuf->st_nlink = 2;
        } else if (strcmp(path+1, "hello") == 0) {
                stbuf->st_mode = S_IFREG | 0444;
                stbuf->st_nlink = 1;
                stbuf->st_size = strlen("hello there");
        } else
                res = -ENOENT;
        return res;
}
static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
                         off_t offset, struct fuse_file_info *fi,
                         enum fuse_readdir_flags flags)
{
        (void) offset;
        (void) fi;
        (void) flags;
        if (strcmp(path, "/") != 0)
                return -ENOENT;
        filler(buf, ".", NULL, 0, 0);
        filler(buf, "..", NULL, 0, 0);
        filler(buf, "hello", NULL, 0, 0);
        return 0;
}
static int hello_open(const char *path, struct fuse_file_info *fi)
{
        char* fpath = get_full_path(path);
        int fd = open(fpath,O_RDONLY);
        fi->fh = fd;
        log1(fpath);
        log1("  open\n");
        return 0;
}
static int hello_read(const char *path, char *buf, size_t size, off_t offset,
                      struct fuse_file_info *fi)
{
        char* fpath = get_full_path(path);
        read(fi->fh,buf,size); 
        log1(fpath);
        log1("  read\n");
        return size;
}

Basically i use the hello_readdir() to fill a filename to the directory,then tell the hello_getattr() to get some random info for the file. Then i "tail" the file five times, and this is what i get from the log

/home/P1G3s/WorkSpace/PIT/libfuse-fuse-3.9.2/example/hello  open
/home/P1G3s/WorkSpace/PIT/libfuse-fuse-3.9.2/example/hello  read
/home/P1G3s/WorkSpace/PIT/libfuse-fuse-3.9.2/example/hello  open
/home/P1G3s/WorkSpace/PIT/libfuse-fuse-3.9.2/example/hello  open
/home/P1G3s/WorkSpace/PIT/libfuse-fuse-3.9.2/example/hello  open

i thought it should not be opening a file that does not exist, but it seems the open() is doing fine and no deadlock happened, however the read wont show up after the first tail.

  • Is the path produced by `bb_fullpath` outside the mount point of your FUSE filesystem? – Ian Abbott Jul 01 '20 at 09:58
  • What are some example values for path and fpath? – user253751 Jul 01 '20 at 09:58
  • Also, your use of `open()` is incorrect. If the `open()` call could create the file it requires a third argument to specify the created file's initial permissions. – Andrew Henle Jul 01 '20 at 10:28
  • Oh yes, i think the way i created the file is a bit odd, i use the method as example "hello" of libfuse did, the file is added through filler() under the readdir operation, does that mean the file open is merely a name? – juicyliberty Jul 01 '20 at 10:45
  • @Ian Abbott Sorry for the confusion, i didnt use bb_fullpath(), i just input the path manually, the file is right under the mount point. I tried both relative path and absolute path, the file is opened successfully under both circumstances. i'm using python to open the file, and it seems to open the file. – juicyliberty Jul 01 '20 at 11:02

1 Answers1

1

If you try to open a file inside your own FUSE filesystem, this will create a deadlock because open is waiting for your FUSE filesystem to finish processing the last open request before it sends the next one, but your FUSE filesystem is waiting for open to finish before it finishes that request.

But if you open another file that isn't inside your FUSE filesystem, there's no problem. You open the different file, and finish processing the other program's open request, and then open returns in the other program. It's just recursion.

user253751
  • 57,427
  • 7
  • 48
  • 90
  • thank you for the reply sir, so it is a deadlock instead of a loop? does that mean the bb_open that i defined for the fuse_operation is different from the syscall open() under the filesystem that fuse created? – juicyliberty Jul 01 '20 at 10:51
  • @HolyCheeses I don't understand the question, but bb_open is not a syscall – user253751 Jul 01 '20 at 10:52
  • I assume that bb_open() is defined as a fuse_operation "open" that act as a as the syscall open() only under the filesystem fuse created, is my assumption right? – juicyliberty Jul 01 '20 at 11:01
  • @HolyCheeses The syscall "open" is the syscall "open". The syscall code checks whether the path is on a FUSE filesystem, and if it is, then it sends a message to the FUSE server process, which says "hey, someone just called 'open' on one of your files, what should I tell them?" and waits for a reply. – user253751 Jul 01 '20 at 11:03
  • oh i think i get it, then the FUSE tell it to execute bb_open(), but it gets blocked right until the open() within the bb_open(), because the last open() is not done yet. So the bb_open() is actually a part of the open() – juicyliberty Jul 01 '20 at 11:17
  • @HolyCheeses basically yes. Actually the second open() will send a message to your process but your process is not receiving that message at that moment, it's waiting for open() instead. If you had a multithreaded FUSE program, it *might* work (unreliably, I think). – user253751 Jul 01 '20 at 11:58
  • Thank you! Really informative! After some testing i still cant manage to get that deadlock, i use the filler() for readdir just to fill a filename to the directory, and set some random file information for getattr(), then use a absolute full path for open(), and log some information after the open(). But it seems to be opened quite flawlessly... – juicyliberty Jul 02 '20 at 02:56
  • @HolyCheeses What's the path you are trying to open, and what's the path where your FUSE filesystem is mounted? – user253751 Jul 02 '20 at 09:31
  • you can take a look at the edit above, the path im trying to open is "/home/P1G3s/WorkSpace/PIT/libfuse-fuse-3.9.2/example/hello". the mount point is "/home/P1G3s/WorkSpace/PIT/libfuse-fuse-3.9.2/example" – juicyliberty Jul 02 '20 at 10:16
  • @HolyCheese It doesn't tell me the path where the FUSE filesystem is mounted – user253751 Jul 02 '20 at 10:18
  • sry about that i tried to open a new line, it submit the comment instead XD – juicyliberty Jul 02 '20 at 10:19
  • Well that should be impossible. Your program prints "open" *after* the open finishes. It should be either a deadlock or infinite recursion, and never get to the point where it prints "open" – user253751 Jul 02 '20 at 10:24
  • that's what i thought too, it might be some kind of very low level stuff that i have not heard of yet, i think i shouldn't dwell on it too much and save it for the future XD. anyway, tons of thanks sir! – juicyliberty Jul 02 '20 at 10:37