Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Miscellaneous cgroup controller
0004  *
0005  * Copyright 2020 Google LLC
0006  * Author: Vipin Sharma <vipinsh@google.com>
0007  */
0008 
0009 #include <linux/limits.h>
0010 #include <linux/cgroup.h>
0011 #include <linux/errno.h>
0012 #include <linux/atomic.h>
0013 #include <linux/slab.h>
0014 #include <linux/misc_cgroup.h>
0015 
0016 #define MAX_STR "max"
0017 #define MAX_NUM ULONG_MAX
0018 
0019 /* Miscellaneous res name, keep it in sync with enum misc_res_type */
0020 static const char *const misc_res_name[] = {
0021 #ifdef CONFIG_KVM_AMD_SEV
0022     /* AMD SEV ASIDs resource */
0023     "sev",
0024     /* AMD SEV-ES ASIDs resource */
0025     "sev_es",
0026 #endif
0027 };
0028 
0029 /* Root misc cgroup */
0030 static struct misc_cg root_cg;
0031 
0032 /*
0033  * Miscellaneous resources capacity for the entire machine. 0 capacity means
0034  * resource is not initialized or not present in the host.
0035  *
0036  * root_cg.max and capacity are independent of each other. root_cg.max can be
0037  * more than the actual capacity. We are using Limits resource distribution
0038  * model of cgroup for miscellaneous controller.
0039  */
0040 static unsigned long misc_res_capacity[MISC_CG_RES_TYPES];
0041 
0042 /**
0043  * parent_misc() - Get the parent of the passed misc cgroup.
0044  * @cgroup: cgroup whose parent needs to be fetched.
0045  *
0046  * Context: Any context.
0047  * Return:
0048  * * struct misc_cg* - Parent of the @cgroup.
0049  * * %NULL - If @cgroup is null or the passed cgroup does not have a parent.
0050  */
0051 static struct misc_cg *parent_misc(struct misc_cg *cgroup)
0052 {
0053     return cgroup ? css_misc(cgroup->css.parent) : NULL;
0054 }
0055 
0056 /**
0057  * valid_type() - Check if @type is valid or not.
0058  * @type: misc res type.
0059  *
0060  * Context: Any context.
0061  * Return:
0062  * * true - If valid type.
0063  * * false - If not valid type.
0064  */
0065 static inline bool valid_type(enum misc_res_type type)
0066 {
0067     return type >= 0 && type < MISC_CG_RES_TYPES;
0068 }
0069 
0070 /**
0071  * misc_cg_res_total_usage() - Get the current total usage of the resource.
0072  * @type: misc res type.
0073  *
0074  * Context: Any context.
0075  * Return: Current total usage of the resource.
0076  */
0077 unsigned long misc_cg_res_total_usage(enum misc_res_type type)
0078 {
0079     if (valid_type(type))
0080         return atomic_long_read(&root_cg.res[type].usage);
0081 
0082     return 0;
0083 }
0084 EXPORT_SYMBOL_GPL(misc_cg_res_total_usage);
0085 
0086 /**
0087  * misc_cg_set_capacity() - Set the capacity of the misc cgroup res.
0088  * @type: Type of the misc res.
0089  * @capacity: Supported capacity of the misc res on the host.
0090  *
0091  * If capacity is 0 then the charging a misc cgroup fails for that type.
0092  *
0093  * Context: Any context.
0094  * Return:
0095  * * %0 - Successfully registered the capacity.
0096  * * %-EINVAL - If @type is invalid.
0097  */
0098 int misc_cg_set_capacity(enum misc_res_type type, unsigned long capacity)
0099 {
0100     if (!valid_type(type))
0101         return -EINVAL;
0102 
0103     WRITE_ONCE(misc_res_capacity[type], capacity);
0104     return 0;
0105 }
0106 EXPORT_SYMBOL_GPL(misc_cg_set_capacity);
0107 
0108 /**
0109  * misc_cg_cancel_charge() - Cancel the charge from the misc cgroup.
0110  * @type: Misc res type in misc cg to cancel the charge from.
0111  * @cg: Misc cgroup to cancel charge from.
0112  * @amount: Amount to cancel.
0113  *
0114  * Context: Any context.
0115  */
0116 static void misc_cg_cancel_charge(enum misc_res_type type, struct misc_cg *cg,
0117                   unsigned long amount)
0118 {
0119     WARN_ONCE(atomic_long_add_negative(-amount, &cg->res[type].usage),
0120           "misc cgroup resource %s became less than 0",
0121           misc_res_name[type]);
0122 }
0123 
0124 /**
0125  * misc_cg_try_charge() - Try charging the misc cgroup.
0126  * @type: Misc res type to charge.
0127  * @cg: Misc cgroup which will be charged.
0128  * @amount: Amount to charge.
0129  *
0130  * Charge @amount to the misc cgroup. Caller must use the same cgroup during
0131  * the uncharge call.
0132  *
0133  * Context: Any context.
0134  * Return:
0135  * * %0 - If successfully charged.
0136  * * -EINVAL - If @type is invalid or misc res has 0 capacity.
0137  * * -EBUSY - If max limit will be crossed or total usage will be more than the
0138  *        capacity.
0139  */
0140 int misc_cg_try_charge(enum misc_res_type type, struct misc_cg *cg,
0141                unsigned long amount)
0142 {
0143     struct misc_cg *i, *j;
0144     int ret;
0145     struct misc_res *res;
0146     int new_usage;
0147 
0148     if (!(valid_type(type) && cg && READ_ONCE(misc_res_capacity[type])))
0149         return -EINVAL;
0150 
0151     if (!amount)
0152         return 0;
0153 
0154     for (i = cg; i; i = parent_misc(i)) {
0155         res = &i->res[type];
0156 
0157         new_usage = atomic_long_add_return(amount, &res->usage);
0158         if (new_usage > READ_ONCE(res->max) ||
0159             new_usage > READ_ONCE(misc_res_capacity[type])) {
0160             ret = -EBUSY;
0161             goto err_charge;
0162         }
0163     }
0164     return 0;
0165 
0166 err_charge:
0167     for (j = i; j; j = parent_misc(j)) {
0168         atomic_long_inc(&j->res[type].events);
0169         cgroup_file_notify(&j->events_file);
0170     }
0171 
0172     for (j = cg; j != i; j = parent_misc(j))
0173         misc_cg_cancel_charge(type, j, amount);
0174     misc_cg_cancel_charge(type, i, amount);
0175     return ret;
0176 }
0177 EXPORT_SYMBOL_GPL(misc_cg_try_charge);
0178 
0179 /**
0180  * misc_cg_uncharge() - Uncharge the misc cgroup.
0181  * @type: Misc res type which was charged.
0182  * @cg: Misc cgroup which will be uncharged.
0183  * @amount: Charged amount.
0184  *
0185  * Context: Any context.
0186  */
0187 void misc_cg_uncharge(enum misc_res_type type, struct misc_cg *cg,
0188               unsigned long amount)
0189 {
0190     struct misc_cg *i;
0191 
0192     if (!(amount && valid_type(type) && cg))
0193         return;
0194 
0195     for (i = cg; i; i = parent_misc(i))
0196         misc_cg_cancel_charge(type, i, amount);
0197 }
0198 EXPORT_SYMBOL_GPL(misc_cg_uncharge);
0199 
0200 /**
0201  * misc_cg_max_show() - Show the misc cgroup max limit.
0202  * @sf: Interface file
0203  * @v: Arguments passed
0204  *
0205  * Context: Any context.
0206  * Return: 0 to denote successful print.
0207  */
0208 static int misc_cg_max_show(struct seq_file *sf, void *v)
0209 {
0210     int i;
0211     struct misc_cg *cg = css_misc(seq_css(sf));
0212     unsigned long max;
0213 
0214     for (i = 0; i < MISC_CG_RES_TYPES; i++) {
0215         if (READ_ONCE(misc_res_capacity[i])) {
0216             max = READ_ONCE(cg->res[i].max);
0217             if (max == MAX_NUM)
0218                 seq_printf(sf, "%s max\n", misc_res_name[i]);
0219             else
0220                 seq_printf(sf, "%s %lu\n", misc_res_name[i],
0221                        max);
0222         }
0223     }
0224 
0225     return 0;
0226 }
0227 
0228 /**
0229  * misc_cg_max_write() - Update the maximum limit of the cgroup.
0230  * @of: Handler for the file.
0231  * @buf: Data from the user. It should be either "max", 0, or a positive
0232  *   integer.
0233  * @nbytes: Number of bytes of the data.
0234  * @off: Offset in the file.
0235  *
0236  * User can pass data like:
0237  * echo sev 23 > misc.max, OR
0238  * echo sev max > misc.max
0239  *
0240  * Context: Any context.
0241  * Return:
0242  * * >= 0 - Number of bytes processed in the input.
0243  * * -EINVAL - If buf is not valid.
0244  * * -ERANGE - If number is bigger than the unsigned long capacity.
0245  */
0246 static ssize_t misc_cg_max_write(struct kernfs_open_file *of, char *buf,
0247                  size_t nbytes, loff_t off)
0248 {
0249     struct misc_cg *cg;
0250     unsigned long max;
0251     int ret = 0, i;
0252     enum misc_res_type type = MISC_CG_RES_TYPES;
0253     char *token;
0254 
0255     buf = strstrip(buf);
0256     token = strsep(&buf, " ");
0257 
0258     if (!token || !buf)
0259         return -EINVAL;
0260 
0261     for (i = 0; i < MISC_CG_RES_TYPES; i++) {
0262         if (!strcmp(misc_res_name[i], token)) {
0263             type = i;
0264             break;
0265         }
0266     }
0267 
0268     if (type == MISC_CG_RES_TYPES)
0269         return -EINVAL;
0270 
0271     if (!strcmp(MAX_STR, buf)) {
0272         max = MAX_NUM;
0273     } else {
0274         ret = kstrtoul(buf, 0, &max);
0275         if (ret)
0276             return ret;
0277     }
0278 
0279     cg = css_misc(of_css(of));
0280 
0281     if (READ_ONCE(misc_res_capacity[type]))
0282         WRITE_ONCE(cg->res[type].max, max);
0283     else
0284         ret = -EINVAL;
0285 
0286     return ret ? ret : nbytes;
0287 }
0288 
0289 /**
0290  * misc_cg_current_show() - Show the current usage of the misc cgroup.
0291  * @sf: Interface file
0292  * @v: Arguments passed
0293  *
0294  * Context: Any context.
0295  * Return: 0 to denote successful print.
0296  */
0297 static int misc_cg_current_show(struct seq_file *sf, void *v)
0298 {
0299     int i;
0300     unsigned long usage;
0301     struct misc_cg *cg = css_misc(seq_css(sf));
0302 
0303     for (i = 0; i < MISC_CG_RES_TYPES; i++) {
0304         usage = atomic_long_read(&cg->res[i].usage);
0305         if (READ_ONCE(misc_res_capacity[i]) || usage)
0306             seq_printf(sf, "%s %lu\n", misc_res_name[i], usage);
0307     }
0308 
0309     return 0;
0310 }
0311 
0312 /**
0313  * misc_cg_capacity_show() - Show the total capacity of misc res on the host.
0314  * @sf: Interface file
0315  * @v: Arguments passed
0316  *
0317  * Only present in the root cgroup directory.
0318  *
0319  * Context: Any context.
0320  * Return: 0 to denote successful print.
0321  */
0322 static int misc_cg_capacity_show(struct seq_file *sf, void *v)
0323 {
0324     int i;
0325     unsigned long cap;
0326 
0327     for (i = 0; i < MISC_CG_RES_TYPES; i++) {
0328         cap = READ_ONCE(misc_res_capacity[i]);
0329         if (cap)
0330             seq_printf(sf, "%s %lu\n", misc_res_name[i], cap);
0331     }
0332 
0333     return 0;
0334 }
0335 
0336 static int misc_events_show(struct seq_file *sf, void *v)
0337 {
0338     struct misc_cg *cg = css_misc(seq_css(sf));
0339     unsigned long events, i;
0340 
0341     for (i = 0; i < MISC_CG_RES_TYPES; i++) {
0342         events = atomic_long_read(&cg->res[i].events);
0343         if (READ_ONCE(misc_res_capacity[i]) || events)
0344             seq_printf(sf, "%s.max %lu\n", misc_res_name[i], events);
0345     }
0346     return 0;
0347 }
0348 
0349 /* Misc cgroup interface files */
0350 static struct cftype misc_cg_files[] = {
0351     {
0352         .name = "max",
0353         .write = misc_cg_max_write,
0354         .seq_show = misc_cg_max_show,
0355         .flags = CFTYPE_NOT_ON_ROOT,
0356     },
0357     {
0358         .name = "current",
0359         .seq_show = misc_cg_current_show,
0360         .flags = CFTYPE_NOT_ON_ROOT,
0361     },
0362     {
0363         .name = "capacity",
0364         .seq_show = misc_cg_capacity_show,
0365         .flags = CFTYPE_ONLY_ON_ROOT,
0366     },
0367     {
0368         .name = "events",
0369         .flags = CFTYPE_NOT_ON_ROOT,
0370         .file_offset = offsetof(struct misc_cg, events_file),
0371         .seq_show = misc_events_show,
0372     },
0373     {}
0374 };
0375 
0376 /**
0377  * misc_cg_alloc() - Allocate misc cgroup.
0378  * @parent_css: Parent cgroup.
0379  *
0380  * Context: Process context.
0381  * Return:
0382  * * struct cgroup_subsys_state* - css of the allocated cgroup.
0383  * * ERR_PTR(-ENOMEM) - No memory available to allocate.
0384  */
0385 static struct cgroup_subsys_state *
0386 misc_cg_alloc(struct cgroup_subsys_state *parent_css)
0387 {
0388     enum misc_res_type i;
0389     struct misc_cg *cg;
0390 
0391     if (!parent_css) {
0392         cg = &root_cg;
0393     } else {
0394         cg = kzalloc(sizeof(*cg), GFP_KERNEL);
0395         if (!cg)
0396             return ERR_PTR(-ENOMEM);
0397     }
0398 
0399     for (i = 0; i < MISC_CG_RES_TYPES; i++) {
0400         WRITE_ONCE(cg->res[i].max, MAX_NUM);
0401         atomic_long_set(&cg->res[i].usage, 0);
0402     }
0403 
0404     return &cg->css;
0405 }
0406 
0407 /**
0408  * misc_cg_free() - Free the misc cgroup.
0409  * @css: cgroup subsys object.
0410  *
0411  * Context: Any context.
0412  */
0413 static void misc_cg_free(struct cgroup_subsys_state *css)
0414 {
0415     kfree(css_misc(css));
0416 }
0417 
0418 /* Cgroup controller callbacks */
0419 struct cgroup_subsys misc_cgrp_subsys = {
0420     .css_alloc = misc_cg_alloc,
0421     .css_free = misc_cg_free,
0422     .legacy_cftypes = misc_cg_files,
0423     .dfl_cftypes = misc_cg_files,
0424 };