fn inherit_from_parent_aux(
    path: &mut PathBuf,
    file_name: &str,
    retry_one_level_up: bool,
) -> Result<()> {
    // The function with_file_name() replaces the last component of a path with the given name.
    let parent_file = path.with_file_name(file_name);

    let mut line = readln_special(&parent_file)?;
    if line.is_empty() {
        if retry_one_level_up {
            // We have to borrow "parent" from "parent_file" as opposed to "path", because then
            // we wouldn't be able to mutably borrow path at the end of this function (at least not
            // according to how the Rust borrow checker operates right now :-s)
            let parent = parent_file
                .parent()
                .ok_or_else(|| Error::MissingParent(parent_file.clone()))?;

            // Trying to avoid the race condition described above. We don't care about the result,
            // because we check once more if line.is_empty() after the end of this block.
            let _ = inherit_from_parent_aux(&mut parent.to_path_buf(), file_name, false);
            line = readln_special(&parent_file)?;
        }

        if line.is_empty() {
            return Err(Error::CgroupInheritFromParent(
                path.to_path_buf(),
                file_name.to_string(),
            ));
        }
    }

    path.push(file_name);
    writeln_special(&path, &line)?;
    path.pop();

    Ok(())
}
// There is also a potential race condition mentioned below. Here is what it refers to: let's say we
// start multiple jailer processes, and one of them calls
// inherit_from_parent_aux(/A/firecracker/id1, file, true), and hits case number 3) from the list
// above, thus recursively calling inherit_from_parent_aux(/A/firecracker, file, false). It's
// entirely possible there was another process in the exact same situations, and that process
// gets to write something to /A/firecracker/file first. In this case, the recursive call made by
// the first process to inherit_from_parent_aux(/A/firecracker, file, false) may fail when writing
// to /A/firecracker/file, but we can still continue, because step 4) only cares about the file
// no longer being empty, regardless of who actually got to populated its contents.
There is also a potential race condition mentioned below.
There is also a potential race condition mentioned below .
fn inherit_from_parent_aux(
    path: &mut PathBuf,
    file_name: &str,
    retry_one_level_up: bool,
) -> Result<()> {
    // The function with_file_name() replaces the last component of a path with the given name.
    let parent_file = path.with_file_name(file_name);
    let mut line = readln_special(&parent_file)?;
    if line.is_empty() {
        if retry_one_level_up {
            // We have to borrow "parent" from "parent_file" as opposed to "path", because then
            // we wouldn't be able to mutably borrow path at the end of this function (at least not
            // according to how the Rust borrow checker operates right now :-s)
            let parent = parent_file
                .parent()
                .ok_or_else(|| Error::MissingParent(parent_file.clone()))?;
            // Trying to avoid the race condition described above. We don't care about the result,
            // because we check once more if line.is_empty() after the end of this block.
            let _ = inherit_from_parent_aux(&mut parent.to_path_buf(), file_name, false);
            line = readln_special(&parent_file)?;
        }
        if line.is_empty() {
            return Err(Error::CgroupInheritFromParent(
                path.to_path_buf(),
                file_name.to_string(),
            ));
        }
    }
    path.push(file_name);
    writeln_special(&path, &line)?;
    path.pop();
    Ok(())
}
fn inherit_from_parent_aux ( path : & mut PathBuf , file_name : & str , retry_one_level_up : bool , ) -> Result < ( ) > { // The function with_file_name() replaces the last component of a path with the given name. let parent_file = path . with_file_name ( file_name ) ; let mut line = readln_special ( & parent_file ) ? ; if line . is_empty ( ) { if retry_one_level_up { // We have to borrow "parent" from "parent_file" as opposed to "path", because then // we wouldn't be able to mutably borrow path at the end of this function (at least not // according to how the Rust borrow checker operates right now :-s) let parent = parent_file . parent ( ) . ok_or_else ( | | Error :: MissingParent ( parent_file . clone ( ) ) ) ? ; // Trying to avoid the race condition described above. We don't care about the result, // because we check once more if line.is_empty() after the end of this block. let _ = inherit_from_parent_aux ( & mut parent . to_path_buf ( ) , file_name , false ) ; line = readln_special ( & parent_file ) ? ; } if line . is_empty ( ) { return Err ( Error :: CgroupInheritFromParent ( path . to_path_buf ( ) , file_name . to_string ( ) , ) ) ; } } path . push ( file_name ) ; writeln_special ( & path , & line ) ? ; path . pop ( ) ; Ok ( ( ) ) }
There is also a potential race condition mentioned below.
There is also a potential race condition mentioned below .
path
&mut PathBuf
file_name
&str
retry_one_level_up
bool
path
&mut PathBuf
file_name
&str
retry_one_level_up
bool