^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * RDMA resource limiting controller for cgroups.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Used to allow a cgroup hierarchy to stop processes from consuming
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * additional RDMA resources after a certain limit is reached.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Copyright (C) 2016 Parav Pandit <pandit.parav@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/bitops.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/seq_file.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/cgroup.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/parser.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/cgroup_rdma.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define RDMACG_MAX_STR "max"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * Protects list of resource pools maintained on per cgroup basis
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * and rdma device list.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) static DEFINE_MUTEX(rdmacg_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static LIST_HEAD(rdmacg_devices);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) enum rdmacg_file_type {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) RDMACG_RESOURCE_TYPE_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) RDMACG_RESOURCE_TYPE_STAT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * resource table definition as to be seen by the user.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * Need to add entries to it when more resources are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * added/defined at IB verb/core layer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static char const *rdmacg_resource_names[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) [RDMACG_RESOURCE_HCA_HANDLE] = "hca_handle",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) [RDMACG_RESOURCE_HCA_OBJECT] = "hca_object",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) /* resource tracker for each resource of rdma cgroup */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) struct rdmacg_resource {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) int max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) int usage;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * resource pool object which represents per cgroup, per device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * resources. There are multiple instances of this object per cgroup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * therefore it cannot be embedded within rdma_cgroup structure. It
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * is maintained as list.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) struct rdmacg_resource_pool {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) struct rdmacg_device *device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) struct rdmacg_resource resources[RDMACG_RESOURCE_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) struct list_head cg_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct list_head dev_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) /* count active user tasks of this pool */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) u64 usage_sum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) /* total number counts which are set to max */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) int num_max_cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) static struct rdma_cgroup *css_rdmacg(struct cgroup_subsys_state *css)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return container_of(css, struct rdma_cgroup, css);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) static struct rdma_cgroup *parent_rdmacg(struct rdma_cgroup *cg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) return css_rdmacg(cg->css.parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) static inline struct rdma_cgroup *get_current_rdmacg(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) return css_rdmacg(task_get_css(current, rdma_cgrp_id));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static void set_resource_limit(struct rdmacg_resource_pool *rpool,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) int index, int new_max)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) if (new_max == S32_MAX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (rpool->resources[index].max != S32_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) rpool->num_max_cnt++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) if (rpool->resources[index].max == S32_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) rpool->num_max_cnt--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) rpool->resources[index].max = new_max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static void set_all_resource_max_limit(struct rdmacg_resource_pool *rpool)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) for (i = 0; i < RDMACG_RESOURCE_MAX; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) set_resource_limit(rpool, i, S32_MAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) static void free_cg_rpool_locked(struct rdmacg_resource_pool *rpool)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) lockdep_assert_held(&rdmacg_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) list_del(&rpool->cg_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) list_del(&rpool->dev_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) kfree(rpool);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) static struct rdmacg_resource_pool *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) find_cg_rpool_locked(struct rdma_cgroup *cg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) struct rdmacg_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) struct rdmacg_resource_pool *pool;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) lockdep_assert_held(&rdmacg_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) list_for_each_entry(pool, &cg->rpools, cg_node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (pool->device == device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) return pool;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) static struct rdmacg_resource_pool *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) get_cg_rpool_locked(struct rdma_cgroup *cg, struct rdmacg_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) struct rdmacg_resource_pool *rpool;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) rpool = find_cg_rpool_locked(cg, device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) if (rpool)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) return rpool;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) rpool = kzalloc(sizeof(*rpool), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (!rpool)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) rpool->device = device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) set_all_resource_max_limit(rpool);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) INIT_LIST_HEAD(&rpool->cg_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) INIT_LIST_HEAD(&rpool->dev_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) list_add_tail(&rpool->cg_node, &cg->rpools);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) list_add_tail(&rpool->dev_node, &device->rpools);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) return rpool;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) * uncharge_cg_locked - uncharge resource for rdma cgroup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) * @cg: pointer to cg to uncharge and all parents in hierarchy
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) * @device: pointer to rdmacg device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) * @index: index of the resource to uncharge in cg (resource pool)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * It also frees the resource pool which was created as part of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) * charging operation when there are no resources attached to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) * resource pool.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) uncharge_cg_locked(struct rdma_cgroup *cg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) struct rdmacg_device *device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) enum rdmacg_resource_type index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) struct rdmacg_resource_pool *rpool;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) rpool = find_cg_rpool_locked(cg, device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) * rpool cannot be null at this stage. Let kernel operate in case
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) * if there a bug in IB stack or rdma controller, instead of crashing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) * the system.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) if (unlikely(!rpool)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) pr_warn("Invalid device %p or rdma cgroup %p\n", cg, device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) rpool->resources[index].usage--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) * A negative count (or overflow) is invalid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) * it indicates a bug in the rdma controller.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) WARN_ON_ONCE(rpool->resources[index].usage < 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) rpool->usage_sum--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (rpool->usage_sum == 0 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) rpool->num_max_cnt == RDMACG_RESOURCE_MAX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) * No user of the rpool and all entries are set to max, so
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) * safe to delete this rpool.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) free_cg_rpool_locked(rpool);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) * rdmacg_uncharge_hierarchy - hierarchically uncharge rdma resource count
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) * @device: pointer to rdmacg device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) * @stop_cg: while traversing hirerchy, when meet with stop_cg cgroup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) * stop uncharging
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) * @index: index of the resource to uncharge in cg in given resource pool
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) static void rdmacg_uncharge_hierarchy(struct rdma_cgroup *cg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) struct rdmacg_device *device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) struct rdma_cgroup *stop_cg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) enum rdmacg_resource_type index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) struct rdma_cgroup *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) mutex_lock(&rdmacg_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) for (p = cg; p != stop_cg; p = parent_rdmacg(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) uncharge_cg_locked(p, device, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) mutex_unlock(&rdmacg_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) css_put(&cg->css);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) * rdmacg_uncharge - hierarchically uncharge rdma resource count
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) * @device: pointer to rdmacg device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) * @index: index of the resource to uncharge in cgroup in given resource pool
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) void rdmacg_uncharge(struct rdma_cgroup *cg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) struct rdmacg_device *device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) enum rdmacg_resource_type index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) if (index >= RDMACG_RESOURCE_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) rdmacg_uncharge_hierarchy(cg, device, NULL, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) EXPORT_SYMBOL(rdmacg_uncharge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) * rdmacg_try_charge - hierarchically try to charge the rdma resource
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) * @rdmacg: pointer to rdma cgroup which will own this resource
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) * @device: pointer to rdmacg device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) * @index: index of the resource to charge in cgroup (resource pool)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) * This function follows charging resource in hierarchical way.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) * It will fail if the charge would cause the new value to exceed the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) * hierarchical limit.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) * Returns 0 if the charge succeded, otherwise -EAGAIN, -ENOMEM or -EINVAL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) * Returns pointer to rdmacg for this resource when charging is successful.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) * Charger needs to account resources on two criteria.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) * (a) per cgroup & (b) per device resource usage.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) * Per cgroup resource usage ensures that tasks of cgroup doesn't cross
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) * the configured limits. Per device provides granular configuration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) * in multi device usage. It allocates resource pool in the hierarchy
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) * for each parent it come across for first resource. Later on resource
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) * pool will be available. Therefore it will be much faster thereon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) * to charge/uncharge.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) int rdmacg_try_charge(struct rdma_cgroup **rdmacg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) struct rdmacg_device *device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) enum rdmacg_resource_type index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) struct rdma_cgroup *cg, *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) struct rdmacg_resource_pool *rpool;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) s64 new;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) if (index >= RDMACG_RESOURCE_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) * hold on to css, as cgroup can be removed but resource
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) * accounting happens on css.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) cg = get_current_rdmacg();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) mutex_lock(&rdmacg_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) for (p = cg; p; p = parent_rdmacg(p)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) rpool = get_cg_rpool_locked(p, device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) if (IS_ERR(rpool)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) ret = PTR_ERR(rpool);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) new = rpool->resources[index].usage + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) if (new > rpool->resources[index].max) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) ret = -EAGAIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) rpool->resources[index].usage = new;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) rpool->usage_sum++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) mutex_unlock(&rdmacg_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) *rdmacg = cg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) mutex_unlock(&rdmacg_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) rdmacg_uncharge_hierarchy(cg, device, p, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) EXPORT_SYMBOL(rdmacg_try_charge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) * rdmacg_register_device - register rdmacg device to rdma controller.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) * @device: pointer to rdmacg device whose resources need to be accounted.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) * If IB stack wish a device to participate in rdma cgroup resource
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) * tracking, it must invoke this API to register with rdma cgroup before
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) * any user space application can start using the RDMA resources.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) void rdmacg_register_device(struct rdmacg_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) INIT_LIST_HEAD(&device->dev_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) INIT_LIST_HEAD(&device->rpools);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) mutex_lock(&rdmacg_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) list_add_tail(&device->dev_node, &rdmacg_devices);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) mutex_unlock(&rdmacg_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) EXPORT_SYMBOL(rdmacg_register_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) * rdmacg_unregister_device - unregister rdmacg device from rdma controller.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) * @device: pointer to rdmacg device which was previously registered with rdma
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) * controller using rdmacg_register_device().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) * IB stack must invoke this after all the resources of the IB device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) * are destroyed and after ensuring that no more resources will be created
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) * when this API is invoked.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) void rdmacg_unregister_device(struct rdmacg_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) struct rdmacg_resource_pool *rpool, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) * Synchronize with any active resource settings,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) * usage query happening via configfs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) mutex_lock(&rdmacg_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) list_del_init(&device->dev_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) * Now that this device is off the cgroup list, its safe to free
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) * all the rpool resources.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) list_for_each_entry_safe(rpool, tmp, &device->rpools, dev_node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) free_cg_rpool_locked(rpool);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) mutex_unlock(&rdmacg_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) EXPORT_SYMBOL(rdmacg_unregister_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) static int parse_resource(char *c, int *intval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) substring_t argstr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) char *name, *value = c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) size_t len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) int ret, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) name = strsep(&value, "=");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) if (!name || !value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) i = match_string(rdmacg_resource_names, RDMACG_RESOURCE_MAX, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) if (i < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) len = strlen(value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) argstr.from = value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) argstr.to = value + len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) ret = match_int(&argstr, intval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) if (ret >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) if (*intval < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) if (strncmp(value, RDMACG_MAX_STR, len) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) *intval = S32_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) static int rdmacg_parse_limits(char *options,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) int *new_limits, unsigned long *enables)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) char *c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) int err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) /* parse resource options */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) while ((c = strsep(&options, " ")) != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) int index, intval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) index = parse_resource(c, &intval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) if (index < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) new_limits[index] = intval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) *enables |= BIT(index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) static struct rdmacg_device *rdmacg_get_device_locked(const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) struct rdmacg_device *device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) lockdep_assert_held(&rdmacg_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) list_for_each_entry(device, &rdmacg_devices, dev_node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) if (!strcmp(name, device->name))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) return device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) static ssize_t rdmacg_resource_set_max(struct kernfs_open_file *of,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) char *buf, size_t nbytes, loff_t off)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) struct rdma_cgroup *cg = css_rdmacg(of_css(of));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) const char *dev_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) struct rdmacg_resource_pool *rpool;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) struct rdmacg_device *device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) char *options = strstrip(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) int *new_limits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) unsigned long enables = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) int i = 0, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) /* extract the device name first */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) dev_name = strsep(&options, " ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) if (!dev_name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) new_limits = kcalloc(RDMACG_RESOURCE_MAX, sizeof(int), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) if (!new_limits) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) ret = rdmacg_parse_limits(options, new_limits, &enables);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) goto parse_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) /* acquire lock to synchronize with hot plug devices */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) mutex_lock(&rdmacg_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) device = rdmacg_get_device_locked(dev_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) if (!device) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) goto dev_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) rpool = get_cg_rpool_locked(cg, device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) if (IS_ERR(rpool)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) ret = PTR_ERR(rpool);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) goto dev_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) /* now set the new limits of the rpool */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) for_each_set_bit(i, &enables, RDMACG_RESOURCE_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) set_resource_limit(rpool, i, new_limits[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) if (rpool->usage_sum == 0 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) rpool->num_max_cnt == RDMACG_RESOURCE_MAX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) * No user of the rpool and all entries are set to max, so
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) * safe to delete this rpool.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) free_cg_rpool_locked(rpool);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) dev_err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) mutex_unlock(&rdmacg_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) parse_err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) kfree(new_limits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) return ret ?: nbytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) static void print_rpool_values(struct seq_file *sf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) struct rdmacg_resource_pool *rpool)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) enum rdmacg_file_type sf_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) u32 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) sf_type = seq_cft(sf)->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) for (i = 0; i < RDMACG_RESOURCE_MAX; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) seq_puts(sf, rdmacg_resource_names[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) seq_putc(sf, '=');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) if (sf_type == RDMACG_RESOURCE_TYPE_MAX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) if (rpool)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) value = rpool->resources[i].max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) value = S32_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) if (rpool)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) value = rpool->resources[i].usage;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) value = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) if (value == S32_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) seq_puts(sf, RDMACG_MAX_STR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) seq_printf(sf, "%d", value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) seq_putc(sf, ' ');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) static int rdmacg_resource_read(struct seq_file *sf, void *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) struct rdmacg_device *device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) struct rdmacg_resource_pool *rpool;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) struct rdma_cgroup *cg = css_rdmacg(seq_css(sf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) mutex_lock(&rdmacg_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) list_for_each_entry(device, &rdmacg_devices, dev_node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) seq_printf(sf, "%s ", device->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) rpool = find_cg_rpool_locked(cg, device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) print_rpool_values(sf, rpool);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) seq_putc(sf, '\n');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) mutex_unlock(&rdmacg_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) static struct cftype rdmacg_files[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) .name = "max",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) .write = rdmacg_resource_set_max,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) .seq_show = rdmacg_resource_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) .private = RDMACG_RESOURCE_TYPE_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) .flags = CFTYPE_NOT_ON_ROOT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) .name = "current",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) .seq_show = rdmacg_resource_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) .private = RDMACG_RESOURCE_TYPE_STAT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) .flags = CFTYPE_NOT_ON_ROOT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) { } /* terminate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) static struct cgroup_subsys_state *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) rdmacg_css_alloc(struct cgroup_subsys_state *parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) struct rdma_cgroup *cg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) cg = kzalloc(sizeof(*cg), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) if (!cg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) INIT_LIST_HEAD(&cg->rpools);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) return &cg->css;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) static void rdmacg_css_free(struct cgroup_subsys_state *css)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) struct rdma_cgroup *cg = css_rdmacg(css);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) kfree(cg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) * rdmacg_css_offline - cgroup css_offline callback
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) * @css: css of interest
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) * This function is called when @css is about to go away and responsible
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) * for shooting down all rdmacg associated with @css. As part of that it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) * marks all the resource pool entries to max value, so that when resources are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) * uncharged, associated resource pool can be freed as well.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) static void rdmacg_css_offline(struct cgroup_subsys_state *css)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) struct rdma_cgroup *cg = css_rdmacg(css);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) struct rdmacg_resource_pool *rpool;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) mutex_lock(&rdmacg_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) list_for_each_entry(rpool, &cg->rpools, cg_node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) set_all_resource_max_limit(rpool);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) mutex_unlock(&rdmacg_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) struct cgroup_subsys rdma_cgrp_subsys = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) .css_alloc = rdmacg_css_alloc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) .css_free = rdmacg_css_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) .css_offline = rdmacg_css_offline,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) .legacy_cftypes = rdmacg_files,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) .dfl_cftypes = rdmacg_files,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) };