Merge pull request #26936 from DaanDeMeyer/xopenat-lock

fs-util: Add xopenat_lock()
This commit is contained in:
Daan De Meyer
2023-03-23 07:49:12 +01:00
committed by GitHub
5 changed files with 125 additions and 24 deletions
+44
View File
@@ -3,6 +3,7 @@
#include <errno.h>
#include <stddef.h>
#include <stdlib.h>
#include <sys/file.h>
#include <linux/falloc.h>
#include <linux/magic.h>
#include <unistd.h>
@@ -13,6 +14,7 @@
#include "fileio.h"
#include "fs-util.h"
#include "hostname-util.h"
#include "lock-util.h"
#include "log.h"
#include "macro.h"
#include "missing_fcntl.h"
@@ -1099,6 +1101,9 @@ int xopenat(int dir_fd, const char *path, int flags, mode_t mode) {
bool made = false;
int r;
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(path);
if (FLAGS_SET(flags, O_DIRECTORY|O_CREAT)) {
r = RET_NERRNO(mkdirat(dir_fd, path, mode));
if (r == -EEXIST) {
@@ -1135,3 +1140,42 @@ int xopenat(int dir_fd, const char *path, int flags, mode_t mode) {
return TAKE_FD(fd);
}
int xopenat_lock(int dir_fd, const char *path, int flags, mode_t mode, LockType locktype, int operation) {
_cleanup_close_ int fd = -EBADF;
int r;
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(path);
assert(IN_SET(operation & ~LOCK_NB, LOCK_EX, LOCK_SH));
/* POSIX/UNPOSIX locks don't work on directories (errno is set to -EBADF so let's return early with
* the same error here). */
if (FLAGS_SET(flags, O_DIRECTORY) && locktype != LOCK_BSD)
return -EBADF;
for (;;) {
struct stat st;
fd = xopenat(dir_fd, path, flags, mode);
if (fd < 0)
return fd;
r = lock_generic(fd, locktype, operation);
if (r < 0)
return r;
/* If we acquired the lock, let's check if the file/directory still exists in the file
* system. If not, then the previous exclusive owner removed it and then closed it. In such a
* case our acquired lock is worthless, hence try again. */
if (fstat(fd, &st) < 0)
return -errno;
if (st.st_nlink > 0)
break;
fd = safe_close(fd);
}
return TAKE_FD(fd);
}
+3
View File
@@ -12,6 +12,7 @@
#include "alloc-util.h"
#include "errno-util.h"
#include "lock-util.h"
#include "time-util.h"
#include "user-util.h"
@@ -132,3 +133,5 @@ int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode);
int openat_report_new(int dirfd, const char *pathname, int flags, mode_t mode, bool *ret_newly_created);
int xopenat(int dir_fd, const char *path, int flags, mode_t mode);
int xopenat_lock(int dir_fd, const char *path, int flags, mode_t mode, LockType locktype, int operation);
+18 -23
View File
@@ -18,7 +18,6 @@
int make_lock_file_at(int dir_fd, const char *p, int operation, LockFile *ret) {
_cleanup_close_ int fd = -EBADF, dfd = -EBADF;
_cleanup_free_ char *t = NULL;
int r;
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(p);
@@ -38,28 +37,9 @@ int make_lock_file_at(int dir_fd, const char *p, int operation, LockFile *ret) {
if (!t)
return -ENOMEM;
for (;;) {
struct stat st;
fd = openat(dfd, p, O_CREAT|O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NOCTTY, 0600);
if (fd < 0)
return -errno;
r = unposix_lock(fd, operation);
if (r < 0)
return r == -EAGAIN ? -EBUSY : r;
/* If we acquired the lock, let's check if the file still exists in the file system. If not,
* then the previous exclusive owner removed it and then closed it. In such a case our
* acquired lock is worthless, hence try again. */
if (fstat(fd, &st) < 0)
return -errno;
if (st.st_nlink > 0)
break;
fd = safe_close(fd);
}
fd = xopenat_lock(dfd, p, O_CREAT|O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NOCTTY, 0600, LOCK_UNPOSIX, operation);
if (fd < 0)
return fd == -EAGAIN ? -EBUSY : fd;
*ret = (LockFile) {
.dir_fd = TAKE_FD(dfd),
@@ -183,3 +163,18 @@ void unposix_unlockpp(int **fd) {
(void) fcntl_lock(**fd, LOCK_UN, /*ofd=*/ true);
*fd = NULL;
}
int lock_generic(int fd, LockType type, int operation) {
assert(fd >= 0);
switch (type) {
case LOCK_BSD:
return RET_NERRNO(flock(fd, operation));
case LOCK_POSIX:
return posix_lock(fd, operation);
case LOCK_UNPOSIX:
return unposix_lock(fd, operation);
default:
assert_not_reached();
}
}
+8
View File
@@ -32,3 +32,11 @@ void unposix_unlockpp(int **fd);
#define CLEANUP_UNPOSIX_UNLOCK(fd) \
_cleanup_(unposix_unlockpp) _unused_ int *CONCATENATE(_cleanup_unposix_unlock_, UNIQ) = &(fd)
typedef enum LockType {
LOCK_BSD,
LOCK_POSIX,
LOCK_UNPOSIX,
} LockType;
int lock_generic(int fd, LockType type, int operation);