Skip to content

Commit 6957cc1

Browse files
authored
Merge pull request #686 from kadinsayani/feat/zswap
Add zswap accounting
2 parents e09fff7 + c503b12 commit 6957cc1

File tree

6 files changed

+73
-13
lines changed

6 files changed

+73
-13
lines changed

src/bindings.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747

4848
static bool can_use_pidfd;
4949
static bool can_use_swap;
50+
static bool can_use_zswap;
5051
static bool can_use_sys_cpu;
5152
static bool has_versioned_opts;
5253
static bool memory_is_cgroupv2;
@@ -77,6 +78,11 @@ bool liblxcfs_can_use_swap(void)
7778
return can_use_swap;
7879
}
7980

81+
bool liblxcfs_can_use_zswap(void)
82+
{
83+
return can_use_zswap;
84+
}
85+
8086
bool liblxcfs_can_use_sys_cpu(void)
8187
{
8288
return can_use_sys_cpu;
@@ -980,6 +986,12 @@ void lxcfslib_init(void)
980986
hierarchy = cgroup_ops->get_hierarchy(cgroup_ops, "memory");
981987
memory_is_cgroupv2 = hierarchy && is_unified_hierarchy(hierarchy);
982988

989+
can_use_zswap = cgroup && cgroup_ops->can_use_zswap(cgroup_ops, cgroup);
990+
if (can_use_zswap)
991+
lxcfs_info("Kernel supports zswap accounting");
992+
else
993+
lxcfs_info("Kernel does not support zswap accounting");
994+
983995
lxcfs_info("api_extensions:");
984996
for (size_t nr = 0; nr < nr_api_extensions; nr++)
985997
lxcfs_info("- %s", api_extensions[nr]);

src/bindings.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,15 @@ struct lxcfs_opts {
127127
__u32 version;
128128
// As of opts version 2.
129129
char runtime_path[PATH_MAX];
130+
bool zswap_off;
130131
};
131132

132133
typedef enum lxcfs_opt_t {
133134
LXCFS_SWAP_ON = 0,
134135
LXCFS_PIDFD_ON = 1,
135136
LXCFS_CFS_ON = 2,
136-
LXCFS_OPTS_MAX = LXCFS_CFS_ON,
137+
LXCFS_ZSWAP_ON = 3,
138+
LXCFS_OPTS_MAX = LXCFS_ZSWAP_ON,
137139
} lxcfs_opt_t;
138140

139141

@@ -142,6 +144,7 @@ extern void prune_init_slice(char *cg);
142144
extern bool supports_pidfd(void);
143145
extern bool liblxcfs_functional(void);
144146
extern bool liblxcfs_can_use_swap(void);
147+
extern bool liblxcfs_can_use_zswap(void);
145148
extern bool liblxcfs_memory_is_cgroupv2(void);
146149
extern bool liblxcfs_can_use_sys_cpu(void);
147150
extern bool liblxcfs_has_versioned_opts(void);
@@ -164,6 +167,11 @@ static inline bool lxcfs_has_opt(struct lxcfs_opts *opts, lxcfs_opt_t opt)
164167
return opts->use_pidfd;
165168
case LXCFS_CFS_ON:
166169
return opts->use_cfs;
170+
case LXCFS_ZSWAP_ON:
171+
/* Check opts version before accessing zswap_off (added in version 3) */
172+
if (opts->version >= 3 && !opts->zswap_off)
173+
return liblxcfs_can_use_zswap();
174+
return false;
167175
}
168176

169177
return false;

