File 0005-btrfs-progs-add-helper-to-check-or-wait-for-exclusiv.patch of Package btrfsprogs.24931
From 741a437cdc6b0b258d262d611fd8fa9d5f08bd48 Mon Sep 17 00:00:00 2001
From: David Sterba <dsterba@suse.com>
Date: Thu, 5 Nov 2020 02:52:40 +0100
Subject: [PATCH] btrfs-progs: add helper to check or wait for exclusive operation
Add helper that will either check a running operation or wait until it's
done, so that commands can be started and enqueued. If there are more
enqueued, an attempt to avoid racing is done based on the remaining
waiting time of each command.
Signed-off-by: David Sterba <dsterba@suse.com>
---
utils.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
utils.h | 1
2 files changed, 70 insertions(+)
--- a/utils.c
+++ b/utils.c
@@ -2681,3 +2681,72 @@
return exclop_def[op];
return "UNKNOWN";
}
+
+/*
+ * Check if there's another exclusive operation running and either return error
+ * or wait until there's none in case @enqueue is true. The timeout between
+ * checks is 1 minute as we get notification on the sysfs file when the
+ * operation finishes.
+ *
+ * Return:
+ * 0 - caller can continue, nothing running or the status is not available
+ * 1 - another operation running
+ * <0 - there was another error
+ */
+int check_running_fs_exclop(int fd, const char *desc, bool enqueue)
+{
+ int sysfs_fd;
+ int exclop;
+ int ret;
+
+ sysfs_fd = sysfs_open_fsid_file(fd, "exclusive_operation");
+ if (sysfs_fd < 0) {
+ if (errno == ENOENT)
+ return 0;
+ return -errno;
+ }
+
+ exclop = get_fs_exclop(fd);
+ if (exclop <= 0) {
+ ret = 0;
+ goto out;
+ }
+
+ if (!enqueue) {
+ error(
+ "unable to start %s, another exclusive operation '%s' in progress",
+ desc, get_fs_exclop_name(exclop));
+ ret = 1;
+ goto out;
+ }
+
+ while (exclop > 0) {
+ fd_set fds;
+ struct timeval tv = { .tv_sec = 60, .tv_usec = 0 };
+
+ FD_ZERO(&fds);
+ FD_SET(sysfs_fd, &fds);
+
+ ret = select(sysfs_fd + 1, NULL, NULL, &fds, &tv);
+ if (ret < 0) {
+ ret = -errno;
+ break;
+ }
+ if (ret > 0) {
+ /*
+ * Notified before the timeout, check again before
+ * returning. In case there are more operations
+ * waiting, we want to reduce the chances to race so
+ * reuse the remaining time to randomize the order.
+ */
+ tv.tv_sec /= 2;
+ ret = select(sysfs_fd + 1, NULL, NULL, &fds, &tv);
+ exclop = get_fs_exclop(fd);
+ continue;
+ }
+ }
+out:
+ close(sysfs_fd);
+
+ return ret;
+}
--- a/utils.h
+++ b/utils.h
@@ -124,6 +124,7 @@
int get_fsid(const char *path, u8 *fsid, int silent);
int get_fsid_fd(int fd, u8 *fsid);
int get_fs_exclop(int fd);
+int check_running_fs_exclop(int fd, const char *desc, bool enqueue);
const char *get_fs_exclop_name(int op);
int is_seen_fsid(u8 *fsid, struct seen_fsid *seen_fsid_hash[]);