函数的目的是根据 cgroup 的配额来计算它实际能从上层group中瓜分的额度。
以 min 为例:
struct page_counter {
/*
* Make sure 'usage' does not share cacheline with any other field. The
* memcg->memory.usage is a hot member of struct mem_cgroup.
*/
atomic_long_t usage; // 本节点已经用的页数
CACHELINE_PADDING(_pad1_);
/* effective memory.min and memory.min usage tracking */
unsigned long emin; // 本节点实际从上层瓜分的min保留额度。
atomic_long_t min_usage; // 本节点已经使用的min保留额度。
atomic_long_t children_min_usage; // 本节点的所有子节点已经实际使用的页数(当有子节点的实际使用页数没有达到它的min保留额度时,其使用值会当成min保留额度去累加)。
/* effective memory.low and memory.low usage tracking */
unsigned long elow;
atomic_long_t low_usage;
atomic_long_t children_low_usage;
unsigned long watermark;
unsigned long failcnt;
/* Keep all the read most fields in a separete cacheline. */
CACHELINE_PADDING(_pad2_);
unsigned long min; // 本节点设置的min保留额度
unsigned long low;
unsigned long high;
unsigned long max;
struct page_counter *parent;
} ____cacheline_internodealigned_in_smp;
effective_protection实现如下,其多退少补的原则大概描述为:实际额度已用完,就按已分配的页数占总分配页的比瓜分额度;实际额度未用完,则在本节点已分配内存的基础上,按本节点使用超出额度的部分占所有使用超出额度部分的比瓜分剩余额度。
/**
* @param setting: 本节点实际分配了的页数
* @param parent_effective: 父节点从祖父节点实际划分来的预留额度
* @param siblings_protected: 父节点的所有子节点已分配页数或预留额度的和(已分配页数不足预留额度时,按预留额度计),这其中包含了本节点
*/
static unsigned long effective_protection(unsigned long usage,
unsigned long parent_usage,
unsigned long setting,
unsigned long parent_effective,
unsigned long siblings_protected)
{
unsigned long protected;
unsigned long ep;
// 已分配页数不足预留额度时,按预留额度计
protected = min(usage, setting);
// 子实际使用或预留额度的和超出了父节点实际瓜分的值,则按父本节点在所有子节点中的比例去瓜分父的实际额度
if (siblings_protected > parent_effective)
return protected * parent_effective / siblings_protected;
ep = protected;
if (!(cgrp_dfl_root.flags & CGRP_ROOT_MEMORY_RECURSIVE_PROT))
return ep;
// 父瓜分额度大于所有子节点的实际使用或预留额度时,如果本节点分配的页数超出了设定额度,则按与本节点超出预留部分,与父节点超出所有子节点使用部分或预留部分的比值,来瓜分未分配的预留额度。如果本节点使用已经超出了预留额度,则不再瓜分。
if (parent_effective > siblings_protected &&
parent_usage > siblings_protected &&
usage > protected) {
unsigned long unclaimed;
unclaimed = parent_effective - siblings_protected;
unclaimed *= usage - protected;
unclaimed /= parent_usage - siblings_protected;
ep += unclaimed;
}
return ep;
}