1
0
mirror of https://github.com/systemd/systemd synced 2026-04-23 07:24:51 +02:00

Compare commits

...

5 Commits

Author SHA1 Message Date
Lennart Poettering
a321e0e463 sd-event: fix creation of floating event_add_time_change() event sources
We shouldn't auto-disable event sources we create in "floating" mode.
Hence don#t use the disabling destructor for event sources.

Given that noone else has access to this event source we just allocated
anyway there's no point in explicitly disabling it before freeing it.

Follow-up for ec75e8e07a0ad972e0c40e0a187e15a8d4fb3d66
2022-03-21 21:57:36 +00:00
Luca Boccassi
94c17d67be
Merge pull request #22808 from poettering/openat-report-newly
journal: add openat() wrapper that reports file creation, and use it in journal
2022-03-21 21:56:37 +00:00
Lennart Poettering
db5e7d75dc journal-file: port journal_file_open() to openat_report_new()
We so far had some magic logic in place that files we open for write
with size zero are freshly created. That of course is a bogus
assumption, in particular as this code deals with corrupted file systems
which oftentimes contain zero size inodes from left-over runs.

Let's fix this properly, and actually let the kernel tell us whether it
create the file or not.
2022-03-21 18:23:44 +01:00
Lennart Poettering
d120d897ec sd-journal: refuse invocation of journal_file_open() with O_RDONLY|O_CREAT 2022-03-21 18:23:44 +01:00
Lennart Poettering
ca8503f168 fs-util: add openat_report_new() wrapper around openat()
This is a wrapper around openat(). It works mostly the same, except for
one thing: it race-freely reports whether we just created the indicated
file in case O_CREAT is passed without O_EXCL.
2022-03-21 18:23:44 +01:00
5 changed files with 111 additions and 11 deletions

View File

@ -1083,3 +1083,42 @@ int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode) {
return TAKE_FD(fd); return TAKE_FD(fd);
} }
int openat_report_new(int dirfd, const char *pathname, int flags, mode_t mode, bool *ret_newly_created) {
unsigned attempts = 7;
/* Just like openat(), but adds one thing: optionally returns whether we created the file anew or if
* it already existed before. This is only relevant of O_CREAT is set without O_EXCL, and thus will
* shortcut to openat() otherwise */
if (!FLAGS_SET(flags, O_CREAT) || FLAGS_SET(flags, O_EXCL) || !ret_newly_created)
return RET_NERRNO(openat(dirfd, pathname, flags, mode));
for (;;) {
int fd;
/* First, attempt to open without O_CREAT/O_EXCL, i.e. open existing file */
fd = openat(dirfd, pathname, flags & ~(O_CREAT | O_EXCL), mode);
if (fd >= 0) {
*ret_newly_created = false;
return fd;
}
if (errno != ENOENT)
return -errno;
/* So the file didn't exist yet, hence create it with O_CREAT/O_EXCL. */
fd = openat(dirfd, pathname, flags | O_CREAT | O_EXCL, mode);
if (fd >= 0) {
*ret_newly_created = true;
return fd;
}
if (errno != EEXIST)
return -errno;
/* Hmm, so now we got EEXIST? So it apparently exists now? If so, let's try to open again
* without the two flags. But let's not spin forever, hnce put a limit on things */
if (--attempts == 0) /* Give up eventually, somebody is playing with us */
return -EEXIST;
}
}

View File

@ -110,3 +110,5 @@ int posix_fallocate_loop(int fd, uint64_t offset, uint64_t size);
int parse_cifs_service(const char *s, char **ret_host, char **ret_service, char **ret_path); int parse_cifs_service(const char *s, char **ret_host, char **ret_service, char **ret_path);
int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode); 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);

View File

