Skip to content

Commit c67f5f8

Browse files
authored
Merge pull request #691 from mihalicyn/psi_write_support
/proc/pressure/{cpu, io, memory} virtualization
2 parents 6957cc1 + 456047f commit c67f5f8

File tree

14 files changed

+704
-173
lines changed

14 files changed

+704
-173
lines changed

.github/actions/build/action.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ runs:
4848
meson setup build \
4949
-Ddocs=false \
5050
-Dtests=true \
51+
-Dmocks=true \
5152
-Dinit-script=systemd \
5253
-Dprefix=/usr \
5354
-Db_sanitize=address,undefined

.github/workflows/tests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ jobs:
3838
- name: Test
3939
env:
4040
CC: ${{ matrix.compiler }}
41+
LIBFUSE: ${{ matrix.fuse }}
4142
run: |
4243
echo "::group::Running the testsuite"
4344

meson.build

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ conf.set_quoted('LXCFSTARGETDIR', join_paths(localstatedir, 'lib/lxcfs'))
6969
# Custom configuration.
7070
init_script = get_option('init-script')
7171
want_tests = get_option('tests')
72+
want_mocks = get_option('mocks')
7273
want_docs = get_option('docs')
7374

7475
# Build flags.
@@ -232,12 +233,18 @@ liblxcfs_common_dependencies = declare_dependency(
232233
libfuse,
233234
])
234235

236+
liblxcfs_cargs = []
237+
if want_mocks == true
238+
liblxcfs_cargs = ['-DPSITRIGGERTEST', '-DDEBUG']
239+
endif
240+
235241
liblxcfs = shared_module(
236242
'lxcfs',
237243
liblxcfs_sources,
238244
dependencies: liblxcfs_common_dependencies,
239245
install: true,
240-
install_dir: lxcfsdir)
246+
install_dir: lxcfsdir,
247+
c_args: liblxcfs_cargs)
241248

242249
# Tests.
243250
test_programs = []
@@ -248,7 +255,7 @@ if want_tests == true
248255
dependencies: liblxcfs_common_dependencies,
249256
install: false,
250257
install_dir: lxcfsdir,
251-
c_args: '-DRELOADTEST -DDEBUG')
258+
c_args: ['-DRELOADTEST', '-DDEBUG'])
252259
endif
253260

254261
# RPM spec.
@@ -306,6 +313,7 @@ status = [
306313
'lxcfs source root directory: @0@'.format(project_source_root),
307314
'init system(s): @0@'.format(init_script),
308315
'tests: @0@'.format(want_tests),
316+
'mocks: @0@'.format(want_mocks),
309317
'documentation: @0@'.format(want_docs),
310318
]
311319
message('\n '.join(status))

meson_options.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
option('tests', type : 'boolean', value: 'false',
44
description : 'enable tests')
55

6+
option('mocks', type : 'boolean', value: 'false',
7+
description : 'enable CI-only features (mocks some things in LXCFS for CI/testing purposes)')
8+
69
option('runtime-path', type : 'string', value : '/run',
710
description : 'the runtime directory')
811

src/bindings.h

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,16 @@ enum lxcfs_virt_t {
8787
#define LXCFS_TYPE_SYS(type) (type >= LXC_TYPE_SYS && type <= LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE)
8888
#define LXCFS_TYPE_OK(type) (type >= LXC_TYPE_CGDIR && type < LXC_TYPE_MAX)
8989

90+
/*
91+
* This signal will be used in /proc/pressure/{cpu, memory, io} poll()
92+
* virtualization to notify a background thread that it's
93+
* a time to finish.
94+
*
95+
* We don't need a handler for this, we want this signal to be
96+
* ignored, but interrupt any interruptible syscall like poll().
97+
*/
98+
#define SIG_NOTIFY_POLL_WAKEUP (SIGRTMIN + 0)
99+
90100
/*
91101
* This signal will be used to signal fuse request processing thread that
92102
* request was interrupted (FUSE_INTERRUPT came from the kernel).
@@ -106,13 +116,20 @@ extern int rwlock_rdlock_interruptible(pthread_rwlock_t *l);
106116
extern int rwlock_wrlock_interruptible(pthread_rwlock_t *l);
107117

108118
struct file_info {
109-
char *controller;
110-
char *cgroup;
111-
char *file;
119+
union {
120+
struct {
121+
char *controller;
122+
char *cgroup;
123+
char *file;
124+
};
125+
struct {
126+
void *private_data;
127+
};
128+
};
112129
int type;
113130
char *buf; /* unused */
114131
int buflen;
115-
int size; /*actual data size */
132+
int size; /* actual data size */
116133
int cached;
117134
};
118135

