Skip to main content

starnix_uapi/
mount_flags.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::uapi;
6use atomic_bitflags::atomic_bitflags;
7
8atomic_bitflags! {
9    #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
10    pub struct MountFlags: u32 {
11        // per-mountpoint flags
12        const RDONLY = uapi::MS_RDONLY;
13        const NOEXEC = uapi::MS_NOEXEC;
14        const NOSUID = uapi::MS_NOSUID;
15        const NODEV = uapi::MS_NODEV;
16        const NOATIME = uapi::MS_NOATIME;
17        const NODIRATIME = uapi::MS_NODIRATIME;
18        const RELATIME = uapi::MS_RELATIME;
19        const STRICTATIME = uapi::MS_STRICTATIME;
20
21        // per-superblock flags
22        const SILENT = uapi::MS_SILENT;
23        const LAZYTIME = uapi::MS_LAZYTIME;
24        const SYNCHRONOUS = uapi::MS_SYNCHRONOUS;
25        const DIRSYNC = uapi::MS_DIRSYNC;
26        const MANDLOCK = uapi::MS_MANDLOCK;
27
28        // mount() control flags
29        const REMOUNT = uapi::MS_REMOUNT;
30        const BIND = uapi::MS_BIND;
31        const MOVE = uapi::MS_MOVE;
32        const REC = uapi::MS_REC;
33        const DOWNSTREAM = uapi::MS_SLAVE;
34        const SHARED = uapi::MS_SHARED;
35        const PRIVATE = uapi::MS_PRIVATE;
36
37        /// Flags that change be changed with REMOUNT.
38        ///
39        /// MS_DIRSYNC and MS_SILENT cannot be changed with REMOUNT.
40        const CHANGEABLE_WITH_REMOUNT = MountpointFlags::all().bits() |
41            Self::MANDLOCK.bits() | Self::LAZYTIME.bits() | Self::SYNCHRONOUS.bits();
42    }
43}
44
45atomic_bitflags! {
46    /// Subset of `MountFlags` that allow the behaviours of different mountpoints to the same
47    /// underlying `FileSystem` to be independently configured.
48    /// Note that
49    #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
50    pub struct MountpointFlags: u32 {
51        // Flags stored for each mountpoint to configure its behaviour.
52        const RDONLY = MountFlags::RDONLY.bits();
53        const NOEXEC = MountFlags::NOEXEC.bits();
54        const NOSUID = MountFlags::NOSUID.bits();
55        const NODEV = MountFlags::NODEV.bits();
56        const NOATIME = MountFlags::NOATIME.bits();
57        const NODIRATIME = MountFlags::NODIRATIME.bits();
58        const RELATIME = MountFlags::RELATIME.bits();
59
60        const STORED_ON_MOUNT = Self::RDONLY.bits() | Self::NOEXEC.bits() | Self::NOSUID.bits() |
61            Self::NODEV.bits() | Self::NOATIME.bits() | Self::NODIRATIME.bits() | Self::RELATIME.bits();
62
63        // Flags affecting the behaviour of a single operation on a mountpoint.
64        const STRICTATIME = MountFlags::STRICTATIME.bits();
65        const REC = MountFlags::REC.bits();
66
67        /// Flags used to control how file access times are managed. Note that STRICTATIME is only
68        /// used by callers to specify that all other bits should be cleared; it is never stored.
69        const ATIME_MODE_FLAGS = Self::NOATIME.bits() | Self::RELATIME.bits() |Self::STRICTATIME.bits();
70        const ATIME_FLAGS = Self::ATIME_MODE_FLAGS.bits() | Self::NODIRATIME.bits();
71    }
72}
73
74impl MountpointFlags {
75    /// Ensures that `self` has an access-time flag set, copying the flag value from `existing` if
76    /// no flag is currently set.
77    /// This is used both to apply the kernel default `MS_RELATIME` if no other access-time flag is
78    /// passed to `mount()`, and to preserve existing access-time flags when re-mounting, unless the
79    /// `MS_STRICTATIME` flag is explicitly passed.
80    pub fn default_atime_from(&mut self, existing: MountpointFlags) {
81        if !self.intersects(Self::ATIME_FLAGS) {
82            // If no `ATIME_FLAGS` are set at all, preserve the `existing` flags.
83            *self |= existing & Self::ATIME_FLAGS;
84        } else if !self.intersects(Self::ATIME_MODE_FLAGS) {
85            // If the caller did not set any `ATIME_MODE_FLAGS` then default to the `RELATIME` mode.
86            *self |= Self::RELATIME;
87        }
88    }
89}
90
91impl From<MountpointFlags> for MountFlags {
92    fn from(flags: MountpointFlags) -> Self {
93        // MountpointFlags is defined using only bits that are valid for MountFlags.
94        Self::from_bits_retain(flags.bits())
95    }
96}
97
98atomic_bitflags! {
99    /// Subset of `MountFlags` that affect `FileSystem` behaviour.
100    #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
101    pub struct FileSystemFlags: u32 {
102        const RDONLY = MountFlags::RDONLY.bits();
103        const DIRSYNC = MountFlags::DIRSYNC.bits();
104        const LAZYTIME = MountFlags::LAZYTIME.bits();
105        const MANDLOCK = MountFlags::MANDLOCK.bits();
106        const SILENT = MountFlags::SILENT.bits();
107        const SYNCHRONOUS = MountFlags::SYNCHRONOUS.bits();
108    }
109}
110
111impl From<FileSystemFlags> for MountFlags {
112    fn from(flags: FileSystemFlags) -> Self {
113        // FileSystemFlags is defined using only bits that are valid for MountFlags.
114        Self::from_bits_retain(flags.bits())
115    }
116}
117
118impl MountFlags {
119    pub fn mountpoint_flags(&self) -> MountpointFlags {
120        MountpointFlags::from_bits_truncate(self.bits())
121    }
122
123    pub fn file_system_flags(&self) -> FileSystemFlags {
124        FileSystemFlags::from_bits_truncate(self.bits())
125    }
126}
127
128impl std::fmt::Display for MountpointFlags {
129    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130        MountFlags::from(*self).fmt(f)
131    }
132}
133
134impl std::fmt::Display for FileSystemFlags {
135    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
136        MountFlags::from(*self).fmt(f)
137    }
138}
139
140/// Display trait implementation for the subset of flags that are stored with mounts or superblocks.
141impl std::fmt::Display for MountFlags {
142    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143        // `RDONLY` is stored both with the mount and the superblock flags.
144        write!(f, "{}", if self.contains(Self::RDONLY) { "ro" } else { "rw" })?;
145
146        // Stored only in the mount flags.
147        if self.contains(Self::NOEXEC) {
148            write!(f, ",noexec")?;
149        }
150        if self.contains(Self::NOSUID) {
151            write!(f, ",nosuid")?;
152        }
153        if self.contains(Self::NODEV) {
154            write!(f, ",nodev")?
155        }
156        if self.contains(Self::NOATIME) {
157            write!(f, ",noatime")?;
158        }
159        if self.contains(Self::NODIRATIME) {
160            write!(f, ",nodiratime")?;
161        }
162        if self.contains(Self::RELATIME) {
163            write!(f, ",relatime")?;
164        }
165
166        // Stored only on the superblock.
167        if self.contains(Self::DIRSYNC) {
168            write!(f, ",dirsync")?;
169        }
170        if self.contains(Self::LAZYTIME) {
171            write!(f, ",lazytime")?;
172        }
173        if self.contains(Self::MANDLOCK) {
174            write!(f, ",mand")?;
175        }
176        // `SILENT` is not reported in proc-mounts nor proc-pid-mountinfo.
177        if self.contains(Self::SYNCHRONOUS) {
178            write!(f, ",sync")?;
179        }
180
181        Ok(())
182    }
183}