@ -124,7 +124,7 @@ int event_source_is_enabled(sd_event_source *s) {
} }
int event_add_time_change(sd_event *e, sd_event_source **ret, sd_event_io_handler_t callback, void *userdata) { int event_add_time_change(sd_event *e, sd_event_source **ret, sd_event_io_handler_t callback, void *userdata) {
_cleanup_(sd_event_source_disable_unrefp) sd_event_source *s = NULL; _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
_cleanup_close_ int fd = -1; _cleanup_close_ int fd = -1;
int r; int r;

View File

@ -3336,6 +3336,9 @@ int journal_file_open(
if (!IN_SET((flags & O_ACCMODE), O_RDONLY, O_RDWR)) if (!IN_SET((flags & O_ACCMODE), O_RDONLY, O_RDWR))
return -EINVAL; return -EINVAL;
if ((flags & O_ACCMODE) == O_RDONLY && FLAGS_SET(flags, O_CREAT))
return -EINVAL;
if (fname && (flags & O_CREAT) && !endswith(fname, ".journal")) if (fname && (flags & O_CREAT) && !endswith(fname, ".journal"))
return -EINVAL; return -EINVAL;
@ -3421,9 +3424,9 @@ int journal_file_open(
* or so, we likely fail quickly than block for long. For regular files O_NONBLOCK has no effect, hence * or so, we likely fail quickly than block for long. For regular files O_NONBLOCK has no effect, hence
* it doesn't hurt in that case. */ * it doesn't hurt in that case. */
f->fd = open(f->path, f->flags|O_CLOEXEC|O_NONBLOCK, f->mode); f->fd = openat_report_new(AT_FDCWD, f->path, f->flags|O_CLOEXEC|O_NONBLOCK, f->mode, &newly_created);
if (f->fd < 0) { if (f->fd < 0) {
r = -errno; r = f->fd;
goto fail; goto fail;
} }
@ -3433,6 +3436,19 @@ int journal_file_open(
r = fd_nonblock(f->fd, false); r = fd_nonblock(f->fd, false);
if (r < 0) if (r < 0)
goto fail; goto fail;
if (!newly_created) {
r = journal_file_fstat(f);
if (r < 0)
goto fail;
}
} else {
r = journal_file_fstat(f);
if (r < 0)
goto fail;
/* If we just got the fd passed in, we don't really know if we created the file anew */
newly_created = f->last_stat.st_size == 0 && f->writable;
} }
f->cache_fd = mmap_cache_add_fd(mmap_cache, f->fd, prot_from_flags(flags)); f->cache_fd = mmap_cache_add_fd(mmap_cache, f->fd, prot_from_flags(flags));
@ -3441,12 +3457,7 @@ int journal_file_open(
goto fail; goto fail;
} }
r = journal_file_fstat(f); if (newly_created) {
if (r < 0)
goto fail;
if (f->last_stat.st_size == 0 && f->writable) {
(void) journal_file_warn_btrfs(f); (void) journal_file_warn_btrfs(f);
/* Let's attach the creation time to the journal file, so that the vacuuming code knows the age of this /* Let's attach the creation time to the journal file, so that the vacuuming code knows the age of this
@ -3473,8 +3484,6 @@ int journal_file_open(
r = journal_file_fstat(f); r = journal_file_fstat(f);
if (r < 0) if (r < 0)
goto fail; goto fail;
newly_created = true;
} }
if (f->last_stat.st_size < (off_t) HEADER_SIZE_MIN) { if (f->last_stat.st_size < (off_t) HEADER_SIZE_MIN) {

View File

@ -970,6 +970,56 @@ TEST(open_mkdir_at) {
assert_se(subsubdir_fd >= 0); assert_se(subsubdir_fd >= 0);
} }
TEST(openat_report_new) {
_cleanup_free_ char *j = NULL;
_cleanup_(rm_rf_physical_and_freep) char *d = NULL;
_cleanup_close_ int fd = -1;
bool b;
assert_se(mkdtemp_malloc(NULL, &d) >= 0);
j = path_join(d, "test");
assert_se(j);
fd = openat_report_new(AT_FDCWD, j, O_RDWR|O_CREAT, 0666, &b);
assert_se(fd >= 0);
fd = safe_close(fd);
assert_se(b);
fd = openat_report_new(AT_FDCWD, j, O_RDWR|O_CREAT, 0666, &b);
assert_se(fd >= 0);
fd = safe_close(fd);
assert_se(!b);
fd = openat_report_new(AT_FDCWD, j, O_RDWR|O_CREAT, 0666, &b);
assert_se(fd >= 0);
fd = safe_close(fd);
assert_se(!b);
assert_se(unlink(j) >= 0);
fd = openat_report_new(AT_FDCWD, j, O_RDWR|O_CREAT, 0666, &b);
assert_se(fd >= 0);
fd = safe_close(fd);
assert_se(b);
fd = openat_report_new(AT_FDCWD, j, O_RDWR|O_CREAT, 0666, &b);
assert_se(fd >= 0);
fd = safe_close(fd);
assert_se(!b);
assert_se(unlink(j) >= 0);
fd = openat_report_new(AT_FDCWD, j, O_RDWR|O_CREAT, 0666, NULL);
assert_se(fd >= 0);
fd = safe_close(fd);
fd = openat_report_new(AT_FDCWD, j, O_RDWR|O_CREAT, 0666, &b);
assert_se(fd >= 0);
fd = safe_close(fd);
assert_se(!b);
}
static int intro(void) { static int intro(void) {
arg_test_dir = saved_argv[1]; arg_test_dir = saved_argv[1];
return EXIT_SUCCESS; return EXIT_SUCCESS;