xref: /linux/tools/testing/selftests/damon/_damon_sysfs.py (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
1# SPDX-License-Identifier: GPL-2.0
2
3import os
4
5ksft_skip=4
6
7sysfs_root = None
8with open('/proc/mounts', 'r') as f:
9    for line in f:
10        dev_name, mount_point, dev_fs = line.split()[:3]
11        if dev_fs == 'sysfs':
12            sysfs_root = '%s/kernel/mm/damon/admin' % mount_point
13            break
14if sysfs_root is None:
15    print('Seems sysfs not mounted?')
16    exit(ksft_skip)
17
18if not os.path.exists(sysfs_root):
19    print('Seems DAMON disabled?')
20    exit(ksft_skip)
21
22def write_file(path, string):
23    "Returns error string if failed, or None otherwise"
24    string = '%s' % string
25    try:
26        with open(path, 'w') as f:
27            f.write(string)
28    except Exception as e:
29        return '%s' % e
30    return None
31
32def read_file(path):
33    '''Returns the read content and error string.  The read content is None if
34    the reading failed'''
35    try:
36        with open(path, 'r') as f:
37            return f.read(), None
38    except Exception as e:
39        return None, '%s' % e
40
41class DamosAccessPattern:
42    size = None
43    nr_accesses = None
44    age = None
45    scheme = None
46
47    def __init__(self, size=None, nr_accesses=None, age=None):
48        self.size = size
49        self.nr_accesses = nr_accesses
50        self.age = age
51
52        if self.size is None:
53            self.size = [0, 2**64 - 1]
54        if self.nr_accesses is None:
55            self.nr_accesses = [0, 2**32 - 1]
56        if self.age is None:
57            self.age = [0, 2**32 - 1]
58
59    def sysfs_dir(self):
60        return os.path.join(self.scheme.sysfs_dir(), 'access_pattern')
61
62    def stage(self):
63        err = write_file(
64                os.path.join(self.sysfs_dir(), 'sz', 'min'), self.size[0])
65        if err is not None:
66            return err
67        err = write_file(
68                os.path.join(self.sysfs_dir(), 'sz', 'max'), self.size[1])
69        if err is not None:
70            return err
71        err = write_file(os.path.join(self.sysfs_dir(), 'nr_accesses', 'min'),
72                self.nr_accesses[0])
73        if err is not None:
74            return err
75        err = write_file(os.path.join(self.sysfs_dir(), 'nr_accesses', 'max'),
76                self.nr_accesses[1])
77        if err is not None:
78            return err
79        err = write_file(
80                os.path.join(self.sysfs_dir(), 'age', 'min'), self.age[0])
81        if err is not None:
82            return err
83        err = write_file(
84                os.path.join(self.sysfs_dir(), 'age', 'max'), self.age[1])
85        if err is not None:
86            return err
87
88qgoal_metric_user_input = 'user_input'
89qgoal_metric_some_mem_psi_us = 'some_mem_psi_us'
90qgoal_metrics = [qgoal_metric_user_input, qgoal_metric_some_mem_psi_us]
91
92class DamosQuotaGoal:
93    metric = None
94    target_value = None
95    current_value = None
96    nid = None
97    effective_bytes = None
98    quota = None            # owner quota
99    idx = None
100
101    def __init__(self, metric, target_value=10000, current_value=0, nid=0):
102        self.metric = metric
103        self.target_value = target_value
104        self.current_value = current_value
105        self.nid = nid
106
107    def sysfs_dir(self):
108        return os.path.join(self.quota.sysfs_dir(), 'goals', '%d' % self.idx)
109
110    def stage(self):
111        err = write_file(os.path.join(self.sysfs_dir(), 'target_metric'),
112                         self.metric)
113        if err is not None:
114            return err
115        err = write_file(os.path.join(self.sysfs_dir(), 'target_value'),
116                         self.target_value)
117        if err is not None:
118            return err
119        err = write_file(os.path.join(self.sysfs_dir(), 'current_value'),
120                         self.current_value)
121        if err is not None:
122            return err
123        err = write_file(os.path.join(self.sysfs_dir(), 'nid'), self.nid)
124        if err is not None:
125            return err
126
127        return None
128
129class DamosQuota:
130    sz = None                   # size quota, in bytes
131    ms = None                   # time quota
132    goals = None                # quota goals
133    reset_interval_ms = None    # quota reset interval
134    weight_sz_permil = None
135    weight_nr_accesses_permil = None
136    weight_age_permil = None
137    scheme = None               # owner scheme
138
139    def __init__(self, sz=0, ms=0, goals=None, reset_interval_ms=0,
140                 weight_sz_permil=0, weight_nr_accesses_permil=0,
141                 weight_age_permil=0):
142        self.sz = sz
143        self.ms = ms
144        self.reset_interval_ms = reset_interval_ms
145        self.weight_sz_permil = weight_sz_permil
146        self.weight_nr_accesses_permil = weight_nr_accesses_permil
147        self.weight_age_permil = weight_age_permil
148        self.goals = goals if goals is not None else []
149        for idx, goal in enumerate(self.goals):
150            goal.idx = idx
151            goal.quota = self
152
153    def sysfs_dir(self):
154        return os.path.join(self.scheme.sysfs_dir(), 'quotas')
155
156    def stage(self):
157        err = write_file(os.path.join(self.sysfs_dir(), 'bytes'), self.sz)
158        if err is not None:
159            return err
160        err = write_file(os.path.join(self.sysfs_dir(), 'ms'), self.ms)
161        if err is not None:
162            return err
163        err = write_file(os.path.join(self.sysfs_dir(), 'reset_interval_ms'),
164                         self.reset_interval_ms)
165        if err is not None:
166            return err
167
168        err = write_file(os.path.join(
169            self.sysfs_dir(), 'weights', 'sz_permil'), self.weight_sz_permil)
170        if err is not None:
171            return err
172        err = write_file(os.path.join(
173            self.sysfs_dir(), 'weights', 'nr_accesses_permil'),
174                         self.weight_nr_accesses_permil)
175        if err is not None:
176            return err
177        err = write_file(os.path.join(
178            self.sysfs_dir(), 'weights', 'age_permil'), self.weight_age_permil)
179        if err is not None:
180            return err
181
182        nr_goals_file = os.path.join(self.sysfs_dir(), 'goals', 'nr_goals')
183        content, err = read_file(nr_goals_file)
184        if err is not None:
185            return err
186        if int(content) != len(self.goals):
187            err = write_file(nr_goals_file, len(self.goals))
188            if err is not None:
189                return err
190        for goal in self.goals:
191            err = goal.stage()
192            if err is not None:
193                return err
194        return None
195
196class DamosWatermarks:
197    metric = None
198    interval = None
199    high = None
200    mid = None
201    low = None
202    scheme = None   # owner scheme
203
204    def __init__(self, metric='none', interval=0, high=0, mid=0, low=0):
205        self.metric = metric
206        self.interval = interval
207        self.high = high
208        self.mid = mid
209        self.low = low
210
211    def sysfs_dir(self):
212        return os.path.join(self.scheme.sysfs_dir(), 'watermarks')
213
214    def stage(self):
215        err = write_file(os.path.join(self.sysfs_dir(), 'metric'), self.metric)
216        if err is not None:
217            return err
218        err = write_file(os.path.join(self.sysfs_dir(), 'interval_us'),
219                         self.interval)
220        if err is not None:
221            return err
222        err = write_file(os.path.join(self.sysfs_dir(), 'high'), self.high)
223        if err is not None:
224            return err
225        err = write_file(os.path.join(self.sysfs_dir(), 'mid'), self.mid)
226        if err is not None:
227            return err
228        err = write_file(os.path.join(self.sysfs_dir(), 'low'), self.low)
229        if err is not None:
230            return err
231
232class DamosFilter:
233    type_ = None
234    matching = None
235    allow = None
236    memcg_path = None
237    addr_start = None
238    addr_end = None
239    target_idx = None
240    min_ = None
241    max_ = None
242    idx = None
243    filters = None  # owner filters
244
245    def __init__(self, type_='anon', matching=False, allow=False,
246                 memcg_path='', addr_start=0, addr_end=0, target_idx=0, min_=0,
247                 max_=0):
248        self.type_ = type_
249        self.matching = matching
250        self.allow = allow
251        self.memcg_path = memcg_path,
252        self.addr_start = addr_start
253        self.addr_end = addr_end
254        self.target_idx = target_idx
255        self.min_ = min_
256        self.max_ = max_
257
258    def sysfs_dir(self):
259        return os.path.join(self.filters.sysfs_dir(), '%d' % self.idx)
260
261    def stage(self):
262        err = write_file(os.path.join(self.sysfs_dir(), 'type'), self.type_)
263        if err is not None:
264            return err
265        err = write_file(os.path.join(self.sysfs_dir(), 'matching'),
266                         self.matching)
267        if err is not None:
268            return err
269        err = write_file(os.path.join(self.sysfs_dir(), 'allow'), self.allow)
270        if err is not None:
271            return err
272        err = write_file(os.path.join(self.sysfs_dir(), 'memcg_path'),
273                         self.memcg_path)
274        if err is not None:
275            return err
276        err = write_file(os.path.join(self.sysfs_dir(), 'addr_start'),
277                         self.addr_start)
278        if err is not None:
279            return err
280        err = write_file(os.path.join(self.sysfs_dir(), 'addr_end'),
281                         self.addr_end)
282        if err is not None:
283            return err
284        err = write_file(os.path.join(self.sysfs_dir(), 'damon_target_idx'),
285                         self.target_idx)
286        if err is not None:
287            return err
288        err = write_file(os.path.join(self.sysfs_dir(), 'min'), self.min_)
289        if err is not None:
290            return err
291        err = write_file(os.path.join(self.sysfs_dir(), 'max'), self.max_)
292        if err is not None:
293            return err
294        return None
295
296class DamosFilters:
297    name = None
298    filters = None
299    scheme = None   # owner scheme
300
301    def __init__(self, name, filters=[]):
302        self.name = name
303        self.filters = filters
304        for idx, filter_ in enumerate(self.filters):
305            filter_.idx = idx
306            filter_.filters = self
307
308    def sysfs_dir(self):
309        return os.path.join(self.scheme.sysfs_dir(), self.name)
310
311    def stage(self):
312        err = write_file(os.path.join(self.sysfs_dir(), 'nr_filters'),
313                         len(self.filters))
314        if err is not None:
315            return err
316        for filter_ in self.filters:
317            err = filter_.stage()
318            if err is not None:
319                return err
320        return None
321
322class DamosDest:
323    id = None
324    weight = None
325    idx = None
326    dests = None    # owner dests
327
328    def __init__(self, id=0, weight=0):
329        self.id = id
330        self.weight = weight
331
332    def sysfs_dir(self):
333        return os.path.join(self.dests.sysfs_dir(), '%d' % self.idx)
334
335    def stage(self):
336        err = write_file(os.path.join(self.sysfs_dir(), 'id'), self.id)
337        if err is not None:
338            return err
339        err = write_file(os.path.join(self.sysfs_dir(), 'weight'), self.weight)
340        if err is not None:
341            return err
342        return None
343
344class DamosDests:
345    dests = None
346    scheme = None   # owner scheme
347
348    def __init__(self, dests=[]):
349        self.dests = dests
350        for idx, dest in enumerate(self.dests):
351            dest.idx = idx
352            dest.dests = self
353
354    def sysfs_dir(self):
355        return os.path.join(self.scheme.sysfs_dir(), 'dests')
356
357    def stage(self):
358        err = write_file(os.path.join(self.sysfs_dir(), 'nr_dests'),
359                         len(self.dests))
360        if err is not None:
361            return err
362        for dest in self.dests:
363            err = dest.stage()
364            if err is not None:
365                return err
366        return None
367
368class DamosStats:
369    nr_tried = None
370    sz_tried = None
371    nr_applied = None
372    sz_applied = None
373    qt_exceeds = None
374
375    def __init__(self, nr_tried, sz_tried, nr_applied, sz_applied, qt_exceeds):
376        self.nr_tried = nr_tried
377        self.sz_tried = sz_tried
378        self.nr_applied = nr_applied
379        self.sz_applied = sz_applied
380        self.qt_exceeds = qt_exceeds
381
382class DamosTriedRegion:
383    def __init__(self, start, end, nr_accesses, age):
384        self.start = start
385        self.end = end
386        self.nr_accesses = nr_accesses
387        self.age = age
388
389class Damos:
390    action = None
391    access_pattern = None
392    quota = None
393    watermarks = None
394    core_filters = None
395    ops_filters = None
396    filters = None
397    apply_interval_us = None
398    target_nid = None
399    dests = None
400    idx = None
401    context = None
402    tried_bytes = None
403    stats = None
404    tried_regions = None
405
406    def __init__(self, action='stat', access_pattern=DamosAccessPattern(),
407                 quota=DamosQuota(), watermarks=DamosWatermarks(),
408                 core_filters=[], ops_filters=[], filters=[], target_nid=0,
409                 dests=DamosDests(), apply_interval_us=0):
410        self.action = action
411        self.access_pattern = access_pattern
412        self.access_pattern.scheme = self
413        self.quota = quota
414        self.quota.scheme = self
415        self.watermarks = watermarks
416        self.watermarks.scheme = self
417
418        self.core_filters = DamosFilters(name='core_filters',
419                                         filters=core_filters)
420        self.core_filters.scheme = self
421        self.ops_filters = DamosFilters(name='ops_filters',
422                                         filters=ops_filters)
423        self.ops_filters.scheme = self
424        self.filters = DamosFilters(name='filters', filters=filters)
425        self.filters.scheme = self
426
427        self.target_nid = target_nid
428        self.dests = dests
429        self.dests.scheme = self
430
431        self.apply_interval_us = apply_interval_us
432
433    def sysfs_dir(self):
434        return os.path.join(
435                self.context.sysfs_dir(), 'schemes', '%d' % self.idx)
436
437    def stage(self):
438        err = write_file(os.path.join(self.sysfs_dir(), 'action'), self.action)
439        if err is not None:
440            return err
441        err = self.access_pattern.stage()
442        if err is not None:
443            return err
444        err = write_file(os.path.join(self.sysfs_dir(), 'apply_interval_us'),
445                         '%d' % self.apply_interval_us)
446        if err is not None:
447            return err
448
449        err = self.quota.stage()
450        if err is not None:
451            return err
452
453        err = self.watermarks.stage()
454        if err is not None:
455            return err
456
457        err = self.core_filters.stage()
458        if err is not None:
459            return err
460        err = self.ops_filters.stage()
461        if err is not None:
462            return err
463        err = self.filters.stage()
464        if err is not None:
465            return err
466
467        err = write_file(os.path.join(self.sysfs_dir(), 'target_nid'), '%d' %
468                         self.target_nid)
469        if err is not None:
470            return err
471
472        err = self.dests.stage()
473        if err is not None:
474            return err
475
476class DamonTarget:
477    pid = None
478    # todo: Support target regions if test is made
479    idx = None
480    context = None
481
482    def __init__(self, pid):
483        self.pid = pid
484
485    def sysfs_dir(self):
486        return os.path.join(
487                self.context.sysfs_dir(), 'targets', '%d' % self.idx)
488
489    def stage(self):
490        err = write_file(
491                os.path.join(self.sysfs_dir(), 'regions', 'nr_regions'), '0')
492        if err is not None:
493            return err
494        return write_file(
495                os.path.join(self.sysfs_dir(), 'pid_target'), self.pid)
496
497class IntervalsGoal:
498    access_bp = None
499    aggrs = None
500    min_sample_us = None
501    max_sample_us = None
502    attrs = None    # owner DamonAttrs
503
504    def __init__(self, access_bp=0, aggrs=0, min_sample_us=0, max_sample_us=0):
505        self.access_bp = access_bp
506        self.aggrs = aggrs
507        self.min_sample_us = min_sample_us
508        self.max_sample_us = max_sample_us
509
510    def sysfs_dir(self):
511        return os.path.join(self.attrs.interval_sysfs_dir(), 'intervals_goal')
512
513    def stage(self):
514        err = write_file(
515                os.path.join(self.sysfs_dir(), 'access_bp'), self.access_bp)
516        if err is not None:
517            return err
518        err = write_file(os.path.join(self.sysfs_dir(), 'aggrs'), self.aggrs)
519        if err is not None:
520            return err
521        err = write_file(os.path.join(self.sysfs_dir(), 'min_sample_us'),
522                         self.min_sample_us)
523        if err is not None:
524            return err
525        err = write_file(os.path.join(self.sysfs_dir(), 'max_sample_us'),
526                         self.max_sample_us)
527        if err is not None:
528            return err
529        return None
530
531class DamonAttrs:
532    sample_us = None
533    aggr_us = None
534    intervals_goal = None
535    update_us = None
536    min_nr_regions = None
537    max_nr_regions = None
538    context = None
539
540    def __init__(self, sample_us=5000, aggr_us=100000,
541                 intervals_goal=IntervalsGoal(), update_us=1000000,
542            min_nr_regions=10, max_nr_regions=1000):
543        self.sample_us = sample_us
544        self.aggr_us = aggr_us
545        self.intervals_goal = intervals_goal
546        self.intervals_goal.attrs = self
547        self.update_us = update_us
548        self.min_nr_regions = min_nr_regions
549        self.max_nr_regions = max_nr_regions
550
551    def interval_sysfs_dir(self):
552        return os.path.join(self.context.sysfs_dir(), 'monitoring_attrs',
553                'intervals')
554
555    def nr_regions_range_sysfs_dir(self):
556        return os.path.join(self.context.sysfs_dir(), 'monitoring_attrs',
557                'nr_regions')
558
559    def stage(self):
560        err = write_file(os.path.join(self.interval_sysfs_dir(), 'sample_us'),
561                self.sample_us)
562        if err is not None:
563            return err
564        err = write_file(os.path.join(self.interval_sysfs_dir(), 'aggr_us'),
565                self.aggr_us)
566        if err is not None:
567            return err
568        err = self.intervals_goal.stage()
569        if err is not None:
570            return err
571        err = write_file(os.path.join(self.interval_sysfs_dir(), 'update_us'),
572                self.update_us)
573        if err is not None:
574            return err
575
576        err = write_file(
577                os.path.join(self.nr_regions_range_sysfs_dir(), 'min'),
578                self.min_nr_regions)
579        if err is not None:
580            return err
581
582        err = write_file(
583                os.path.join(self.nr_regions_range_sysfs_dir(), 'max'),
584                self.max_nr_regions)
585        if err is not None:
586            return err
587
588class DamonCtx:
589    ops = None
590    monitoring_attrs = None
591    targets = None
592    schemes = None
593    kdamond = None
594    idx = None
595
596    def __init__(self, ops='paddr', monitoring_attrs=DamonAttrs(), targets=[],
597            schemes=[]):
598        self.ops = ops
599        self.monitoring_attrs = monitoring_attrs
600        self.monitoring_attrs.context = self
601
602        self.targets = targets
603        for idx, target in enumerate(self.targets):
604            target.idx = idx
605            target.context = self
606
607        self.schemes = schemes
608        for idx, scheme in enumerate(self.schemes):
609            scheme.idx = idx
610            scheme.context = self
611
612    def sysfs_dir(self):
613        return os.path.join(self.kdamond.sysfs_dir(), 'contexts',
614                '%d' % self.idx)
615
616    def stage(self):
617        err = write_file(
618                os.path.join(self.sysfs_dir(), 'operations'), self.ops)
619        if err is not None:
620            return err
621        err = self.monitoring_attrs.stage()
622        if err is not None:
623            return err
624
625        nr_targets_file = os.path.join(
626                self.sysfs_dir(), 'targets', 'nr_targets')
627        content, err = read_file(nr_targets_file)
628        if err is not None:
629            return err
630        if int(content) != len(self.targets):
631            err = write_file(nr_targets_file, '%d' % len(self.targets))
632            if err is not None:
633                return err
634        for target in self.targets:
635            err = target.stage()
636            if err is not None:
637                return err
638
639        nr_schemes_file = os.path.join(
640                self.sysfs_dir(), 'schemes', 'nr_schemes')
641        content, err = read_file(nr_schemes_file)
642        if err is not None:
643            return err
644        if int(content) != len(self.schemes):
645            err = write_file(nr_schemes_file, '%d' % len(self.schemes))
646            if err is not None:
647                return err
648        for scheme in self.schemes:
649            err = scheme.stage()
650            if err is not None:
651                return err
652        return None
653
654class Kdamond:
655    state = None
656    pid = None
657    contexts = None
658    idx = None      # index of this kdamond between siblings
659    kdamonds = None # parent
660
661    def __init__(self, contexts=[]):
662        self.contexts = contexts
663        for idx, context in enumerate(self.contexts):
664            context.idx = idx
665            context.kdamond = self
666
667    def sysfs_dir(self):
668        return os.path.join(self.kdamonds.sysfs_dir(), '%d' % self.idx)
669
670    def start(self):
671        nr_contexts_file = os.path.join(self.sysfs_dir(),
672                'contexts', 'nr_contexts')
673        content, err = read_file(nr_contexts_file)
674        if err is not None:
675            return err
676        if int(content) != len(self.contexts):
677            err = write_file(nr_contexts_file, '%d' % len(self.contexts))
678            if err is not None:
679                return err
680
681        for context in self.contexts:
682            err = context.stage()
683            if err is not None:
684                return err
685        err = write_file(os.path.join(self.sysfs_dir(), 'state'), 'on')
686        if err is not None:
687            return err
688        self.pid, err = read_file(os.path.join(self.sysfs_dir(), 'pid'))
689        return err
690
691    def stop(self):
692        err = write_file(os.path.join(self.sysfs_dir(), 'state'), 'off')
693        return err
694
695    def update_schemes_tried_regions(self):
696        err = write_file(os.path.join(self.sysfs_dir(), 'state'),
697                         'update_schemes_tried_regions')
698        if err is not None:
699            return err
700        for context in self.contexts:
701            for scheme in context.schemes:
702                tried_regions = []
703                tried_regions_dir = os.path.join(
704                        scheme.sysfs_dir(), 'tried_regions')
705                region_indices = []
706                for filename in os.listdir(
707                        os.path.join(scheme.sysfs_dir(), 'tried_regions')):
708                    tried_region_dir = os.path.join(tried_regions_dir, filename)
709                    if not os.path.isdir(tried_region_dir):
710                        continue
711                    region_indices.append(int(filename))
712                for region_idx in sorted(region_indices):
713                    tried_region_dir = os.path.join(tried_regions_dir,
714                                                    '%d' % region_idx)
715                    region_values = []
716                    for f in ['start', 'end', 'nr_accesses', 'age']:
717                        content, err = read_file(
718                                os.path.join(tried_region_dir, f))
719                        if err is not None:
720                            return err
721                        region_values.append(int(content))
722                    tried_regions.append(DamosTriedRegion(*region_values))
723                scheme.tried_regions = tried_regions
724
725    def update_schemes_tried_bytes(self):
726        err = write_file(os.path.join(self.sysfs_dir(), 'state'),
727                'update_schemes_tried_bytes')
728        if err is not None:
729            return err
730        for context in self.contexts:
731            for scheme in context.schemes:
732                content, err = read_file(os.path.join(scheme.sysfs_dir(),
733                    'tried_regions', 'total_bytes'))
734                if err is not None:
735                    return err
736                scheme.tried_bytes = int(content)
737
738    def update_schemes_stats(self):
739        err = write_file(os.path.join(self.sysfs_dir(), 'state'),
740                'update_schemes_stats')
741        if err is not None:
742            return err
743        for context in self.contexts:
744            for scheme in context.schemes:
745                stat_values = []
746                for stat in ['nr_tried', 'sz_tried', 'nr_applied',
747                             'sz_applied', 'qt_exceeds']:
748                    content, err = read_file(
749                            os.path.join(scheme.sysfs_dir(), 'stats', stat))
750                    if err is not None:
751                        return err
752                    stat_values.append(int(content))
753                scheme.stats = DamosStats(*stat_values)
754
755    def update_schemes_effective_quotas(self):
756        err = write_file(os.path.join(self.sysfs_dir(), 'state'),
757                         'update_schemes_effective_quotas')
758        if err is not None:
759            return err
760        for context in self.contexts:
761            for scheme in context.schemes:
762                for goal in scheme.quota.goals:
763                    content, err = read_file(
764                            os.path.join(scheme.quota.sysfs_dir(),
765                                         'effective_bytes'))
766                    if err is not None:
767                        return err
768                    goal.effective_bytes = int(content)
769        return None
770
771    def commit(self):
772        nr_contexts_file = os.path.join(self.sysfs_dir(),
773                'contexts', 'nr_contexts')
774        content, err = read_file(nr_contexts_file)
775        if err is not None:
776            return err
777        if int(content) != len(self.contexts):
778            err = write_file(nr_contexts_file, '%d' % len(self.contexts))
779            if err is not None:
780                return err
781
782        for context in self.contexts:
783            err = context.stage()
784            if err is not None:
785                return err
786        err = write_file(os.path.join(self.sysfs_dir(), 'state'), 'commit')
787        return err
788
789
790    def commit_schemes_quota_goals(self):
791        for context in self.contexts:
792            for scheme in context.schemes:
793                for goal in scheme.quota.goals:
794                    err = goal.stage()
795                    if err is not None:
796                        print('commit_schemes_quota_goals failed stagign: %s'%
797                              err)
798                        exit(1)
799        return write_file(os.path.join(self.sysfs_dir(), 'state'),
800                         'commit_schemes_quota_goals')
801
802class Kdamonds:
803    kdamonds = []
804
805    def __init__(self, kdamonds=[]):
806        self.kdamonds = kdamonds
807        for idx, kdamond in enumerate(self.kdamonds):
808            kdamond.idx = idx
809            kdamond.kdamonds = self
810
811    def sysfs_dir(self):
812        return os.path.join(sysfs_root, 'kdamonds')
813
814    def start(self):
815        err = write_file(os.path.join(self.sysfs_dir(),  'nr_kdamonds'),
816                '%s' % len(self.kdamonds))
817        if err is not None:
818            return err
819        for kdamond in self.kdamonds:
820            err = kdamond.start()
821            if err is not None:
822                return err
823        return None
824
825    def stop(self):
826        for kdamond in self.kdamonds:
827            err = kdamond.stop()
828            if err is not None:
829                return err
830        return None
831