(path: &str, data: &TdxReportData)
| 401 | } |
| 402 | |
| 403 | fn write_inblob_with_retry(path: &str, data: &TdxReportData) -> Result<()> { |
| 404 | const RETRY_WAIT_MS: u64 = 10000; // 10 seconds |
| 405 | const MAX_RETRIES: usize = 3; |
| 406 | |
| 407 | let mut last_err = None; |
| 408 | for _ in 0..MAX_RETRIES { |
| 409 | let mut file = match OpenOptions::new().write(true).open(path) { |
| 410 | Ok(f) => f, |
| 411 | Err(e) => { |
| 412 | last_err = Some(e); |
| 413 | continue; |
| 414 | } |
| 415 | }; |
| 416 | |
| 417 | match file.write_all(data) { |
| 418 | Ok(()) => return Ok(()), |
| 419 | Err(e) => { |
| 420 | if e.raw_os_error() == Some(libc::EBUSY) { |
| 421 | thread::sleep(Duration::from_millis(RETRY_WAIT_MS)); |
| 422 | last_err = Some(e); |
| 423 | continue; |
| 424 | } |
| 425 | return Err(TdxAttestError::Unexpected(format!("write {path}: {e}"))); |
| 426 | } |
| 427 | } |
| 428 | } |
| 429 | |
| 430 | match last_err { |
| 431 | Some(e) if e.raw_os_error() == Some(libc::EBUSY) => Err(TdxAttestError::Busy), |
| 432 | Some(e) => Err(TdxAttestError::Unexpected(format!("write {path}: {e}"))), |
| 433 | None => Err(TdxAttestError::Unexpected("unknown error".to_string())), |
| 434 | } |
| 435 | } |
| 436 | |
| 437 | fn wait_for_generation_change(path: &str, current: i64) -> Result<i64> { |
| 438 | let deadline = Instant::now() + Duration::from_secs(CONFIGFS_GEN_WAIT_TIMEOUT_SECS); |
no test coverage detected