Source code for crash.subsystem.cgroup

# -*- coding: utf-8 -*-
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:

from typing import Dict, Iterator, List

import gdb

from crash.exceptions import InvalidArgumentError, CorruptedError
from crash.types.list import list_for_each_entry
from crash.util import AddressSpecifier, get_typed_pointer
from crash.util.symbols import Types, Symvals, TypeCallbacks, SymbolCallbacks

symvals = Symvals(['cgroup_roots', 'cgroup_subsys'])
types = Types([
    'struct cgroup',
    'struct cgroup_root',
    'struct cgroup_subsys',
    'struct cgrp_cset_link',
    'struct task_struct',
])

[docs] class Subsys: _subsys_names: Dict[int, str] = dict() _available_mask = 0
[docs] @classmethod def init_subsys_ids(cls, subsys_enum: gdb.Type) -> None: suffix = '_cgrp_id' for k in subsys_enum.keys(): if k == 'CGROUP_SUBSYS_COUNT': continue if subsys_enum[k].enumval in cls._subsys_names: raise InvalidArgumentError("Enum {} is not unique".format(subsys_enum.name)) if not k.endswith(suffix): raise InvalidArgumentError("Enum {} has unknown names".format(subsys_enum.name)) cls._subsys_names[subsys_enum[k].enumval] = k[:-len(suffix)] cls._available_mask |= (1 << subsys_enum[k].enumval)
[docs] def for_each_subsys(self) -> Iterator[gdb.Value]: for ssid in self._subsys_names: yield symvals.cgroup_subsys[ssid].dereference()
[docs] def subsys_mask_to_names(self, mask: int) -> List[str]: unknown = mask & ~self._available_mask if unknown: raise InvalidArgumentError(f"Mask contains unknown controllers {unknown:x}") ret = [] for ssid in self._subsys_names: if mask & (1 << ssid): ret.append(self._subsys_names[ssid]) return ret
_Subsys = Subsys()
[docs] def for_each_hierarchy() -> Iterator[gdb.Value]: # TODO should we factor in cgrp_dfl_visible? return list_for_each_entry(symvals.cgroup_roots, types.cgroup_root_type, 'root_list')
[docs] def for_each_subsys() -> Iterator[gdb.Value]: return _Subsys.for_each_subsys()
[docs] def subsys_mask_to_names(mask: int) -> List[str]: return _Subsys.subsys_mask_to_names(mask)
[docs] def cgroup_from_root(task: gdb.Value, cgroup_root: gdb.Value) -> gdb.Value: cssset = task['cgroups'].dereference() for link in list_for_each_entry(cssset['cgrp_links'], types.cgrp_cset_link_type, 'cgrp_link'): if link['cgrp']['root'] == cgroup_root.address: return link['cgrp'].dereference() # TODO think about migrating tasks raise CorruptedError( "Task {int(task.address):016x} not under cgroup_root {int(cgroup_root.address):016x}}" )
[docs] def find_cgroup(addr: AddressSpecifier) -> gdb.Value: cgrp = get_typed_pointer(addr, types.cgroup_type).dereference() return cgrp
[docs] def for_each_cgroup_task(cgrp: gdb.Value) -> Iterator[gdb.Value]: # TODO migrating tasks?, zombies? for link in list_for_each_entry(cgrp['cset_links'], types.cgrp_cset_link_type, 'cset_link'): cssset = link['cset'].dereference() for task in list_for_each_entry(cssset['tasks'], types.task_struct_type, 'cg_list'): yield task
type_cbs = TypeCallbacks([('enum cgroup_subsys_id', Subsys.init_subsys_ids)])