Skip to content

Commit a6c309b

Browse files
alexhudspithmihalicyn
authored andcommitted
proc: Fix swap handling for cgroups v2 (zero limits)
Since memory.swap.max = 0 is valid under v2, limits of 0 must not be treated differently. Instead, use UINT64_MAX as the default limit. This aligns with cgroups v1 behaviour anyway since 'limit_in_bytes' files contain a large number for unspecified limits (2^63). Resolves: #534 Signed-off-by: Alex Hudspith <[email protected]>
1 parent f496e62 commit a6c309b

File tree

1 file changed

+72
-42
lines changed

1 file changed

+72
-42
lines changed

src/proc_fuse.c

+72-42
Original file line numberDiff line numberDiff line change
@@ -239,21 +239,37 @@ __lxcfs_fuse_ops int proc_release(const char *path, struct fuse_file_info *fi)
239239
return 0;
240240
}
241241

242-
static uint64_t get_memlimit(const char *cgroup, bool swap)
242+
/**
243+
* Gets a non-hierarchical memory controller limit, or UINT64_MAX if no limit is
244+
* in place. If `swap` is true, reads 'swap' (v2) or 'memsw' (v1); otherwise
245+
* reads the memory (RAM) limits.
246+
*
247+
* @returns 0 on success (and sets `*limit`), < 0 on error
248+
*/
249+
static int get_memlimit(const char *cgroup, bool swap, uint64_t *limit)
243250
{
244251
__do_free char *memlimit_str = NULL;
245-
uint64_t memlimit = 0;
252+
uint64_t memlimit = UINT64_MAX;
246253
int ret;
247254

248255
if (swap)
249256
ret = cgroup_ops->get_memory_swap_max(cgroup_ops, cgroup, &memlimit_str);
250257
else
251258
ret = cgroup_ops->get_memory_max(cgroup_ops, cgroup, &memlimit_str);
252-
if (ret > 0 && memlimit_str[0] && safe_uint64(memlimit_str, &memlimit, 10) < 0)
253-
lxcfs_error("Failed to convert memory%s.max=%s for cgroup %s",
254-
swap ? ".swap" : "", memlimit_str, cgroup);
255259

256-
return memlimit;
260+
if (ret < 0)
261+
return ret;
262+
263+
if (memlimit_str[0]) {
264+
ret = safe_uint64(memlimit_str, &memlimit, 10);
265+
if (ret < 0) {
266+
lxcfs_error("Failed to convert memory%s.max=%s for cgroup %s",
267+
swap ? ".swap" : "", memlimit_str, cgroup);
268+
return ret;
269+
}
270+
}
271+
*limit = memlimit;
272+
return 0;
257273
}
258274

259275
/*
@@ -318,31 +334,44 @@ static char *gnu_dirname(char *path)
318334
return path;
319335
}
320336

321-
static uint64_t get_min_memlimit(const char *cgroup, bool swap)
337+
/**
338+
* Gets a hierarchical memory controller limit, or UINT64_MAX if no limit is
339+
* in place. If `swap` is true, reads 'swap' (v2) or 'memsw' (v1); otherwise
340+
* reads the memory (RAM) limits.
341+
*
342+
* @returns 0 on success (and sets `*limit`), < 0 on error
343+
*/
344+
static int get_min_memlimit(const char *cgroup, bool swap, uint64_t *limit)
322345
{
323346
__do_free char *copy = NULL;
324-
uint64_t memlimit = 0, retlimit = 0;
347+
uint64_t memlimit = UINT64_MAX, retlimit = UINT64_MAX;
348+
int ret;
325349

326350
copy = strdup(cgroup);
327351
if (!copy)
328352
return log_error_errno(0, ENOMEM, "Failed to allocate memory");
329353

330-
retlimit = get_memlimit(copy, swap);
354+
ret = get_memlimit(copy, swap, &retlimit);
355+
if (ret < 0)
356+
return ret;
331357

332358
/*
333359
* If the cgroup doesn't start with / (probably won't happen), dirname()
334360
* will terminate with "" instead of "/"
335361
*/
336-
while (*copy && strcmp(copy, "/") != 0) {
362+
while (retlimit != 0 && *copy && strcmp(copy, "/") != 0) {
337363
char *it = copy;
338364

339365
it = gnu_dirname(it);
340-
memlimit = get_memlimit(it, swap);
341-
if (memlimit > 0 && memlimit < retlimit)
366+
ret = get_memlimit(it, swap, &memlimit);
367+
if (ret < 0)
368+
return ret;
369+
if (memlimit < retlimit)
342370
retlimit = memlimit;
343-
};
371+
}
344372

345-
return retlimit;
373+
*limit = retlimit;
374+
return 0;
346375
}
347376

