diff mbox series

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

Message ID 115aa2d8-0c05-df99-518c-99211762b6c8@huawei.com
State New
Headers show
Series lib/ext2fs/unix_io.c: add flock operation to struct_unix_manager in e2fsprogs | expand

Commit Message

zhanchengbin Oct. 15, 2022, 8:35 a.m. UTC
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@huawei.com>
---
  lib/ext2fs/unix_io.c  | 90 +++++++++++++++++++++++++++++++++++++++++--
  util/android_config.h |  1 +
  2 files changed, 87 insertions(+), 4 deletions(-)
diff mbox series

Patch

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