@@ -1060,16 +1060,28 @@ impl<S: BitmapSlice + Send + Sync> PassthroughFs<S> {
1060
1060
}
1061
1061
}
1062
1062
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.
1066
1063
fn get_writeback_open_flags ( & self , flags : i32 ) -> i32 {
1067
1064
let mut new_flags = flags;
1068
1065
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.
1069
1070
if writeback && flags & libc:: O_ACCMODE == libc:: O_WRONLY {
1070
1071
new_flags &= !libc:: O_ACCMODE ;
1071
1072
new_flags |= libc:: O_RDWR ;
1072
1073
}
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
+
1073
1085
new_flags
1074
1086
}
1075
1087
}
@@ -1356,7 +1368,8 @@ mod tests {
1356
1368
#[ test]
1357
1369
fn test_get_writeback_open_flags ( ) {
1358
1370
// 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.
1360
1373
let mut fs = prepare_passthroughfs ( ) ;
1361
1374
fs. writeback = AtomicBool :: new ( true ) ;
1362
1375
fs. no_open = AtomicBool :: new ( false ) ;
@@ -1373,6 +1386,15 @@ mod tests {
1373
1386
let flags = libc:: O_WRONLY ;
1374
1387
assert_eq ! ( fs. get_writeback_open_flags( flags) , libc:: O_RDWR ) ;
1375
1388
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
+
1376
1398
// prepare a fs with writeback cache disabled, open flags should not change
1377
1399
let mut fs = prepare_passthroughfs ( ) ;
1378
1400
fs. writeback = AtomicBool :: new ( false ) ;
@@ -1389,6 +1411,24 @@ mod tests {
1389
1411
1390
1412
let flags = libc:: O_WRONLY ;
1391
1413
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
+ ) ;
1392
1432
}
1393
1433
1394
1434
#[ test]
0 commit comments