@@ -125,17 +142,19 @@ struct lxcfs_opts {
125142
* and the use of bool instead of explicited __u32 and __u64 we can't.
126143
*/
127144
__u32 version;
128-
// As of opts version 2.
129-
char runtime_path[PATH_MAX];
145+
// As of opts version 2.
146+
char runtime_path[PATH_MAX];
130147
bool zswap_off;
148+
bool psi_poll_on;
131149
};
132150

133151
typedef enum lxcfs_opt_t {
134-
LXCFS_SWAP_ON = 0,
135-
LXCFS_PIDFD_ON = 1,
136-
LXCFS_CFS_ON = 2,
137-
LXCFS_ZSWAP_ON = 3,
138-
LXCFS_OPTS_MAX = LXCFS_ZSWAP_ON,
152+
LXCFS_SWAP_ON = 0,
153+
LXCFS_PIDFD_ON = 1,
154+
LXCFS_CFS_ON = 2,
155+
LXCFS_ZSWAP_ON = 3,
156+
LXCFS_PSI_POLL_ON = 4,
157+
LXCFS_OPTS_MAX = LXCFS_PSI_POLL_ON,
139158
} lxcfs_opt_t;
140159

141160

@@ -172,6 +191,8 @@ static inline bool lxcfs_has_opt(struct lxcfs_opts *opts, lxcfs_opt_t opt)
172191
if (opts->version >= 3 && !opts->zswap_off)
173192
return liblxcfs_can_use_zswap();
174193
return false;
194+
case LXCFS_PSI_POLL_ON:
195+
return (opts->version >= 4 && opts->psi_poll_on);
175196
}
176197

177198
return false;

src/lxcfs.c

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,8 @@ static void sigusr1_reload(int signo, siginfo_t *info, void *extra)
242242
need_reload = 1;
243243
}
244244

245+
static void sig_noop_handler(int signo, siginfo_t *info, void *extra) {}
246+
245247
/* Functions to run the library methods */
246248

247249
#define DEF_LIB_FS_OP(type, fsop) \
@@ -276,8 +278,14 @@ DEF_LIB_FS_OP(sys , read)
276278
off_t offset, struct fuse_file_info *fi
277279
#define LIB_FS_write_OP_ARGS path, buf, size, offset, fi
278280
DEF_LIB_FS_OP(cg , write)
281+
DEF_LIB_FS_OP(proc , write)
279282
DEF_LIB_FS_OP(sys , write)
280283

284+
#define LIB_FS_poll_OP_ARGS_TYPE const char *path, struct fuse_file_info *fi, \
285+
struct fuse_pollhandle *ph, unsigned *reventsp
286+
#define LIB_FS_poll_OP_ARGS path, fi, ph, reventsp
287+
DEF_LIB_FS_OP(proc , poll)
288+
281289
#define LIB_FS_mkdir_OP_ARGS_TYPE const char *path, mode_t mode
282290
#define LIB_FS_mkdir_OP_ARGS path, mode
283291
DEF_LIB_FS_OP(cg, mkdir)
@@ -605,6 +613,13 @@ int lxcfs_write(const char *path, const char *buf, size_t size, off_t offset,
605613
return ret;
606614
}
607615

