Skip to contentSkip to conversation

Write is not atomic?

DISCUSSION Juliusz Chroboczek 5 participants 8 messages Oct 15, 2012 – Oct 16, 2012

lore
Share & tools
lore
#0 lore raw

Hi,

The Linux manual page for write(2) says:

The adjustment of the file offset and the write operation are performed as an atomic step.

This is apparently an extension to POSIX, which says

This volume of IEEE Std 1003.1-2001 does not specify behavior of concurrent writes to a file from multiple processes. Applications should use some form of concurrency control.

The following fragment of code

    int fd;
    fd = open("exemple", O_CREAT | O_WRONLY | O_TRUNC, 0666);
    fork();
    write(fd, "Ouille", 6);
    close(fd);

produces "OuilleOuille", as expected, on ext4 on two machines running Linux 3.2 AMD64. However, over XFS on an old Pentium III at 500 MHz running 2.6.32, it produces just "Ouille" roughly once in three times.

Sorry for not being able to give more test cases, but I cannot easily change either the filesystem or the kernel on the Pentium server.

-- Juliusz Chroboczek

P.S. I'll appreciate being copied with any replies.

#1 lore raw
Quoted 13 lines · Juliusz Chroboczek

Hi,

The Linux manual page for write(2) says:

The adjustment of the file offset and the write operation are performed as an atomic step.

This is apparently an extension to POSIX, which says

This volume of IEEE Std 1003.1-2001 does not specify behavior of concurrent writes to a file from multiple processes. Applications should use some form of concurrency control.

Quoted 6 lines

The following fragment of code

    int fd;
    fd = open("exemple", O_CREAT | O_WRONLY | O_TRUNC, 0666);
    fork();
    write(fd, "Ouille", 6);

You don't check return code here, does write succeed at all?

Quoted 5 lines
    close(fd);

produces "OuilleOuille", as expected, on ext4 on two machines running Linux 3.2 AMD64. However, over XFS on an old Pentium III at 500 MHz running 2.6.32, it produces just "Ouille" roughly once in three times.

Does it ever produce e.g. OuOuilleille (as this is what atomicity is about here)?

Signature · 2 lines
Thanks.
-- Max
#2 lore raw
Quoted 1 line

You don't check return code here, does write succeed at all?

Yes, both writes return 6.

Quoted 1 line

Does it ever produce e.g. OuOuilleille

No.

Quoted 1 line

(as this is what atomicity is about here)?

I was referring to the claim that under Linux writing and adjusting the file offset are performed as an atomic step, not to the atomicity of the write operation itself.

-- Juliusz

#3 lore raw
In reply to Juliusz Chroboczek
Quoted 6 lines · Juliusz Chroboczek

Hi,

The Linux manual page for write(2) says:

The adjustment of the file offset and the write operation are performed as an atomic step.

That's wrong. The file offset update is not synchronised at all with the write, and for a shared fd the update will race.

Quoted 5 lines

This is apparently an extension to POSIX, which says

This volume of IEEE Std 1003.1-2001 does not specify behavior of concurrent writes to a file from multiple processes. Applications should use some form of concurrency control.

This is how Linux behaves.

Quoted 11 lines

The following fragment of code

    int fd;
    fd = open("exemple", O_CREAT | O_WRONLY | O_TRUNC, 0666);
    fork();
    write(fd, "Ouille", 6);
    close(fd);

produces "OuilleOuille", as expected, on ext4 on two machines running Linux 3.2 AMD64. However, over XFS on an old Pentium III at 500 MHz running 2.6.32, it produces just "Ouille" roughly once in three times.

ext4, on 3.6:

$ for i in `seq 0 10000`; do ./a.out ; cat /mnt/scratch/foo ; echo ; done | sort |uniq -c
     39 Ouille
   9962 OuilleOuille
$

XFS, on the same kernel, hardware and block device:

$ for i in `seq 0 10000`; do ./a.out ; cat /mnt/scratch/foo ; echo ; done | sort |uniq -c
     40 Ouille
   9961 OuilleOuille
$

So both filesystems behave according to the POSIX definition of concurrent writes....

Cheers,

Dave.

Signature · 2 lines
Dave Chinner
[email protected]
#4 lore raw
Quoted 10 lines · Dave Chinner
Quoted 6 lines · Juliusz Chroboczek

Hi,

The Linux manual page for write(2) says:

The adjustment of the file offset and the write operation are performed as an atomic step.

That's wrong. The file offset update is not synchronised at all with the write, and for a shared fd the update will race.

That's what O_APPEND or pread/pwrite are for.

Quoted 15 lines
Quoted 5 lines

This is apparently an extension to POSIX, which says

This volume of IEEE Std 1003.1-2001 does not specify behavior of concurrent writes to a file from multiple processes. Applications should use some form of concurrency control.

This is how Linux behaves.

Quoted 7 lines

The following fragment of code

    int fd;
    fd = open("exemple", O_CREAT | O_WRONLY | O_TRUNC, 0666);
    fork();
    write(fd, "Ouille", 6);
    close(fd);

can be replaced with:

        int fd;
        fd = open("exemple", O_CREAT | O_WRONLY | O_TRUNC | O_APPEND, 0666);
        fork();
        write(fd, "Ouille", 6);
        close(fd);

or:

        int fd;
    fd = open("exemple", O_CREAT | O_WRONLY | O_TRUNC, 0666);
    pid_t pid = fork();
    pwrite(fd, "Ouille", 6, strlen("Ouille")*(pid == 0));
    close(fd);

(both code fragments untested)

Phil.

#5 lore raw
Quoted 10 lines · Philippe Troin
Quoted 8 lines · Dave Chinner
Quoted 7 lines · Juliusz Chroboczek

The following fragment of code

    int fd;
    fd = open("exemple", O_CREAT | O_WRONLY | O_TRUNC, 0666);
    fork();
    write(fd, "Ouille", 6);
    close(fd);
Quoted 7 lines

can be replaced with:

        int fd;
        fd = open("exemple", O_CREAT | O_WRONLY | O_TRUNC | O_APPEND, 0666);
        fork();
        write(fd, "Ouille", 6);
        close(fd);

Fails the same way as the original. I guess O_APPEND doesn't work this way for writes to the shared file descriptor.

Signature · 2 lines
Thanks.
-- Max
#6 lore raw
In reply to Juliusz Chroboczek

Hello,

Quoted 4 lines · Juliusz Chroboczek

The Linux manual page for write(2) says:

The adjustment of the file offset and the write operation are performed as an atomic step.

This seems out of context.

Over here write(2) reads:

If the file was open(2)ed with O_APPEND, the file offset is first set to the end of the file before writing. The adjustment of the file offset and the write operation are performed as an atomic step.

Sounds different, doesn't it?

Hth,
Jochen.

#7 lore raw
Quoted 8 lines

This seems out of context.

If the file was open(2)ed with O_APPEND, the file offset is first set to the end of the file before writing. The adjustment of the file offset and the write operation are performed as an atomic step.

Sounds different, doesn't it?

Yes, it does -- thanks for the clarification. (And thanks to Dave for the interesting tests.)

Sorry for the confusion,

-- Juliusz