[PATCH] lib/ext2fs/unix_io.c: add flock operation to struct_unix_manager in e2fsprogs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



We noticed that systemd has an issue about symlink unreliable caused by
formatting filesystem and systemd operating on same device.
Issue Link: https://github.com/systemd/systemd/issues/23746

According to systemd doc, a BSD flock needs to be acquired before
formatting the device.
Related Link: https://systemd.io/BLOCK_DEVICE_LOCKING/

So we acquire flock after opening the device but before
writing superblock.

Signed-off-by: zhanchengbin <zhanchengbin1@xxxxxxxxxx>
---
 lib/ext2fs/unix_io.c  | 90 +++++++++++++++++++++++++++++++++++++++++--
 util/android_config.h |  1 +
 2 files changed, 87 insertions(+), 4 deletions(-)

diff --git a/lib/ext2fs/unix_io.c b/lib/ext2fs/unix_io.c
index e53db333..a0ca8b37 100644
--- a/lib/ext2fs/unix_io.c
+++ b/lib/ext2fs/unix_io.c
@@ -61,6 +61,9 @@
 #if HAVE_SYS_STAT_H
 #include <sys/stat.h>
 #endif
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
 #if HAVE_SYS_RESOURCE_H
 #include <sys/resource.h>
 #endif
@@ -634,18 +637,93 @@ static errcode_t flush_cached_blocks(io_channel channel,
 #endif
 #endif

+/* return 0 on success */
+int blkdev_lock(int fd, const char *devname)
+{
+	int oper, rc;
+	char *lock_mode = NULL;
+
+	lock_mode = getenv("LOCK_BLOCK_DEVICE");
+	if (!lock_mode)
+		lock_mode = "1";
+
+	if (strcasecmp(lock_mode, "yes") == 0 ||
+	    strcmp(lock_mode, "1") == 0)
+		oper = LOCK_EX;
+
+	else if (strcasecmp(lock_mode, "nonblock") == 0)
+		oper = LOCK_EX | LOCK_NB;
+
+	else if (strcasecmp(lock_mode, "no") == 0 ||
+		 strcmp(lock_mode, "0") == 0)
+		return 0;
+	else {
+		printf("unsupported lock mode: %s", lock_mode);
+		return -EINVAL;
+	}
+
+	if (!(oper & LOCK_NB)) {
+		/* Try non-block first to provide message */
+		rc = flock(fd, oper | LOCK_NB);
+		if (rc == 0)
+			return 0;
+		if (rc != 0 && errno == EWOULDBLOCK) {
+			fprintf(stderr, "%s: device already locked, waiting to get lock ... ",
+					devname);
+		}
+	}
+	rc = flock(fd, oper);
+	if (rc != 0) {
+		switch (errno) {
+		case EWOULDBLOCK: /* LOCK_NB */
+			printf("%s: device already locked", devname);
+			break;
+		default:
+			printf("%s: failed to get lock", devname);
+		}
+	}
+	return rc;
+}
+
+/* return 0 on success */
+int blkdev_unlock(int fd)
+{
+	int oper, rc;
+	char *lock_mode = NULL;
+
+	lock_mode = getenv("LOCK_BLOCK_DEVICE");
+	if (!lock_mode)
+		lock_mode = "1";
+
+	if (strcasecmp(lock_mode, "no") == 0 ||
+		 strcmp(lock_mode, "0") == 0)
+		return 0;
+	else
+		oper = LOCK_UN;
+
+	rc = flock(fd, oper);
+	return rc;
+}
+
 int ext2fs_open_file(const char *pathname, int flags, mode_t mode)
 {
+	int fd = -1;
 	if (mode)
 #if defined(HAVE_OPEN64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED)
-		return open64(pathname, flags, mode);
+		fd = open64(pathname, flags, mode);
 	else
-		return open64(pathname, flags);
+		fd = open64(pathname, flags);
 #else
-		return open(pathname, flags, mode);
+		fd = open(pathname, flags, mode);
 	else
-		return open(pathname, flags);
+		fd = open(pathname, flags);
 #endif
+	if (blkdev_lock(fd, pathname) != 0) {
+		printf("File %s is locked\n", pathname);
+		exit(-1);
+	}
+
+	return fd;
 }

 int ext2fs_stat(const char *path, ext2fs_struct_stat *buf)
@@ -926,6 +1004,10 @@ static errcode_t unix_close(io_channel channel)
 	retval = flush_cached_blocks(channel, data, 0);
 #endif

+	if(blkdev_unlock(data->dev) != 0){
+		printf("blkdev unlock error\n");
+		retval = errno;
+        }
 	if (close(data->dev) < 0)
 		retval = errno;
 	free_cache(data);
diff --git a/util/android_config.h b/util/android_config.h
index 6ac16fec..4dd3b69f 100644
--- a/util/android_config.h
+++ b/util/android_config.h
@@ -28,6 +28,7 @@
 #define HAVE_UTIME_H 1

 #define HAVE_SYS_STAT_H 1
+#define HAVE_SYS_FILE_H 1
 #if !defined(__APPLE__)
 # define HAVE_SYS_SYSMACROS_H 1
 #endif
--
2.33.0





[Index of Archives]     [Reiser Filesystem Development]     [Ceph FS]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite National Park]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Device Mapper]     [Linux Media]

  Powered by Linux