Skip to content

Commit ffc5b24

Browse files
eryugeyjiangliu
authored andcommitted
passthrough: open file with O_APPEND cleared when writeback is enabled
When writeback caching is enabled the kernel is responsible for handling `O_APPEND`. And we only did this in OPEN reuqest but not in CREATE request. Signed-off-by: Eryu Guan <[email protected]>
1 parent 1210ae6 commit ffc5b24

File tree

3 files changed

+46
-26
lines changed

3 files changed

+46
-26
lines changed

src/passthrough/async_io.rs

+1-11
Original file line numberDiff line numberDiff line change
@@ -148,17 +148,7 @@ impl<S: BitmapSlice + Send + Sync> PassthroughFs<S> {
148148
inode: Inode,
149149
mut flags: i32,
150150
) -> io::Result<File> {
151-
let mut new_flags = self.get_writeback_open_flags(flags);
152-
153-
// When writeback caching is enabled the kernel is responsible for handling `O_APPEND`.
154-
// However, this breaks atomicity as the file may have changed on disk, invalidating the
155-
// cached copy of the data in the kernel and the offset that the kernel thinks is the end of
156-
// the file. Just allow this for now as it is the user's responsibility to enable writeback
157-
// caching only for directories that are not shared. It also means that we need to clear the
158-
// `O_APPEND` flag.
159-
if self.writeback.load(Ordering::Relaxed) && flags & libc::O_APPEND != 0 {
160-
new_flags &= !libc::O_APPEND;
161-
}
151+
let new_flags = self.get_writeback_open_flags(flags);
162152
163153
let data = self.inode_map.get(inode)?;
164154
let file = data.async_get_file(&self.mount_fds).await?;

src/passthrough/mod.rs

+44-4
Original file line numberDiff line numberDiff line change
@@ -1060,16 +1060,28 @@ impl<S: BitmapSlice + Send + Sync> PassthroughFs<S> {
10601060
}
10611061
}
10621062

1063-
// When writeback caching is enabled, the kernel may send read requests even if the userspace
1064-
// program opened the file write-only. So we need to ensure that we have opened the file for
1065-
// reading as well as writing.
10661063
fn get_writeback_open_flags(&self, flags: i32) -> i32 {
10671064
let mut new_flags = flags;
10681065
let writeback = self.writeback.load(Ordering::Relaxed);
1066+
1067+
// When writeback caching is enabled, the kernel may send read requests even if the
1068+
// userspace program opened the file write-only. So we need to ensure that we have opened
1069+
// the file for reading as well as writing.
10691070
if writeback && flags & libc::O_ACCMODE == libc::O_WRONLY {
10701071
new_flags &= !libc::O_ACCMODE;
10711072
new_flags |= libc::O_RDWR;
10721073
}
1074+
1075+
// When writeback caching is enabled the kernel is responsible for handling `O_APPEND`.
1076+
// However, this breaks atomicity as the file may have changed on disk, invalidating the
1077+
// cached copy of the data in the kernel and the offset that the kernel thinks is the end of
1078+
// the file. Just allow this for now as it is the user's responsibility to enable writeback
1079+
// caching only for directories that are not shared. It also means that we need to clear the
1080+
// `O_APPEND` flag.
1081+
if writeback && flags & libc::O_APPEND != 0 {
1082+
new_flags &= !libc::O_APPEND;
1083+
}
1084+
10731085
new_flags
10741086
}
10751087
}
@@ -1356,7 +1368,8 @@ mod tests {
13561368
#[test]
13571369
fn test_get_writeback_open_flags() {
13581370
// prepare a fs with writeback cache and open being true, so O_WRONLY should be promoted to
1359-
// O_RDWR, as writeback may read files even if file being opened with write-only.
1371+
// O_RDWR, as writeback may read files even if file being opened with write-only. And
1372+
// O_APPEND should be cleared as well.
13601373
let mut fs = prepare_passthroughfs();
13611374
fs.writeback = AtomicBool::new(true);
13621375
fs.no_open = AtomicBool::new(false);
@@ -1373,6 +1386,15 @@ mod tests {
13731386
let flags = libc::O_WRONLY;
13741387
assert_eq!(fs.get_writeback_open_flags(flags), libc::O_RDWR);
13751388

1389+
let flags = libc::O_RDWR | libc::O_APPEND;
1390+
assert_eq!(fs.get_writeback_open_flags(flags), libc::O_RDWR);
1391+
1392+
let flags = libc::O_RDONLY | libc::O_APPEND;
1393+
assert_eq!(fs.get_writeback_open_flags(flags), libc::O_RDONLY);
1394+
1395+
let flags = libc::O_WRONLY | libc::O_APPEND;
1396+
assert_eq!(fs.get_writeback_open_flags(flags), libc::O_RDWR);
1397+
13761398
// prepare a fs with writeback cache disabled, open flags should not change
13771399
let mut fs = prepare_passthroughfs();
13781400
fs.writeback = AtomicBool::new(false);
@@ -1389,6 +1411,24 @@ mod tests {
13891411

13901412
let flags = libc::O_WRONLY;
13911413
assert_eq!(fs.get_writeback_open_flags(flags), libc::O_WRONLY);
1414+
1415+
let flags = libc::O_RDWR | libc::O_APPEND;
1416+
assert_eq!(
1417+
fs.get_writeback_open_flags(flags),
1418+
libc::O_RDWR | libc::O_APPEND
1419+
);
1420+
1421+
let flags = libc::O_RDONLY | libc::O_APPEND;
1422+
assert_eq!(
1423+
fs.get_writeback_open_flags(flags),
1424+
libc::O_RDONLY | libc::O_APPEND
1425+
);
1426+
1427+
let flags = libc::O_WRONLY | libc::O_APPEND;
1428+
assert_eq!(
1429+
fs.get_writeback_open_flags(flags),
1430+
libc::O_WRONLY | libc::O_APPEND
1431+
);
13921432
}
13931433

13941434
#[test]

src/passthrough/sync_io.rs

+1-11
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,7 @@ use crate::transport::FsCacheReqHandler;
2828

2929
impl<S: BitmapSlice + Send + Sync> PassthroughFs<S> {
3030
fn open_inode(&self, inode: Inode, flags: i32) -> io::Result<File> {
31-
let mut new_flags = self.get_writeback_open_flags(flags);
32-
33-
// When writeback caching is enabled the kernel is responsible for handling `O_APPEND`.
34-
// However, this breaks atomicity as the file may have changed on disk, invalidating the
35-
// cached copy of the data in the kernel and the offset that the kernel thinks is the end of
36-
// the file. Just allow this for now as it is the user's responsibility to enable writeback
37-
// caching only for directories that are not shared. It also means that we need to clear the
38-
// `O_APPEND` flag.
39-
if self.writeback.load(Ordering::Relaxed) && flags & libc::O_APPEND != 0 {
40-
new_flags &= !libc::O_APPEND;
41-
}
31+
let new_flags = self.get_writeback_open_flags(flags);
4232

4333
let data = self.inode_map.get(inode)?;
4434
let file = data.get_file(&self.mount_fds)?;

0 commit comments

Comments
 (0)