Craig McQueen
Craig McQueen

Reputation: 43456

Linux CUSE: How to implement blocking or non-blocking operation

I'm interested in implementing a userspace char device in Linux using CUSE.

In a Linux kernel driver for char devices, the kernel driver .read function is supposed to implement either blocking or non-blocking operation depending on the file descriptor's O_NONBLOCK flag state.

But what about a CUSE driver .read function, if there is no data to read "yet"?

I tried implementing a .read function with a sleep(1) in it. I found that it kind of worked, but my CUSE driver became slow to respond to .write. So I suppose a CUSE .read function should not simply block for a long time. But I haven't found out how to do properly block so far, in either CUSE docs or CUSE example code or other projects that use CUSE.

Upvotes: 0

Views: 45

Answers (1)

Craig McQueen
Craig McQueen

Reputation: 43456

  • Is the CUSE driver .read function responsible for implementing both the blocking and non-blocking behaviours, depending on the file descriptor's O_NONBLOCK flag state?

I've examined the source code for the Linux kernel CUSE driver, and the userspace libfuse library. I don't see any code to automatically handle blocking/non-blocking behaviour according to the file descriptor's O_NONBLOCK flag state. So it looks as though it's the responsibility of the userspace driver implementation to check the O_NONBLOCK flag and explicitly implement the blocking and non-blocking behaviour.

The libfuse comment in fuse_common.h for struct fuse_file_info field flags says

Open flags. Available in open() and release()

But, the libfuse do_read() implementation makes the open flags also available in fi->flags in the .read() function. Similarly for the .write() function call. But not .ioctl() — I guess IOCTL calls are normally expected not to block — except for functions where that is the explicit purpose, such as TIOCMIWAIT.

  • How can the CUSE driver .read function implement a blocking read?

I tried implementing a .read function with a sleep(1) in it. I found that it kind of worked, but my CUSE driver became slow to respond to .write.

I was testing my prototype code using picocom. It sets O_NONBLOCK, so it expects .read() and .write() not to block. It superficially appeared to work with my blocking .read(), but didn't really work well, which explains my observation that data was delayed through the .write() function.

So I reworked my .read() function to check that flag.

        if (fi->flags & O_NONBLOCK) {
            fuse_reply_err(req, EAGAIN);
            return;
        }

I removed the sleep(1) from my function and implemented data pacing using clock_gettime(CLOCK_MONOTONIC, &ts) instead.

Upvotes: 0

Related Questions