return EXIT_FAILURE;
}
- // try to take an exclusive and nonblocking BSD lock
+ // try to take an exclusive and nonblocking BSD lock (use O_WRONLY mode to ensure udev
+ // rescans the device once the lock is closed)
__attribute__((cleanup(closep))) int fd =
lock_whole_disk_from_devname(
argv[1],
- O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY,
+ O_WRONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY,
LOCK_EX|LOCK_NB);
if (fd < 0)
if (S_ISBLK(st.st_mode)) {
/* Lock the device so that udev doesn't interfere with our work */
- lock_fd = lock_whole_block_device(st.st_rdev, LOCK_EX);
+ lock_fd = lock_whole_block_device(st.st_rdev, O_WRONLY, LOCK_EX);
if (lock_fd < 0)
return log_error_errno(lock_fd, "Failed to lock whole block device of \"%s\": %m", device);
} else
return get_block_device_harder_fd(fd, ret);
}
-int lock_whole_block_device(dev_t devt, int operation) {
+int lock_whole_block_device(dev_t devt, int open_flags, int operation) {
_cleanup_close_ int lock_fd = -EBADF;
dev_t whole_devt;
int r;
- /* Let's get a BSD file lock on the whole block device, as per: https://systemd.io/BLOCK_DEVICE_LOCKING */
+ /* Let's get a BSD file lock on the whole block device, as per: https://systemd.io/BLOCK_DEVICE_LOCKING
+ *
+ * NB: it matters whether open_flags indicates open for write: only then will the eventual closing of
+ * the fd trigger udev's partitioning rescanning of the device (as it watches for IN_CLOSE_WRITE),
+ * hence make sure to pass the right value there. */
r = block_get_whole_disk(devt, &whole_devt);
if (r < 0)
return r;
- lock_fd = r = device_open_from_devnum(S_IFBLK, whole_devt, O_RDONLY|O_CLOEXEC|O_NONBLOCK, NULL);
- if (r < 0)
- return r;
+ lock_fd = device_open_from_devnum(S_IFBLK, whole_devt, open_flags|O_CLOEXEC|O_NONBLOCK|O_NOCTTY, NULL);
+ if (lock_fd < 0)
+ return lock_fd;
if (flock(lock_fd, operation) < 0)
return -errno;
int get_block_device_harder_fd(int fd, dev_t *dev);
int get_block_device_harder(const char *path, dev_t *dev);
-int lock_whole_block_device(dev_t devt, int operation);
+int lock_whole_block_device(dev_t devt, int open_flags, int operation);
int blockdev_partscan_enabled(sd_device *d);
int blockdev_partscan_enabled_fd(int fd);
return log_oom();
if (fd < 0) {
- fd = RET_NERRNO(open(node, O_RDONLY|O_CLOEXEC|O_NONBLOCK));
+ fd = RET_NERRNO(open(node, O_RDWR|O_CLOEXEC|O_NONBLOCK));
if (fd < 0)
return log_error_errno(fd, "Failed to open '%s': %m", node);
}
struct stat st;
int r;
- fd = open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
+ /* We open in O_WRONLY mode here, to trigger a rescan in udev once we are done */
+ fd = open(path, O_WRONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
if (fd < 0)
return log_error_errno(errno, "Failed to open '%s': %m", path);