|
| 1 | +use rustix::fd::AsFd; |
| 2 | +use rustix::ffi as c; |
| 3 | +use rustix::io::Errno; |
| 4 | +use rustix::ioctl::opcode; |
| 5 | +use rustix::{io, ioctl}; |
| 6 | + |
| 7 | +use crate::util::SignalTerminationGuard; |
| 8 | + |
| 9 | +fn ioctl_fifreeze<Fd: AsFd>(fd: Fd) -> io::Result<()> { |
| 10 | + // SAFETY: `FIFREEZE` is a no-argument opcode. |
| 11 | + // `FIFREEZE` is defined as `_IOWR('X', 119, int)`. |
| 12 | + unsafe { |
| 13 | + let ctl = ioctl::NoArg::<{ opcode::read_write::<c::c_int>(b'X', 119) }>::new(); |
| 14 | + ioctl::ioctl(fd, ctl) |
| 15 | + } |
| 16 | +} |
| 17 | + |
| 18 | +fn ioctl_fithaw<Fd: AsFd>(fd: Fd) -> io::Result<()> { |
| 19 | + // SAFETY: `FITHAW` is a no-argument opcode. |
| 20 | + // `FITHAW` is defined as `_IOWR('X', 120, int)`. |
| 21 | + unsafe { |
| 22 | + let ctl = ioctl::NoArg::<{ opcode::read_write::<c::c_int>(b'X', 120) }>::new(); |
| 23 | + ioctl::ioctl(fd, ctl) |
| 24 | + } |
| 25 | +} |
| 26 | + |
| 27 | +/// syncfs() doesn't flush the journal on XFS, |
| 28 | +/// and since GRUB2 can't read the XFS journal, the system |
| 29 | +/// could fail to boot. |
| 30 | +/// |
| 31 | +/// http://marc.info/?l=linux-fsdevel&m=149520244919284&w=2 |
| 32 | +/// https://github.com/ostreedev/ostree/pull/1049 |
| 33 | +/// |
| 34 | +/// This function always call syncfs() first, then calls |
| 35 | +/// `ioctl(FIFREEZE)` and `ioctl(FITHAW)`, ignoring `EOPNOTSUPP` and `EPERM` |
| 36 | +pub(crate) fn fsfreeze_thaw_cycle<Fd: AsFd>(fd: Fd) -> anyhow::Result<()> { |
| 37 | + rustix::fs::syncfs(&fd)?; |
| 38 | + |
| 39 | + let _guard = SignalTerminationGuard::new()?; |
| 40 | + |
| 41 | + let freeze = ioctl_fifreeze(&fd); |
| 42 | + match freeze { |
| 43 | + // Ignore permissions errors (tests) |
| 44 | + Err(Errno::PERM) => Ok(()), |
| 45 | + // Ignore unsupported FS |
| 46 | + Err(Errno::NOTSUP) => Ok(()), |
| 47 | + Ok(()) => Ok(ioctl_fithaw(fd)?), |
| 48 | + _ => Ok(freeze?), |
| 49 | + } |
| 50 | +} |
0 commit comments