Messages in this thread | | | Subject | Re: [Patch v4 1/2] cgroup: svm: Add Encryption ID controller | From | Brijesh Singh <> | Date | Wed, 13 Jan 2021 09:19:56 -0600 |
| |
On 1/7/2021 7:28 PM, Vipin Sharma wrote: > Hardware memory encryption is available on multiple generic CPUs. For > example AMD has Secure Encrypted Virtualization (SEV) and SEV - > Encrypted State (SEV-ES). > > These memory encryptions are useful in creating encrypted virtual > machines (VMs) and user space programs. > > There are limited number of encryption IDs that can be used > simultaneously on a machine for encryption. This generates a need for > the system admin to track, limit, allocate resources, and optimally > schedule VMs and user workloads in the cloud infrastructure. Some > malicious programs can exhaust all of these resources on a host causing > starvation of other workloads. > > Encryption ID controller allows control of these resources using > Cgroups. > > Controller is enabled by CGROUP_ENCRYPTION_IDS config option. > Encryption controller provide 3 interface files for each encryption ID > type. For example, in SEV: > > 1. encrpytion_ids.sev.max > Sets the maximum usage of SEV IDs in the cgroup. > 2. encryption_ids.sev.current > Current usage of SEV IDs in the cgroup and its children. > 3. encryption_ids.sev.stat > Shown only at the root cgroup. Displays total SEV IDs available > on the platform and current usage count. > > Other ID types can be easily added in the controller in the same way. > > Signed-off-by: Vipin Sharma <vipinsh@google.com> > Reviewed-by: David Rientjes <rientjes@google.com> > Reviewed-by: Dionna Glaze <dionnaglaze@google.com>
Acked-by: Brijesh Singh <brijesh.singh@amd.com>
> --- > arch/x86/kvm/svm/sev.c | 52 +++- > include/linux/cgroup_subsys.h | 4 + > include/linux/encryption_ids_cgroup.h | 72 +++++ > include/linux/kvm_host.h | 4 + > init/Kconfig | 14 + > kernel/cgroup/Makefile | 1 + > kernel/cgroup/encryption_ids.c | 422 ++++++++++++++++++++++++++ > 7 files changed, 557 insertions(+), 12 deletions(-) > create mode 100644 include/linux/encryption_ids_cgroup.h > create mode 100644 kernel/cgroup/encryption_ids.c > > diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c > index 9858d5ae9ddd..1924ab2eaf11 100644 > --- a/arch/x86/kvm/svm/sev.c > +++ b/arch/x86/kvm/svm/sev.c > @@ -14,6 +14,7 @@ > #include <linux/psp-sev.h> > #include <linux/pagemap.h> > #include <linux/swap.h> > +#include <linux/encryption_ids_cgroup.h> > #include <linux/processor.h> > #include <linux/trace_events.h> > #include <asm/fpu/internal.h> > @@ -86,10 +87,18 @@ static bool __sev_recycle_asids(int min_asid, int max_asid) > return true; > } > > -static int sev_asid_new(struct kvm_sev_info *sev) > +static int sev_asid_new(struct kvm *kvm) > { > - int pos, min_asid, max_asid; > + int pos, min_asid, max_asid, ret; > + struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info; > bool retry = true; > + enum encryption_id_type type; > + > + type = sev->es_active ? ENCRYPTION_ID_SEV_ES : ENCRYPTION_ID_SEV; > + > + ret = enc_id_cg_try_charge(kvm, type, 1); > + if (ret) > + return ret; > > mutex_lock(&sev_bitmap_lock); > > @@ -107,7 +116,8 @@ static int sev_asid_new(struct kvm_sev_info *sev) > goto again; > } > mutex_unlock(&sev_bitmap_lock); > - return -EBUSY; > + ret = -EBUSY; > + goto e_uncharge; > } > > __set_bit(pos, sev_asid_bitmap); > @@ -115,6 +125,9 @@ static int sev_asid_new(struct kvm_sev_info *sev) > mutex_unlock(&sev_bitmap_lock); > > return pos + 1; > +e_uncharge: > + enc_id_cg_uncharge(kvm, type, 1); > + return ret; > } > > static int sev_get_asid(struct kvm *kvm) > @@ -124,14 +137,16 @@ static int sev_get_asid(struct kvm *kvm) > return sev->asid; > } > > -static void sev_asid_free(int asid) > +static void sev_asid_free(struct kvm *kvm) > { > struct svm_cpu_data *sd; > int cpu, pos; > + struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info; > + enum encryption_id_type type; > > mutex_lock(&sev_bitmap_lock); > > - pos = asid - 1; > + pos = sev->asid - 1; > __set_bit(pos, sev_reclaim_asid_bitmap); > > for_each_possible_cpu(cpu) { > @@ -140,6 +155,9 @@ static void sev_asid_free(int asid) > } > > mutex_unlock(&sev_bitmap_lock); > + > + type = sev->es_active ? ENCRYPTION_ID_SEV_ES : ENCRYPTION_ID_SEV; > + enc_id_cg_uncharge(kvm, type, 1); > } > > static void sev_unbind_asid(struct kvm *kvm, unsigned int handle) > @@ -184,22 +202,22 @@ static int sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp) > if (unlikely(sev->active)) > return ret; > > - asid = sev_asid_new(sev); > + asid = sev_asid_new(kvm); > if (asid < 0) > return ret; > + sev->asid = asid; > > ret = sev_platform_init(&argp->error); > if (ret) > goto e_free; > > sev->active = true; > - sev->asid = asid; > INIT_LIST_HEAD(&sev->regions_list); > > return 0; > > e_free: > - sev_asid_free(asid); > + sev_asid_free(kvm); > return ret; > } > > @@ -1240,12 +1258,12 @@ void sev_vm_destroy(struct kvm *kvm) > mutex_unlock(&kvm->lock); > > sev_unbind_asid(kvm, sev->handle); > - sev_asid_free(sev->asid); > + sev_asid_free(kvm); > } > > void __init sev_hardware_setup(void) > { > - unsigned int eax, ebx, ecx, edx; > + unsigned int eax, ebx, ecx, edx, sev_asid_count, sev_es_asid_count; > bool sev_es_supported = false; > bool sev_supported = false; > > @@ -1277,7 +1295,11 @@ void __init sev_hardware_setup(void) > if (!sev_reclaim_asid_bitmap) > goto out; > > - pr_info("SEV supported: %u ASIDs\n", max_sev_asid - min_sev_asid + 1); > + sev_asid_count = max_sev_asid - min_sev_asid + 1; > + if (enc_id_cg_set_capacity(ENCRYPTION_ID_SEV, sev_asid_count)) > + goto out; > + > + pr_info("SEV supported: %u ASIDs\n", sev_asid_count); > sev_supported = true; > > /* SEV-ES support requested? */ > @@ -1292,7 +1314,11 @@ void __init sev_hardware_setup(void) > if (min_sev_asid == 1) > goto out; > > - pr_info("SEV-ES supported: %u ASIDs\n", min_sev_asid - 1); > + sev_es_asid_count = min_sev_asid - 1; > + if (enc_id_cg_set_capacity(ENCRYPTION_ID_SEV_ES, sev_es_asid_count)) > + goto out; > + > + pr_info("SEV-ES supported: %u ASIDs\n", sev_es_asid_count); > sev_es_supported = true; > > out: > @@ -1307,6 +1333,8 @@ void sev_hardware_teardown(void) > > bitmap_free(sev_asid_bitmap); > bitmap_free(sev_reclaim_asid_bitmap); > + enc_id_cg_set_capacity(ENCRYPTION_ID_SEV, 0); > + enc_id_cg_set_capacity(ENCRYPTION_ID_SEV_ES, 0); > > sev_flush_asids(); > } > diff --git a/include/linux/cgroup_subsys.h b/include/linux/cgroup_subsys.h > index acb77dcff3b4..83754f58c05e 100644 > --- a/include/linux/cgroup_subsys.h > +++ b/include/linux/cgroup_subsys.h > @@ -61,6 +61,10 @@ SUBSYS(pids) > SUBSYS(rdma) > #endif > > +#if IS_ENABLED(CONFIG_CGROUP_ENCRYPTION_IDS) > +SUBSYS(encryption_ids) > +#endif > + > /* > * The following subsystems are not supported on the default hierarchy. > */ > diff --git a/include/linux/encryption_ids_cgroup.h b/include/linux/encryption_ids_cgroup.h > new file mode 100644 > index 000000000000..af428a4beb28 > --- /dev/null > +++ b/include/linux/encryption_ids_cgroup.h > @@ -0,0 +1,72 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Encryption IDs cgroup controller. > + * > + * Copyright 2020 Google LLC > + * Author: Vipin Sharma <vipinsh@google.com> > + */ > +#ifndef _ENCRYPTION_IDS_CGROUP_H_ > +#define _ENCRYPTION_IDS_CGROUP_H_ > + > +#include <linux/cgroup-defs.h> > +#include <linux/kvm_types.h> > + > +/** > + * Types of encryption IDs supported by the host. > + */ > +enum encryption_id_type { > +#ifdef CONFIG_KVM_AMD_SEV > + ENCRYPTION_ID_SEV, > + ENCRYPTION_ID_SEV_ES, > +#endif > + ENCRYPTION_ID_TYPES > +}; > + > +#ifdef CONFIG_CGROUP_ENCRYPTION_IDS > + > +/** > + * struct encryption_id_res: Per cgroup per encryption ID resource > + * @max: Maximum count of encryption ID that can be used. > + * @usage: Current usage of encryption ID in the cgroup. > + */ > +struct encryption_id_res { > + unsigned int max; > + unsigned int usage; > +}; > + > +/** > + * struct encryption_id_cgroup - Encryption IDs controller's cgroup structure. > + * @css: cgroup subsys state object. > + * @ids: Array of encryption IDs resource usage in the cgroup. > + */ > +struct encryption_id_cgroup { > + struct cgroup_subsys_state css; > + struct encryption_id_res res[ENCRYPTION_ID_TYPES]; > +}; > + > +int enc_id_cg_set_capacity(enum encryption_id_type type, unsigned int capacity); > +int enc_id_cg_try_charge(struct kvm *kvm, enum encryption_id_type type, > + unsigned int amount); > +void enc_id_cg_uncharge(struct kvm *kvm, enum encryption_id_type type, > + unsigned int amount); > +#else > +static inline int enc_id_cg_set_capacity(enum encryption_id_type type, > + unsigned int capacity) > +{ > + return 0; > +} > + > +static inline int enc_id_cg_try_charge(struct kvm *kvm, > + enum encryption_id_type type, > + unsigned int amount) > +{ > + return 0; > +} > + > +static inline void enc_id_cg_uncharge(struct kvm *kvm, > + enum encryption_id_type type, > + unsigned int amount) > +{ > +} > +#endif /* CONFIG_CGROUP_ENCRYPTION_IDS */ > +#endif /* _ENCRYPTION_CGROUP_H_ */ > diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h > index f3b1013fb22c..ae9fde0d4267 100644 > --- a/include/linux/kvm_host.h > +++ b/include/linux/kvm_host.h > @@ -27,6 +27,7 @@ > #include <linux/refcount.h> > #include <linux/nospec.h> > #include <asm/signal.h> > +#include <linux/encryption_ids_cgroup.h> > > #include <linux/kvm.h> > #include <linux/kvm_para.h> > @@ -513,6 +514,9 @@ struct kvm { > pid_t userspace_pid; > unsigned int max_halt_poll_ns; > u32 dirty_ring_size; > +#ifdef CONFIG_CGROUP_ENCRYPTION_IDS > + struct encryption_id_cgroup *enc_id_cg; > +#endif > }; > > #define kvm_err(fmt, ...) \ > diff --git a/init/Kconfig b/init/Kconfig > index b77c60f8b963..6c0bd0e7c08d 100644 > --- a/init/Kconfig > +++ b/init/Kconfig > @@ -1106,6 +1106,20 @@ config CGROUP_BPF > BPF_CGROUP_INET_INGRESS will be executed on the ingress path of > inet sockets. > > +config CGROUP_ENCRYPTION_IDS > + bool "Encryption IDs controller" > + depends on KVM_AMD_SEV > + default n > + help > + Provides a controller for CPU encryption IDs on a host. > + > + Some platforms have limited number of encryption IDs which can be > + used simultaneously, e.g., AMD's Secure Encrypted Virtualization > + (SEV). This controller tracks and limits the total number of IDs used > + by processes attached to a cgroup hierarchy. For more information, > + please check Encryption IDs section in > + /Documentation/admin-guide/cgroup-v2.rst. > + > config CGROUP_DEBUG > bool "Debug controller" > default n > diff --git a/kernel/cgroup/Makefile b/kernel/cgroup/Makefile > index 5d7a76bfbbb7..6c19208dfb7f 100644 > --- a/kernel/cgroup/Makefile > +++ b/kernel/cgroup/Makefile > @@ -5,4 +5,5 @@ obj-$(CONFIG_CGROUP_FREEZER) += legacy_freezer.o > obj-$(CONFIG_CGROUP_PIDS) += pids.o > obj-$(CONFIG_CGROUP_RDMA) += rdma.o > obj-$(CONFIG_CPUSETS) += cpuset.o > +obj-$(CONFIG_CGROUP_ENCRYPTION_IDS) += encryption_ids.o > obj-$(CONFIG_CGROUP_DEBUG) += debug.o > diff --git a/kernel/cgroup/encryption_ids.c b/kernel/cgroup/encryption_ids.c > new file mode 100644 > index 000000000000..7cd7d3951bb9 > --- /dev/null > +++ b/kernel/cgroup/encryption_ids.c > @@ -0,0 +1,422 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Encryption IDs cgroup controller > + * > + * Copyright 2020 Google LLC > + * Author: Vipin Sharma <vipinsh@google.com> > + */ > + > +#include <linux/limits.h> > +#include <linux/cgroup.h> > +#include <linux/errno.h> > +#include <linux/spinlock.h> > +#include <linux/lockdep.h> > +#include <linux/slab.h> > +#include <linux/kvm_host.h> > +#include <linux/encryption_ids_cgroup.h> > + > +#define MAX_STR "max" > +#define MAX_NUM UINT_MAX > + > +/* Root Encryption ID cgroup */ > +static struct encryption_id_cgroup root_cg; > + > +/* Lock for tracking and updating encryption ID resources. */ > +static DEFINE_SPINLOCK(enc_id_cg_lock); > + > +/* Encryption ID types capacity. */ > +static unsigned int enc_id_capacity[ENCRYPTION_ID_TYPES]; > + > +/** > + * css_enc() - Get encryption ID cgroup from the css. > + * @css: cgroup subsys state object. > + * > + * Context: Any context. > + * Return: > + * * %NULL - If @css is null. > + * * struct encryption_id_cgroup* - Encryption ID cgroup pointer of the passed > + * css. > + */ > +static struct encryption_id_cgroup *css_enc(struct cgroup_subsys_state *css) > +{ > + return css ? container_of(css, struct encryption_id_cgroup, css) : NULL; > +} > + > +/** > + * parent_enc() - Get the parent of the passed encryption ID cgroup. > + * @cgroup: cgroup whose parent needs to be fetched. > + * > + * Context: Any context. > + * Return: > + * * struct encryption_id_cgroup* - Parent of the @cgroup. > + * * %NULL - If @cgroup is null or the passed cgroup does not have a parent. > + */ > +static struct encryption_id_cgroup * > +parent_enc(struct encryption_id_cgroup *cgroup) > +{ > + return cgroup ? css_enc(cgroup->css.parent) : NULL; > +} > + > +/** > + * valid_type() - Check if @type is valid or not. > + * @type: encryption ID type. > + * > + * Context: Any context. > + * Return: > + * * true - If valid type. > + * * false - If not valid type. > + */ > +static inline bool valid_type(enum encryption_id_type type) > +{ > + return type >= 0 && type < ENCRYPTION_ID_TYPES; > +} > + > +/** > + * enc_id_cg_uncharge_hierarchy() - Uncharge the enryption ID cgroup hierarchy. > + * @start_cg: Starting cgroup. > + * @stop_cg: cgroup at which uncharge stops. > + * @type: type of encryption ID to uncharge. > + * @amount: Charge amount. > + * > + * Uncharge the cgroup tree from the given start cgroup to the stop cgroup. > + * > + * Context: Any context. Expects enc_id_cg_lock to be held by the caller. > + */ > +static void enc_id_cg_uncharge_hierarchy(struct encryption_id_cgroup *start_cg, > + struct encryption_id_cgroup *stop_cg, > + enum encryption_id_type type, > + unsigned int amount) > +{ > + struct encryption_id_cgroup *i; > + > + lockdep_assert_held(&enc_id_cg_lock); > + > + for (i = start_cg; i != stop_cg; i = parent_enc(i)) { > + WARN_ON_ONCE(i->res[type].usage < amount); > + i->res[type].usage -= amount; > + } > + css_put(&start_cg->css); > +} > + > +/** > + * enc_id_cg_set_capacity() - Set the capacity of the encryption ID. > + * @type: Type of the encryption ID. > + * @capacity: Supported capacity of the encryption ID on the host. > + * > + * If capacity is 0 then the charging a cgroup fails for the encryption ID. > + * > + * Context: Any context. Takes and releases enc_id_cg_lock. > + * Return: > + * * %0 - Successfully registered the capacity. > + * * %-EINVAL - If @type is invalid. > + * * %-EBUSY - If current usage is more than the capacity. > + */ > +int enc_id_cg_set_capacity(enum encryption_id_type type, unsigned int capacity) > +{ > + int ret = 0; > + unsigned long flags; > + > + if (!valid_type(type)) > + return -EINVAL; > + > + spin_lock_irqsave(&enc_id_cg_lock, flags); > + > + if (WARN_ON_ONCE(root_cg.res[type].usage > capacity)) > + ret = -EBUSY; > + else > + enc_id_capacity[type] = capacity; > + > + spin_unlock_irqrestore(&enc_id_cg_lock, flags); > + > + return ret; > +} > +EXPORT_SYMBOL(enc_id_cg_set_capacity); > + > +/** > + * enc_id_cg_try_charge() - Try charging encryption ID cgroup. > + * @kvm: kvm to store charged cgroup. > + * @type: Encryption ID type to charge. > + * @amount: Amount to charge. > + * > + * Charge @amount to the cgroup to which the current task belongs to. Charged > + * cgroup will be pointed by @cg. Caller must use the same cgroup during > + * uncharge call. > + * > + * Context: Any context. Takes and releases enc_id_cg_lock. > + * Return: > + * * %0 - If successfully charged. > + * * -EINVAL - If @type is invalid or encryption ID has 0 capacity. > + * * -EBUSY - If max limit will be crossed or total usage will be more than the > + * capacity. > + */ > +int enc_id_cg_try_charge(struct kvm *kvm, enum encryption_id_type type, > + unsigned int amount) > +{ > + struct encryption_id_cgroup *task_cg, *i; > + struct encryption_id_res *id_res; > + int ret; > + unsigned int new_usage; > + unsigned long flags; > + > + if (!valid_type(type) || !kvm) > + return -EINVAL; > + > + if (!amount) > + return 0; > + > + spin_lock_irqsave(&enc_id_cg_lock, flags); > + > + if (!enc_id_capacity[type]) { > + ret = -EINVAL; > + goto err_capacity; > + } > + > + task_cg = css_enc(task_get_css(current, encryption_ids_cgrp_id)); > + > + for (i = task_cg; i; i = parent_enc(i)) { > + id_res = &i->res[type]; > + > + new_usage = id_res->usage + amount; > + WARN_ON_ONCE(new_usage < id_res->usage); > + > + if (new_usage > id_res->max || > + new_usage > enc_id_capacity[type]) { > + ret = -EBUSY; > + goto err_charge; > + } > + > + id_res->usage = new_usage; > + } > + > + kvm->enc_id_cg = task_cg; > + spin_unlock_irqrestore(&enc_id_cg_lock, flags); > + return 0; > + > +err_charge: > + enc_id_cg_uncharge_hierarchy(task_cg, i, type, amount); > +err_capacity: > + spin_unlock_irqrestore(&enc_id_cg_lock, flags); > + return ret; > +} > +EXPORT_SYMBOL(enc_id_cg_try_charge); > + > +/** > + * enc_id_cg_uncharge() - Uncharge the encryption ID cgroup. > + * @kvm: kvm containing the corresponding encryption ID cgroup. > + * @type: Encryption ID which was charged. > + * @amount: Charged amount. > + * > + * Context: Any context. Takes and releases enc_id_cg_lock. > + */ > +void enc_id_cg_uncharge(struct kvm *kvm, enum encryption_id_type type, > + unsigned int amount) > +{ > + unsigned long flags; > + > + if (!amount) > + return; > + if (!valid_type(type)) > + return; > + if (!kvm || WARN_ON_ONCE(!(kvm->enc_id_cg))) > + return; > + > + spin_lock_irqsave(&enc_id_cg_lock, flags); > + enc_id_cg_uncharge_hierarchy(kvm->enc_id_cg, NULL, type, amount); > + spin_unlock_irqrestore(&enc_id_cg_lock, flags); > + > + kvm->enc_id_cg = NULL; > +} > +EXPORT_SYMBOL(enc_id_cg_uncharge); > + > +/** > + * enc_id_cg_max_show() - Show encryption ID cgroup max limit. > + * @sf: Interface file > + * @v: Arguments passed > + * > + * Uses cft->private value to determine for which enryption ID type results be > + * shown. > + * > + * Context: Any context. > + * Return: 0 to denote successful print. > + */ > +static int enc_id_cg_max_show(struct seq_file *sf, void *v) > +{ > + struct encryption_id_cgroup *cg = css_enc(seq_css(sf)); > + enum encryption_id_type type = seq_cft(sf)->private; > + > + if (cg->res[type].max == MAX_NUM) > + seq_printf(sf, "%s\n", MAX_STR); > + else > + seq_printf(sf, "%u\n", cg->res[type].max); > + > + return 0; > +} > + > +/** > + * enc_id_cg_max_write() - Update the maximum limit of the cgroup. > + * @of: Handler for the file. > + * @buf: Data from the user. It should be either "max", 0, or a positive > + * integer. > + * @nbytes: Number of bytes of the data. > + * @off: Offset in the file. > + * > + * Uses cft->private value to determine for which enryption ID type results be > + * shown. > + * > + * Context: Any context. Takes and releases enc_id_cg_lock. > + * Return: > + * * >= 0 - Number of bytes processed in the input. > + * * -EINVAL - If buf is not valid. > + * * -ERANGE - If number is bigger than unsigned int capacity. > + * * -EBUSY - If usage can become more than max limit. > + */ > +static ssize_t enc_id_cg_max_write(struct kernfs_open_file *of, char *buf, > + size_t nbytes, loff_t off) > +{ > + struct encryption_id_cgroup *cg; > + unsigned int max; > + int ret = 0; > + enum encryption_id_type type; > + > + buf = strstrip(buf); > + if (!strcmp(MAX_STR, buf)) { > + max = UINT_MAX; > + } else { > + ret = kstrtouint(buf, 0, &max); > + if (ret) > + return ret; > + } > + > + cg = css_enc(of_css(of)); > + type = of_cft(of)->private; > + cg->res[type].max = max; > + > + return nbytes; > +} > + > +/** > + * enc_id_cg_current_read() - Show current usage of the encryption ID. > + * @css: css pointer of the cgroup. > + * @cft: cft pointer of the cgroup. > + * > + * Uses cft->private value to determine for which enryption ID type results be > + * shown. > + * > + * Context: Any context. > + * Return: 0 to denote successful print. > + */ > +static u64 enc_id_cg_current_read(struct cgroup_subsys_state *css, > + struct cftype *cft) > +{ > + struct encryption_id_cgroup *cg = css_enc(css); > + enum encryption_id_type type = cft->private; > + > + return cg->res[type].usage; > +} > + > +/** > + * enc_id_cg_stat_show() - Show the current stat of the cgroup. > + * @sf: Interface file > + * @v: Arguments passed > + * > + * Shows the total capacity of the encryption ID and its current usage. > + * Only shows in root cgroup directory. > + * > + * Uses cft->private value to determine for which enryption ID type results be > + * shown. > + * > + * Context: Any context. Takes and releases enc_id_cg_lock. > + * Return: 0 to denote successful print. > + */ > +static int enc_id_cg_stat_show(struct seq_file *sf, void *v) > +{ > + unsigned long flags; > + enum encryption_id_type type = seq_cft(sf)->private; > + > + spin_lock_irqsave(&enc_id_cg_lock, flags); > + > + seq_printf(sf, "total %u\n", enc_id_capacity[type]); > + seq_printf(sf, "used %u\n", root_cg.res[type].usage); > + > + spin_unlock_irqrestore(&enc_id_cg_lock, flags); > + return 0; > +} > + > +/* Each encryption ID type has these cgroup files. */ > +#define ENC_ID_CGROUP_FILES(id_name, id_type) \ > + [(id_type) * 3] = { \ > + .name = id_name ".max", \ > + .write = enc_id_cg_max_write, \ > + .seq_show = enc_id_cg_max_show, \ > + .flags = CFTYPE_NOT_ON_ROOT, \ > + .private = id_type, \ > + }, \ > + [((id_type) * 3) + 1] = { \ > + .name = id_name ".current", \ > + .read_u64 = enc_id_cg_current_read, \ > + .flags = CFTYPE_NOT_ON_ROOT, \ > + .private = id_type, \ > + }, \ > + [((id_type) * 3) + 2] = { \ > + .name = id_name ".stat", \ > + .seq_show = enc_id_cg_stat_show, \ > + .flags = CFTYPE_ONLY_ON_ROOT, \ > + .private = id_type, \ > + } > + > +/* Encryption ID cgroup interface files */ > +static struct cftype enc_id_cg_files[] = { > +#ifdef CONFIG_KVM_AMD_SEV > + ENC_ID_CGROUP_FILES("sev", ENCRYPTION_ID_SEV), > + ENC_ID_CGROUP_FILES("sev_es", ENCRYPTION_ID_SEV_ES), > +#endif > + {} > +}; > + > +/** > + * enc_id_cg_alloc() - Allocate encryption ID cgroup. > + * @parent_css: Parent cgroup. > + * > + * Context: Process context. > + * Return: > + * * struct cgroup_subsys_state* - css of the allocated cgroup. > + * * ERR_PTR(-ENOMEM) - No memory available to allocate. > + */ > +static struct cgroup_subsys_state * > +enc_id_cg_alloc(struct cgroup_subsys_state *parent_css) > +{ > + enum encryption_id_type i; > + struct encryption_id_cgroup *cg; > + > + if (!parent_css) { > + cg = &root_cg; > + } else { > + cg = kzalloc(sizeof(*cg), GFP_KERNEL); > + if (!cg) > + return ERR_PTR(-ENOMEM); > + } > + > + for (i = 0; i < ENCRYPTION_ID_TYPES; i++) > + cg->res[i].max = MAX_NUM; > + > + return &cg->css; > +} > + > +/** > + * enc_id_cg_free() - Free the encryption ID cgroup. > + * @css: cgroup subsys object. > + * > + * Context: Any context. > + */ > +static void enc_id_cg_free(struct cgroup_subsys_state *css) > +{ > + kfree(css_enc(css)); > +} > + > +/* Cgroup controller callbacks */ > +struct cgroup_subsys encryption_ids_cgrp_subsys = { > + .css_alloc = enc_id_cg_alloc, > + .css_free = enc_id_cg_free, > + .legacy_cftypes = enc_id_cg_files, > + .dfl_cftypes = enc_id_cg_files, > +};
| |