348377
static inline bool startswith(const char *line, const char *pref)
@@ -361,30 +390,30 @@ static void get_swap_info(const char *cgroup, uint64_t memlimit,
361390
*swtotal = *swusage = 0;
362391
*memswpriority = 1;
363392

364-
memswlimit = get_min_memlimit(cgroup, true);
365-
if (memswlimit > 0) {
366-
ret = cgroup_ops->get_memory_swap_current(cgroup_ops, cgroup, &memswusage_str);
367-
if (ret < 0 || safe_uint64(memswusage_str, &memswusage, 10) != 0)
368-
return;
369-
370-
if (liblxcfs_memory_is_cgroupv2()) {
371-
*swtotal = memswlimit / 1024;
372-
*swusage = memswusage / 1024;
373-
} else {
374-
if (memlimit > memswlimit)
375-
*swtotal = 0;
376-
else
377-
*swtotal = (memswlimit - memlimit) / 1024;
378-
if (memusage > memswusage || *swtotal == 0)
379-
*swusage = 0;
380-
else
381-
*swusage = (memswusage - memusage) / 1024;
382-
}
383-
384-
ret = cgroup_ops->get_memory_swappiness(cgroup_ops, cgroup, &memswpriority_str);
385-
if (ret >= 0)
386-
safe_uint64(memswpriority_str, memswpriority, 10);
393+
ret = get_min_memlimit(cgroup, true, &memswlimit);
394+
if (ret < 0)
395+
return;
396+
ret = cgroup_ops->get_memory_swap_current(cgroup_ops, cgroup, &memswusage_str);
397+
if (ret < 0 || safe_uint64(memswusage_str, &memswusage, 10) < 0)
398+
return;
399+
400+
if (liblxcfs_memory_is_cgroupv2()) {
401+
*swtotal = memswlimit / 1024;
402+
*swusage = memswusage / 1024;
403+
} else {
404+
if (memlimit > memswlimit)
405+
*swtotal = 0;
406+
else
407+
*swtotal = (memswlimit - memlimit) / 1024;
408+
if (memusage > memswusage || *swtotal == 0)
409+
*swusage = 0;
410+
else
411+
*swusage = (memswusage - memusage) / 1024;
387412
}
413+
414+
ret = cgroup_ops->get_memory_swappiness(cgroup_ops, cgroup, &memswpriority_str);
415+
if (ret >= 0)
416+
safe_uint64(memswpriority_str, memswpriority, 10);
388417
}
389418

390419
static int proc_swaps_read(char *buf, size_t size, off_t offset,
@@ -432,12 +461,12 @@ static int proc_swaps_read(char *buf, size_t size, off_t offset,
432461
return read_file_fuse("/proc/swaps", buf, size, d);
433462
prune_init_slice(cgroup);
434463

435-
memlimit = get_min_memlimit(cgroup, false);
436-
464+
ret = get_min_memlimit(cgroup, false, &memlimit);
465+
if (ret < 0)
466+
return 0;
437467
ret = cgroup_ops->get_memory_current(cgroup_ops, cgroup, &memusage_str);
438468
if (ret < 0)
439469
return 0;
440-
441470
if (safe_uint64(memusage_str, &memusage, 10) < 0)
442471
lxcfs_error("Failed to convert memusage %s", memusage_str);
443472

@@ -1320,8 +1349,9 @@ static int proc_meminfo_read(char *buf, size_t size, off_t offset,
13201349
if (!cgroup_parse_memory_stat(cgroup, &mstat))
13211350
return read_file_fuse("/proc/meminfo", buf, size, d);
13221351

1323-
memlimit = get_min_memlimit(cgroup, false);
1324-
1352+
ret = get_min_memlimit(cgroup, false, &memlimit);
1353+
if (ret < 0)
1354+
return read_file_fuse("/proc/meminfo", buf, size, d);
13251355
/*
13261356
* Following values are allowed to fail, because swapaccount might be
13271357
* turned off for current kernel.

0 commit comments

Comments
 (0)