btrfs-progs: open path in non-blocking mode when reading fs id

There's a report that reading properties from a sound device the system
is stuck and then gets rebooted by watchdog. Reading from fifo files
gets stuck as well, although this would not trigger the watchdog.

The reason is that open() on fifo files is blocking until the other end
of the pipe is opened. For device nodes it's driver specific, most
device nodes fail right away:

  $ btrfs prop get /dev/tty
  ERROR: object is not a btrfs object: /dev/tty

In case of the sound device the consequences were fatal. We can fix that
by opening the path on non-blocking mode. This is only for reading the
fsid, the fd is closed right after the ioctl so the non-blocking mode
does not affect other operation.

The blocking mode must be used for block devices as e.g. loop devices
may not be finalized when the open() call returns and get_fsid fails.
The known problematic devices are character and fifos.

Issue: #699
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
David Sterba 2023-10-31 16:53:51 +01:00
parent d185801b45
commit f240c6114d

View File

@ -22,6 +22,7 @@
#include <sys/time.h>
#include <sys/sysinfo.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
@ -337,8 +338,23 @@ int get_fsid(const char *path, u8 *fsid, int silent)
{
int ret;
int fd;
int flags = O_RDONLY;
struct stat st;
fd = open(path, O_RDONLY);
ret = stat(path, &st);
if (ret < 0) {
if (!silent)
error("failed to stat %s: %m", path);
return -errno;
}
/*
* Open in non-blocking mode in case that path is a fifo or a special
* character device where opening gets stuck (but is interruptible).
*/
if ((st.st_mode & S_IFMT) == S_IFCHR || (st.st_mode & S_IFMT) == S_IFIFO)
flags |= O_NONBLOCK;
fd = open(path, flags);
if (fd < 0) {
if (!silent)
error("failed to open %s: %m", path);