616+
if (LXCFS_TYPE_PROC(type)) {
617+
up_users();
618+
ret = do_proc_write(path, buf, size, offset, fi);
619+
down_users();
620+
return ret;
621+
}
622+
608623
if (LXCFS_TYPE_SYS(type)) {
609624
up_users();
610625
ret = do_sys_write(path, buf, size, offset, fi);
@@ -615,6 +630,27 @@ int lxcfs_write(const char *path, const char *buf, size_t size, off_t offset,
615630
return -EINVAL;
616631
}
617632

633+
int lxcfs_poll(const char *path, struct fuse_file_info *fi,
634+
struct fuse_pollhandle *ph, unsigned *reventsp)
635+
{
636+
int ret;
637+
enum lxcfs_virt_t type;
638+
639+
type = file_info_type(fi);
640+
641+
if (LXCFS_TYPE_PROC(type)) {
642+
up_users();
643+
ret = do_proc_poll(path, fi, ph, reventsp);
644+
down_users();
645+
return ret;
646+
}
647+
648+
/* default f_op->poll() behavior when not supported */
649+
fuse_pollhandle_destroy(ph);
650+
*reventsp = DEFAULT_POLLMASK;
651+
return 0;
652+
}
653+
618654
int lxcfs_readlink(const char *path, char *buf, size_t size)
619655
{
620656
int ret;
@@ -842,6 +878,9 @@ const struct fuse_operations lxcfs_ops = {
842878
.truncate = lxcfs_truncate,
843879
.write = lxcfs_write,
844880
.readlink = lxcfs_readlink,
881+
#if HAVE_FUSE3
882+
.poll = lxcfs_poll,
883+
#endif
845884

846885
.create = NULL,
847886
.destroy = NULL,
@@ -937,6 +976,7 @@ static const struct option long_options[] = {
937976
{"enable-cfs", no_argument, 0, 0 },
938977
{"enable-pidfd", no_argument, 0, 0 },
939978
{"enable-cgroup", no_argument, 0, 0 },
979+
{"enable-psi-poll", no_argument, 0, 0 },
940980

941981
{"pidfile", required_argument, 0, 'p' },
942982
{"runtime-dir", required_argument, 0, 0 },
@@ -1011,7 +1051,8 @@ int main(int argc, char *argv[])
10111051
opts->zswap_off = false;
10121052
opts->use_pidfd = false;
10131053
opts->use_cfs = false;
1014-
opts->version = 3;
1054+
opts->psi_poll_on = false;
1055+
opts->version = 4;
10151056

10161057
while ((c = getopt_long(argc, argv, "dulfhvso:p:", long_options, &idx)) != -1) {
10171058
switch (c) {
@@ -1022,6 +1063,8 @@ int main(int argc, char *argv[])
10221063
opts->use_cfs = true;
10231064
else if (strcmp(long_options[idx].name, "enable-cgroup") == 0)
10241065
cgroup_is_enabled = true;
1066+
else if (strcmp(long_options[idx].name, "enable-psi-poll") == 0)
1067+
opts->psi_poll_on = true;
10251068
else if (strcmp(long_options[idx].name, "runtime-dir") == 0)
10261069
runtime_path_arg = optarg;
10271070
else
@@ -1189,6 +1232,11 @@ int main(int argc, char *argv[])
11891232
}
11901233
#endif
11911234

1235+
if (install_signal_handler(SIG_NOTIFY_POLL_WAKEUP, sig_noop_handler)) {
1236+
lxcfs_error("%s - Failed to install SIG_NOTIFY_POLL_WAKEUP signal handler", strerror(errno));
1237+
goto out;
1238+
}
1239+
11921240
if (!pidfile) {
11931241
snprintf(pidfile_buf, sizeof(pidfile_buf), "%s%s", runtime_path, PID_FILE);
11941242
pidfile = pidfile_buf;

src/macro.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#define CGROUP2_SUPER_MAGIC 0x63677270
2121
#endif
2222

23+
#define DEFAULT_POLLMASK (EPOLLIN | EPOLLOUT | EPOLLRDNORM | EPOLLWRNORM)
24+
2325
#define lxcfs_debug_stream(stream, format, ...) \
2426
do { \
2527
fprintf(stream, "%s: %d: %s: " format "\n", __FILE__, \

0 commit comments

Comments
 (0)