mirror of
https://github.com/systemd/systemd.git
synced 2024-10-26 17:27:41 +03:00
logind: make $XDG_RUNTIME_DIR a per-user tmpfs
This way each user allocates from his own pool, with its own size limit. This puts the size limit by default to 10% of the physical RAM size but makes it configurable in logind.conf.
This commit is contained in:
parent
b5d742138f
commit
1c231f5648
@ -180,6 +180,7 @@ AC_SUBST([OUR_LDFLAGS], "$with_ldflags $address_sanitizer_ldflags")
|
||||
|
||||
AC_CHECK_SIZEOF(pid_t)
|
||||
AC_CHECK_SIZEOF(uid_t)
|
||||
AC_CHECK_SIZEOF(gid_t)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# we use python to build the man page index, and for systemd-python
|
||||
|
@ -295,6 +295,28 @@
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>RuntimeDirectorySize=</varname></term>
|
||||
|
||||
<listitem><para>Sets the size limit on
|
||||
the
|
||||
<varname>$XDG_RUNTIME_DIR</varname>
|
||||
runtime directory for each user who
|
||||
logs in. Takes a size in bytes,
|
||||
possibly suffixed with the usual K, G,
|
||||
M, T suffixes, to the base 1024
|
||||
(IEC). Alternatively, a percentage
|
||||
suffixed by <literal>%</literal> may
|
||||
be specified, which sets the size
|
||||
limit relative to the amount of
|
||||
physical RAM. Defaults to 10%. Note
|
||||
that this size is a safety limit
|
||||
only. As each runtime directory is a
|
||||
tmpfs file system it will only consume
|
||||
as much memory as it is filled up
|
||||
to.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
@ -30,3 +30,4 @@ Login.HibernateKeyIgnoreInhibited, config_parse_bool, 0, offsetof(Manag
|
||||
Login.LidSwitchIgnoreInhibited, config_parse_bool, 0, offsetof(Manager, lid_switch_ignore_inhibited)
|
||||
Login.IdleAction, config_parse_handle_action, 0, offsetof(Manager, idle_action)
|
||||
Login.IdleActionSec, config_parse_sec, 0, offsetof(Manager, idle_action_usec)
|
||||
Login.RuntimeDirectorySize, config_parse_tmpfs_size, 0, offsetof(Manager, runtime_dir_size)
|
||||
|
@ -19,6 +19,7 @@
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <sys/mount.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
@ -28,10 +29,12 @@
|
||||
#include "hashmap.h"
|
||||
#include "strv.h"
|
||||
#include "fileio.h"
|
||||
#include "path-util.h"
|
||||
#include "special.h"
|
||||
#include "unit-name.h"
|
||||
#include "bus-util.h"
|
||||
#include "bus-error.h"
|
||||
#include "conf-parser.h"
|
||||
#include "logind-user.h"
|
||||
|
||||
User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
|
||||
@ -311,21 +314,35 @@ static int user_mkdir_runtime_path(User *u) {
|
||||
}
|
||||
|
||||
if (!u->runtime_path) {
|
||||
if (asprintf(&p, "/run/user/%lu", (unsigned long) u->uid) < 0)
|
||||
if (asprintf(&p, "/run/user/" UID_FMT, u->uid) < 0)
|
||||
return log_oom();
|
||||
} else
|
||||
p = u->runtime_path;
|
||||
|
||||
r = mkdir_safe_label(p, 0700, u->uid, u->gid);
|
||||
if (r < 0) {
|
||||
log_error("Failed to create runtime directory %s: %s", p, strerror(-r));
|
||||
free(p);
|
||||
u->runtime_path = NULL;
|
||||
return r;
|
||||
if (path_is_mount_point(p, false) <= 0) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
|
||||
mkdir(p, 0700);
|
||||
|
||||
if (asprintf(&t, "mode=0700,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size) < 0) {
|
||||
r = log_oom();
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = mount("tmpfs", p, "tmpfs", MS_NODEV|MS_NOSUID, t);
|
||||
if (r < 0) {
|
||||
log_error("Failed to mount per-user tmpfs directory %s: %s", p, strerror(-r));
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
u->runtime_path = p;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
free(p);
|
||||
u->runtime_path = NULL;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int user_start_slice(User *u) {
|
||||
@ -484,6 +501,13 @@ static int user_remove_runtime_path(User *u) {
|
||||
if (!u->runtime_path)
|
||||
return 0;
|
||||
|
||||
r = rm_rf(u->runtime_path, false, false, false);
|
||||
if (r < 0)
|
||||
log_error("Failed to remove runtime directory %s: %s", u->runtime_path, strerror(-r));
|
||||
|
||||
if (umount2(u->runtime_path, MNT_DETACH) < 0)
|
||||
log_error("Failed to unmount user runtime directory %s: %m", u->runtime_path);
|
||||
|
||||
r = rm_rf(u->runtime_path, false, true, false);
|
||||
if (r < 0)
|
||||
log_error("Failed to remove runtime directory %s: %s", u->runtime_path, strerror(-r));
|
||||
@ -691,3 +715,57 @@ static const char* const user_state_table[_USER_STATE_MAX] = {
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
|
||||
|
||||
int config_parse_tmpfs_size(
|
||||
const char* unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
size_t *sz = data;
|
||||
const char *e;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
e = endswith(rvalue, "%");
|
||||
if (e) {
|
||||
unsigned long ul;
|
||||
char *f;
|
||||
|
||||
errno = 0;
|
||||
ul = strtoul(rvalue, &f, 10);
|
||||
if (errno != 0 || f != e) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Failed to parse percentage value, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ul <= 0 || ul >= 100) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Percentage value out of range, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul) / (uint64_t) 100));
|
||||
} else {
|
||||
off_t o;
|
||||
|
||||
r = parse_size(rvalue, 1024, &o);
|
||||
if (r < 0 || (off_t) (size_t) o != o) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*sz = PAGE_ALIGN((size_t) o);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -60,6 +60,8 @@ Manager *manager_new(void) {
|
||||
m->idle_action = HANDLE_IGNORE;
|
||||
m->idle_action_not_before_usec = now(CLOCK_MONOTONIC);
|
||||
|
||||
m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */
|
||||
|
||||
m->devices = hashmap_new(string_hash_func, string_compare_func);
|
||||
m->seats = hashmap_new(string_hash_func, string_compare_func);
|
||||
m->sessions = hashmap_new(string_hash_func, string_compare_func);
|
||||
|
@ -24,3 +24,4 @@
|
||||
#LidSwitchIgnoreInhibited=yes
|
||||
#IdleAction=ignore
|
||||
#IdleActionSec=30min
|
||||
#RuntimeDirectorySize=10%
|
||||
|
@ -123,6 +123,8 @@ struct Manager {
|
||||
Hashmap *polkit_registry;
|
||||
|
||||
sd_event_source *lid_switch_ignore_event_source;
|
||||
|
||||
size_t runtime_dir_size;
|
||||
};
|
||||
|
||||
Manager *manager_new(void);
|
||||
@ -185,3 +187,5 @@ int manager_watch_busname(Manager *manager, const char *name);
|
||||
void manager_drop_busname(Manager *manager, const char *name);
|
||||
|
||||
int manager_set_lid_switch_ignore(Manager *m, usec_t until);
|
||||
|
||||
int config_parse_tmpfs_size(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
|
@ -98,7 +98,7 @@ static inline size_t ALIGN_TO(size_t l, size_t ali) {
|
||||
return ((l + ali - 1) & ~(ali - 1));
|
||||
}
|
||||
|
||||
#define ALIGN_TO_PTR(p, ali) ((void*) ALIGN_TO((unsigned long) p))
|
||||
#define ALIGN_TO_PTR(p, ali) ((void*) ALIGN_TO((unsigned long) p, ali))
|
||||
|
||||
#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0]))
|
||||
|
||||
|
@ -6291,3 +6291,15 @@ const char* personality_to_string(unsigned long p) {
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint64_t physical_memory(void) {
|
||||
long mem;
|
||||
|
||||
/* We return this as uint64_t in case we are running as 32bit
|
||||
* process on a 64bit kernel with huge amounts of memory */
|
||||
|
||||
mem = sysconf(_SC_PHYS_PAGES);
|
||||
assert(mem > 0);
|
||||
|
||||
return (uint64_t) mem * (uint64_t) page_size();
|
||||
}
|
||||
|
@ -58,6 +58,14 @@
|
||||
# error Unknown uid_t size
|
||||
#endif
|
||||
|
||||
#if SIZEOF_GID_T == 4
|
||||
# define GID_FMT "%" PRIu32
|
||||
#elif SIZEOF_GID_T == 2
|
||||
# define GID_FMT "%" PRIu16
|
||||
#else
|
||||
# error Unknown gid_t size
|
||||
#endif
|
||||
|
||||
#include "macro.h"
|
||||
#include "time-util.h"
|
||||
|
||||
@ -883,3 +891,5 @@ int fd_warn_permissions(const char *path, int fd);
|
||||
|
||||
unsigned long personality_from_string(const char *p);
|
||||
const char *personality_to_string(unsigned long);
|
||||
|
||||
uint64_t physical_memory(void);
|
||||
|
Loading…
Reference in New Issue
Block a user