From 505e8b5d0a89aa528dbf98f801051620aa2546c1 Mon Sep 17 00:00:00 2001 From: Keith Reynolds Date: Fri, 27 Sep 2024 20:48:48 -0700 Subject: [PATCH] linux: use O_EXCL when opening a file for write On linux systems, opening a device with O_EXCL will fail with EBUSY if the drive is in use. For example, if a partition is mounted on /dev/nvme1n1p1, the current mounted filesystem check will allow running write workloads on /dev/nvme1n1 even if allow_mounted_write is zero. Opening /dev/nvme1n1 with O_EXCL will fail with EBUSY in that case. Add O_EXCL when opening a file with O_WRONLY or O_RDWR on linux systems. Fixes: https://github.com/axboe/fio/issues/1820 Signed-of-by: Keith Reynolds --- engines/nvme.c | 9 ++++++++- engines/xnvme.c | 8 ++++++++ filesetup.c | 12 +++++++++--- os/os-linux.h | 2 ++ oslib/linux-blkzoned.c | 9 ++++++++- 5 files changed, 35 insertions(+), 5 deletions(-) diff --git a/engines/nvme.c b/engines/nvme.c index 18010c0b55..6124d93689 100644 --- a/engines/nvme.c +++ b/engines/nvme.c @@ -819,7 +819,14 @@ int fio_nvme_reset_wp(struct thread_data *td, struct fio_file *f, /* If the file is not yet opened, open it for this function. */ fd = f->fd; if (fd < 0) { - fd = open(f->file_name, O_RDWR | O_LARGEFILE); + int flags = O_RDWR | O_LARGEFILE; + +#ifdef FIO_USE_O_EXCL + if (!td->o.allow_mounted_write) + flags |= O_EXCL; +#endif + + fd = open(f->file_name, flags); if (fd < 0) return -errno; } diff --git a/engines/xnvme.c b/engines/xnvme.c index 5f1af78d3d..fe4047ebce 100644 --- a/engines/xnvme.c +++ b/engines/xnvme.c @@ -302,6 +302,14 @@ static struct xnvme_opts xnvme_opts_from_fioe(struct thread_data *td) opts.direct = td->o.odirect; + opts.rdonly = opts.wronly = opts.rdwr = 0; + if (td_rw(td)) + opts.rdwr = 1; + else if (td_write(td)) + opts.wronly = 1; + else + opts.rdonly = 1; + return opts; } diff --git a/filesetup.c b/filesetup.c index cb42a852c8..7b41dc3016 100644 --- a/filesetup.c +++ b/filesetup.c @@ -719,6 +719,7 @@ int generic_open_file(struct thread_data *td, struct fio_file *f) int is_std = 0; int flags = 0; int from_hash = 0; + int write_flags = O_RDWR; dprint(FD_FILE, "fd open %s\n", f->file_name); @@ -744,10 +745,15 @@ int generic_open_file(struct thread_data *td, struct fio_file *f) if (f->filetype != FIO_TYPE_FILE) flags |= FIO_O_NOATIME; +#ifdef FIO_USE_O_EXCL + if (!td->o.allow_mounted_write && (flags & O_CREAT) == 0) + write_flags |= O_EXCL; +#endif + open_again: if (td_write(td)) { if (!read_only) - flags |= O_RDWR; + flags |= write_flags; if (td->o.verify_only) { flags &= ~O_RDWR; @@ -763,7 +769,7 @@ int generic_open_file(struct thread_data *td, struct fio_file *f) from_hash = file_lookup_open(f, flags); } else if (td_read(td)) { if (td_ioengine_flagged(td, FIO_RO_NEEDS_RW_OPEN) && !read_only) - flags |= O_RDWR; + flags |= write_flags; else flags |= O_RDONLY; @@ -774,7 +780,7 @@ int generic_open_file(struct thread_data *td, struct fio_file *f) } else if (td_trim(td)) { assert(!td_rw(td)); /* should have matched above */ if (!read_only) - flags |= O_RDWR; + flags |= write_flags; from_hash = file_lookup_open(f, flags); } diff --git a/os/os-linux.h b/os/os-linux.h index ead8295c44..71ee9bc2f6 100644 --- a/os/os-linux.h +++ b/os/os-linux.h @@ -430,4 +430,6 @@ static inline bool os_cpu_has(cpu_features feature) return have_feature; } +#define FIO_USE_O_EXCL + #endif diff --git a/oslib/linux-blkzoned.c b/oslib/linux-blkzoned.c index 1cc8d288b4..a89cb541d8 100644 --- a/oslib/linux-blkzoned.c +++ b/oslib/linux-blkzoned.c @@ -323,7 +323,14 @@ int blkzoned_reset_wp(struct thread_data *td, struct fio_file *f, /* If the file is not yet opened, open it for this function. */ fd = f->fd; if (fd < 0) { - fd = open(f->file_name, O_RDWR | O_LARGEFILE); + int flags = O_RDWR | O_LARGEFILE; + +#ifdef FIO_USE_O_EXCL + if (!td->o.allow_mounted_write) + flags |= O_EXCL; +#endif + + fd = open(f->file_name, flags); if (fd < 0) return -errno; }