1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2024-10-26 17:25:34 +03:00

tmpfiles: while aging, take a BSD file lock on each directory we descent into

Let's add a fully safe way to exclude certain directories from aging, by
taking a BSD file lock on them before aging them. This is useful for
clients that untar tarballs into /tmp or /var/tmp, which might have
really old timestamps, and to which the aging logic would be very harsh:
they can simply take a BSD file lock on any directory they like and thus
exclude it from automatic aging, and thus need not to be afraid of
untarring stuff below it.

Previously, similar functionality was already available through the
sticky bit on non-directories, but it's problematic, since as soon as
the bit is set no clean-up is done for it at all anymore, forever. Also,
it is not suitable for untarring stuff, since the sticky bit after all
is a concept denoted in the tarball itself.  BSD file locking semantics
are much much nicer there, as they are automatically released when the
application that has them dies, and they are entirely orthogonal to data
encoded in tarballs.

This patch takes BSD file locks only on *directories* while descending
down the tree, not on regular files. Moreover, it will do so in
non-blocking mode only, i.e. if anyone else has a lock the aging for a
dir and everything below it is immediately skipped for the current
clean-up iteration.

Of course applications might take BSD file locks for other reasons than
just prevent aging (i.e for their own reasons), but that should be
entirely OK, as in that case tmpfiles should step away from those files
anyway too: it's a good idea to stay away from any such locked file
anyway since it's apparently curretnly being manipulated.

This allows us to fix bugs like this:

https://github.com/systemd/mkosi/issues/252
This commit is contained in:
Lennart Poettering 2019-01-18 16:09:30 +01:00
parent 781bc44e83
commit 52b32b2aac

View File

@ -12,6 +12,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/xattr.h>
#include <sysexits.h>
@ -579,6 +580,7 @@ static int dir_cleanup(
}
if (S_ISDIR(s.st_mode)) {
_cleanup_closedir_ DIR *sub_dir = NULL;
if (mountpoint &&
streq(dent->d_name, "lost+found") &&
@ -590,7 +592,6 @@ static int dir_cleanup(
if (maxdepth <= 0)
log_warning("Reached max depth on \"%s\".", sub_path);
else {
_cleanup_closedir_ DIR *sub_dir;
int q;
sub_dir = xopendirat_nomod(dirfd(d), dent->d_name);
@ -601,6 +602,11 @@ static int dir_cleanup(
continue;
}
if (flock(dirfd(sub_dir), LOCK_EX|LOCK_NB) < 0) {
log_debug_errno(errno, "Couldn't acquire shared BSD lock on directory \"%s\", skipping: %m", p);
continue;
}
q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
if (q < 0)
r = q;