Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The file only writes partial bytes and doesn't raise any errors #6005

Closed
WenyXu opened this issue Sep 13, 2023 · 3 comments
Closed

The file only writes partial bytes and doesn't raise any errors #6005

WenyXu opened this issue Sep 13, 2023 · 3 comments
Labels
A-tokio Area: The main tokio crate C-bug Category: This is a bug. M-fs Module: tokio/fs

Comments

@WenyXu
Copy link

WenyXu commented Sep 13, 2023

Version
v1.29.1

Platform
The output of uname -a (UNIX), or version and 32 or 64-bit (Windows)

Linux 6.2.0-25-generic #25-Ubuntu SMP PREEMPT_DYNAMIC x86_64 GNU/Linux

Description
Enter your issue details here.
One way to structure the description:

tokio::fs::File only writes partial bytes and doesn't raise any errors.

We designed some chaos tests, which simulate what problems will occur when the disk is full.

fallocate -l 512K disk.img 
mkfs disk.img 
mkdir ./td
sudo mount -o loop td.img ./td
chmod a+wr ./td

I tried this code:

#[tokio::test(flavor = "multi_thread")]
async fn tokio_file_write() {
    let root_dir = "/tmp/chaos/td/test";

    let mut f = tokio::fs::File::create(root_dir).await.unwrap();
    // XKB
    let data = [96u8; 1024 * 512];
    let l = f.write(&data.to_vec()).await.unwrap();
    assert_eq!(1024 * 512, l);
}
#[tokio::test(flavor = "multi_thread")]
async fn tokio_file_write() {
    let root_dir = "/tmp/chaos/td/test";

    let mut f = tokio::fs::File::create(root_dir).await.unwrap();
    // XKB
    let data = [96u8; 1024 * 512];
    f.write_all(&data.to_vec()).await.unwrap();
}

I expected to see this happen:

I also tested with the std::fs::File, and it works as expected.

#[test]
fn std_file_write() {
    let root_dir = "/tmp/chaos/td/test";

    let mut f = std::fs::File::create(root_dir).unwrap();
    // XKB
    let data = [96u8; 1024 * 512];
    f.write_all(&data.to_vec()).unwrap();
}

Output:

called `Result::unwrap()` on an `Err` value: Os { code: 28, kind: StorageFull, message: "No space left on device" }
stack backtrace:
   0: rust_begin_unwind
             at /rustc/f3623871cfa0763c95ebd6ceafaa6dc2e44ca68f/library/std/src/panicking.rs:617:5

Instead, this happened:

The tokio::fs::File's writes only contain partial bytes and didn't raise any errors!

running 1 test
test tests::standalone_read_write::tokio_file_write ... ok
➜  td ls -lh  
total 448K
drwx------ 2 root root  16K Sep 13 08:28 lost+found
-rw-rw-r-- 1 weny weny 428K Sep 13 09:10 test
@WenyXu WenyXu added A-tokio Area: The main tokio crate C-bug Category: This is a bug. labels Sep 13, 2023
@Darksonn Darksonn added the M-fs Module: tokio/fs label Sep 13, 2023
@Darksonn
Copy link
Contributor

Tokio's file must be flushed.

@WenyXu
Copy link
Author

WenyXu commented Sep 13, 2023

Tokio's file must be flushed.

Cool,flush throws a NoSpace error. But why after calling the sync_all didn't throw any errors?
Are there any differences between the sync_all and flush?

@Darksonn
Copy link
Contributor

Yes, sync_all and flush are completely different. The flush method ensures that things not yet written by Rust are written to the OS. The sync_all method ensures that everything written to the OS is flushed to disk.

Arguably the sync_all method should do a flush first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-tokio Area: The main tokio crate C-bug Category: This is a bug. M-fs Module: tokio/fs
Projects
None yet
Development

No branches or pull requests

2 participants