@@ -15,9 +15,11 @@ use std::path::PathBuf;
1515
1616use crate :: error:: ErrorKind :: * ;
1717use crate :: error:: * ;
18+ use crate :: { parse_max_value, read_i64_from} ;
1819
1920use crate :: {
20- ControllIdentifier , ControllerInternal , Controllers , CpuResources , Resources , Subsystem ,
21+ ControllIdentifier , ControllerInternal , Controllers , CpuResources , MaxValue , Resources ,
22+ Subsystem ,
2123} ;
2224
2325/// A controller that allows controlling the `cpu` subsystem of a Cgroup.
@@ -41,6 +43,13 @@ pub struct Cpu {
4143 pub stat : String ,
4244}
4345
46+ /// The current state of the control group and its processes.
47+ #[ derive( Debug ) ]
48+ struct CFSQuotaAndPeriod {
49+ quota : MaxValue ,
50+ period : u64 ,
51+ }
52+
4453impl ControllerInternal for CpuController {
4554 fn control_type ( & self ) -> Controllers {
4655 Controllers :: Cpu
@@ -77,8 +86,8 @@ impl ControllerInternal for CpuController {
7786 return Err ( Error :: new ( ErrorKind :: Other ) ) ;
7887 }
7988
80- let _ = self . set_cfs_quota ( res. quota as u64 ) ;
81- if self . cfs_quota ( ) ? != res. quota as u64 {
89+ let _ = self . set_cfs_quota ( res. quota ) ;
90+ if self . cfs_quota ( ) ? != res. quota {
8291 return Err ( Error :: new ( ErrorKind :: Other ) ) ;
8392 }
8493
@@ -182,6 +191,9 @@ impl CpuController {
182191 /// Specify a period (when using the CFS scheduler) of time in microseconds for how often this
183192 /// control group's access to the CPU should be reallocated.
184193 pub fn set_cfs_period ( & self , us : u64 ) -> Result < ( ) > {
194+ if self . v2 {
195+ return self . set_cfs_quota_and_period ( None , Some ( us) ) ;
196+ }
185197 self . open_path ( "cpu.cfs_period_us" , true )
186198 . and_then ( |mut file| {
187199 file. write_all ( us. to_string ( ) . as_ref ( ) )
@@ -192,13 +204,22 @@ impl CpuController {
192204 /// Retrieve the period of time of how often this cgroup's access to the CPU should be
193205 /// reallocated in microseconds.
194206 pub fn cfs_period ( & self ) -> Result < u64 > {
207+ if self . v2 {
208+ let current_value = self
209+ . open_path ( "cpu.max" , false )
210+ . and_then ( parse_cfs_quota_and_period) ?;
211+ return Ok ( current_value. period ) ;
212+ }
195213 self . open_path ( "cpu.cfs_period_us" , false )
196214 . and_then ( read_u64_from)
197215 }
198216
199217 /// Specify a quota (when using the CFS scheduler) of time in microseconds for which all tasks
200218 /// in this control group can run during one period (see: `set_cfs_period()`).
201- pub fn set_cfs_quota ( & self , us : u64 ) -> Result < ( ) > {
219+ pub fn set_cfs_quota ( & self , us : i64 ) -> Result < ( ) > {
220+ if self . v2 {
221+ return self . set_cfs_quota_and_period ( Some ( us) , None ) ;
222+ }
202223 self . open_path ( "cpu.cfs_quota_us" , true )
203224 . and_then ( |mut file| {
204225 file. write_all ( us. to_string ( ) . as_ref ( ) )
@@ -208,28 +229,59 @@ impl CpuController {
208229
209230 /// Retrieve the quota of time for which all tasks in this cgroup can run during one period, in
210231 /// microseconds.
211- pub fn cfs_quota ( & self ) -> Result < u64 > {
232+ pub fn cfs_quota ( & self ) -> Result < i64 > {
233+ if self . v2 {
234+ let current_value = self
235+ . open_path ( "cpu.max" , false )
236+ . and_then ( parse_cfs_quota_and_period) ?;
237+ return Ok ( current_value. quota . to_i64 ( ) ) ;
238+ }
239+
212240 self . open_path ( "cpu.cfs_quota_us" , false )
213- . and_then ( read_u64_from )
241+ . and_then ( read_i64_from )
214242 }
215243
216- pub fn set_cfs_quota_and_period ( & self , quota : u64 , period : u64 ) -> Result < ( ) > {
244+ pub fn set_cfs_quota_and_period ( & self , quota : Option < i64 > , period : Option < u64 > ) -> Result < ( ) > {
217245 if !self . v2 {
218- self . set_cfs_quota ( quota) ?;
219- return self . set_cfs_period ( period) ;
220- }
221- let mut line = "max" . to_string ( ) ;
222- if quota > 0 {
223- line = quota. to_string ( ) ;
246+ if let Some ( q) = quota {
247+ self . set_cfs_quota ( q) ?;
248+ }
249+ if let Some ( p) = period {
250+ self . set_cfs_period ( p) ?;
251+ }
252+ return Ok ( ( ) ) ;
224253 }
225254
226- let mut p = period;
227- if period == 0 {
228- // This default value is documented in
229- // https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html
230- p = 100000
231- }
232- line = format ! ( "{} {}" , line, p) ;
255+ // https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html
256+
257+ // cpu.max
258+ // A read-write two value file which exists on non-root cgroups. The default is “max 100000”.
259+ // The maximum bandwidth limit. It’s in the following format:
260+ // $MAX $PERIOD
261+ // which indicates that the group may consume upto $MAX in each $PERIOD duration.
262+ // “max” for $MAX indicates no limit. If only one number is written, $MAX is updated.
263+
264+ let current_value = self
265+ . open_path ( "cpu.max" , false )
266+ . and_then ( parse_cfs_quota_and_period) ?;
267+
268+ let new_quota = if let Some ( q) = quota {
269+ if q > 0 {
270+ q. to_string ( )
271+ } else {
272+ "max" . to_string ( )
273+ }
274+ } else {
275+ current_value. quota . to_string ( )
276+ } ;
277+
278+ let new_period = if let Some ( p) = period {
279+ p. to_string ( )
280+ } else {
281+ current_value. period . to_string ( )
282+ } ;
283+
284+ let line = format ! ( "{} {}" , new_quota, new_period) ;
233285 self . open_path ( "cpu.max" , true ) . and_then ( |mut file| {
234286 file. write_all ( line. as_ref ( ) )
235287 . map_err ( |e| Error :: with_cause ( WriteFailed , e) )
@@ -252,3 +304,24 @@ impl CpuController {
252304 } )
253305 }
254306}
307+
308+ fn parse_cfs_quota_and_period ( mut file : File ) -> Result < CFSQuotaAndPeriod > {
309+ let mut content = String :: new ( ) ;
310+ file. read_to_string ( & mut content)
311+ . map_err ( |e| Error :: with_cause ( ReadFailed , e) ) ?;
312+
313+ let fields = content. trim ( ) . split ( ' ' ) . collect :: < Vec < & str > > ( ) ;
314+ if fields. len ( ) != 2 {
315+ return Err ( Error :: from_string ( format ! ( "invaild format: {}" , content) ) ) ;
316+ }
317+
318+ let quota = parse_max_value ( & fields[ 0 ] . to_string ( ) ) ?;
319+ let period = fields[ 1 ]
320+ . parse :: < u64 > ( )
321+ . map_err ( |e| Error :: with_cause ( ParseError , e) ) ?;
322+
323+ Ok ( CFSQuotaAndPeriod {
324+ quota : quota,
325+ period : period,
326+ } )
327+ }
0 commit comments