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