src/cgroups/cgfsng.c

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -631,22 +631,16 @@ static int cgfsng_get_memory_slabinfo_fd(struct cgroup_ops *ops, const char *cgr
631631
return openat(h->fd, path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
632632
}
633633

634-
static bool cgfsng_can_use_swap(struct cgroup_ops *ops, const char *cgroup)
634+
static bool cgfsng_can_use_memory_feature(struct cgroup_ops *ops,
635+
struct hierarchy *h, const char *cgroup, const char *file)
635636
{
636637
__do_free char *cgroup_rel = NULL, *junk_value = NULL;
637-
const char *file;
638-
struct hierarchy *h;
639638
bool ret;
640639

641-
h = ops->get_hierarchy(ops, "memory");
642-
if (!h)
643-
return false;
644-
645640
cgroup_rel = must_make_path_relative(cgroup, NULL);
646-
file = is_unified_hierarchy(h) ? "memory.swap.current" : "memory.memsw.usage_in_bytes";
647641

648642
/* For v2, we need to look at the lower levels of the hierarchy because
649-
* no 'memory.swap.current' file exists at the root. We must search
643+
* no 'memory.<feature>.current' file exists at the root. We must search
650644
* upwards in the hierarchy in case memory accounting is disabled via
651645
* cgroup.subtree_control for the given cgroup itself.
652646
*/
@@ -663,7 +657,7 @@ static bool cgfsng_can_use_swap(struct cgroup_ops *ops, const char *cgroup)
663657
__do_closedir DIR *dir = NULL;
664658
struct dirent *dent;
665659

666-
fd = dup(h->fd);
660+
fd = openat_safe(h->fd, ".");
667661
if (fd < 0)
668662
return false;
669663

@@ -684,7 +678,7 @@ static bool cgfsng_can_use_swap(struct cgroup_ops *ops, const char *cgroup)
684678
if (dent->d_type == DT_DIR) {
685679
__do_free char *path;
686680

687-
path = must_make_path_relative(dent->d_name, "memory.swap.current", NULL);
681+
path = must_make_path_relative(dent->d_name, file, NULL);
688682

689683
if (!faccessat(h->fd, path, F_OK, 0)) {
690684
/* We found it. Exit. */
@@ -704,6 +698,32 @@ static bool cgfsng_can_use_swap(struct cgroup_ops *ops, const char *cgroup)
704698
return ret;
705699
}
706700

701+
static bool cgfsng_can_use_swap(struct cgroup_ops *ops, const char *cgroup)
702+
{
703+
struct hierarchy *h;
704+
705+
h = ops->get_hierarchy(ops, "memory");
706+
if (!h)
707+
return false;
708+
709+
return cgfsng_can_use_memory_feature(ops, h, cgroup, is_unified_hierarchy(h) ? "memory.swap.current" : "memory.memsw.usage_in_bytes");
710+
}
711+
712+
static bool cgfsng_can_use_zswap(struct cgroup_ops *ops, const char *cgroup)
713+
{
714+
struct hierarchy *h;
715+
716+
h = ops->get_hierarchy(ops, "memory");
717+
if (!h)
718+
return false;
719+
720+
/* zswap is only available in cgroupv2 */
721+
if (!is_unified_hierarchy(h))
722+
return false;
723+
724+
return cgfsng_can_use_memory_feature(ops, h, cgroup, "memory.zswap.current");
725+
}
726+
707727
static int cgfsng_get_memory_stats(struct cgroup_ops *ops, const char *cgroup,
708728
char **value)
709729
{
@@ -1110,6 +1130,7 @@ struct cgroup_ops *cgfsng_ops_init(void)
11101130
cgfsng_ops->get_memory_swap_current = cgfsng_get_memory_swap_current;
11111131
cgfsng_ops->get_memory_slabinfo_fd = cgfsng_get_memory_slabinfo_fd;
11121132
cgfsng_ops->can_use_swap = cgfsng_can_use_swap;
1133+
cgfsng_ops->can_use_zswap = cgfsng_can_use_zswap;
11131134

11141135
/* cpuset */
11151136
cgfsng_ops->get_cpuset_cpus = cgfsng_get_cpuset_cpus;

src/cgroups/cgroup.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ struct cgroup_ops {
149149
int (*get_memory_slabinfo_fd)(struct cgroup_ops *ops,
150150
const char *cgroup);
151151
bool (*can_use_swap)(struct cgroup_ops *ops, const char *cgroup);
152+
bool (*can_use_zswap)(struct cgroup_ops *ops, const char *cgroup);
152153

153154
/* cpuset */
154155
int (*get_cpuset_cpus)(struct cgroup_ops *ops, const char *cgroup,

src/lxcfs.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,7 @@ static int set_pidfile(char *pidfile)
928928
static const struct option long_options[] = {
929929
{"debug", no_argument, 0, 'd' },
930930
{"disable-swap", no_argument, 0, 'u' },
931+
{"disable-zswap", no_argument, 0, 'z' },
931932
{"enable-loadavg", no_argument, 0, 'l' },
932933
{"foreground", no_argument, 0, 'f' },
933934
{"help", no_argument, 0, 'h' },
@@ -1007,9 +1008,10 @@ int main(int argc, char *argv[])
10071008
}
10081009

10091010
opts->swap_off = false;
1011+
opts->zswap_off = false;
10101012
opts->use_pidfd = false;
10111013
opts->use_cfs = false;
1012-
opts->version = 2;
1014+
opts->version = 3;
10131015

10141016
while ((c = getopt_long(argc, argv, "dulfhvso:p:", long_options, &idx)) != -1) {
10151017
switch (c) {
@@ -1051,6 +1053,9 @@ int main(int argc, char *argv[])
10511053
case 'u':
10521054
opts->swap_off = true;
10531055
break;
1056+
case 'z':
1057+
opts->zswap_off = true;
1058+
break;
10541059
case 'v':
10551060
lxcfs_info("%s", STRINGIFY(PROJECT_VERSION));
10561061
exit(EXIT_SUCCESS);

src/proc_fuse.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ struct memory_stat {
6666
uint64_t slab;
6767
uint64_t slab_reclaimable;
6868
uint64_t slab_unreclaimable;
69+
uint64_t zswapped;
70+
uint64_t zswap;
6971
};
7072

7173
static off_t get_procfile_size(const char *path)
@@ -1389,6 +1391,10 @@ static bool cgroup_parse_memory_stat(const char *cgroup, struct memory_stat *mst
13891391
sscanf(line, "slab_reclaimable %" PRIu64, &(mstat->slab_reclaimable));
13901392
} else if (unified && startswith(line, "slab_unreclaimable")) {
13911393
sscanf(line, "slab_unreclaimable %" PRIu64, &(mstat->slab_unreclaimable));
1394+
} else if (unified && startswith(line, "zswapped")) {
1395+
sscanf(line, "zswapped %" PRIu64, &(mstat->zswapped));
1396+
} else if (unified && startswith(line, "zswap")) {
1397+
sscanf(line, "zswap %" PRIu64, &(mstat->zswap));
13921398
}
13931399
}
13941400

@@ -1404,6 +1410,7 @@ static int proc_meminfo_read(char *buf, size_t size, off_t offset,
14041410
__do_fclose FILE *f = NULL;
14051411
struct fuse_context *fc = fuse_get_context();
14061412
bool wants_swap = lxcfs_has_opt(fuse_get_context()->private_data, LXCFS_SWAP_ON);
1413+
bool wants_zswap = lxcfs_has_opt(fuse_get_context()->private_data, LXCFS_ZSWAP_ON);
14071414
struct file_info *d = INTTYPE_TO_PTR(fi->fh);
14081415
uint64_t memlimit = 0, memusage = 0,
14091416
hosttotal = 0, swfree = 0, swusage = 0, swtotal = 0,
@@ -1520,6 +1527,12 @@ static int proc_meminfo_read(char *buf, size_t size, off_t offset,
15201527

15211528
snprintf(lbuf, 100, "SwapFree: %8" PRIu64 " kB\n", swfree);
15221529
printme = lbuf;
1530+
} else if (startswith(line, "Zswap:")) {
1531+
snprintf(lbuf, 100, "Zswap: %8" PRIu64 " kB\n", wants_zswap ? mstat.zswap / 1024 : 0);
1532+
printme = lbuf;
1533+
} else if (startswith(line, "Zswapped:")) {
1534+
snprintf(lbuf, 100, "Zswapped: %8" PRIu64 " kB\n", wants_zswap ? mstat.zswapped / 1024 : 0);
1535+
printme = lbuf;
15231536
} else if (startswith(line, "Slab:")) {
15241537
snprintf(lbuf, 100, "Slab: %8" PRIu64 " kB\n", mstat.slab / 1024);
15251538
printme = lbuf;

0 commit comments

Comments
 (0)