Skip to contentSkip to conversation

New: ext4 : DATA CORRUPTION read and write on same 4096 page range

Bug 50981 [email protected] 2 participants 13 messages Nov 25, 2012 – Nov 26, 2012

lore
Share & tools
lore
#0 lore raw

https://bugzilla.kernel.org/show_bug.cgi?id=50981

Summary: ext4 : DATA CORRUPTION read and write on same 4096
page range
Product: File System
Version: 2.5
Kernel Version: 2.6.32 Red Hat Enterprise Linux Workstation release
6.2 (Santiago)
Platform: All
OS/Version: Linux
Tree: Mainline
Status: NEW
Severity: high
Priority: P1
Component: ext4
AssignedTo: [email protected]
ReportedBy: [email protected]
Regression: No

Kernal version and Red hat

2.6.32 , Red Hat Enterprise Linux Workstation release 6.2 (Santiago)

I have one scientific application, that is running on ext4 , after three to fours days, I have started to seen that data is not correct.. then i tried to find simple reproducer for the same.

Pl. find the reproducer for the same with this issue is hitting easily.

Logs :

./sim ext4_write
creating the threads
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
reader thread has opened the file, fd : 4
reader..checking data integrity
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
reader..checking data integrity
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
reader..checking data integrity
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
reader..checking data integrity
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
reader..checking data integrity
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
reader..checking data integrity
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
reader..checking data integrity
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
reader..checking data integrity
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
reader..checking data integrity
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
reader..checking data integrity
writing B at offset 0...
writing A at offset 0...
reader..checking data integrity
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
reader..checking data integrity
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
reader..checking data integrity
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
reader..checking data integrity
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
reader..checking data integrity
writing A at offset 0...
reader.. corrupted data, at offset : 511
writing B at offset 0...

C program :
#include <stdio.h>
#include <fcntl.h>
#include <pthread.h>
#include <assert.h>

#include <errno.h>
       #include <sys/types.h>
       #include <sys/stat.h>
       #include <fcntl.h>
       #include <unistd.h>

#include <sys/mman.h>

pthread_t reader_id, writer_id;

char write_buf [4096] = {0,};
char read_buf[4096] = {0,};

char datafile[256] = {0,};
int stop_write = 0;

void * writer (void * arg)
{

        int fd = -1;
        int count = 0;
        /* this thread will open the file and write 4k data to it alternatively
         * of a different data set to the same offset
         */
        /* opening the file */
        assert((fd = open(datafile, O_CREAT|O_RDWR, 0777)) != -1);

        while (1) {

                if (stop_write)
                {
                        close(fd);
                        printf("write stopped\n");
                        return NULL;
                }
                if (count % 2 == 0)
                        memset(write_buf, 'A', sizeof(write_buf));
                else
                        memset(write_buf, 'B', sizeof(write_buf));


                assert(lseek(fd, 0, SEEK_SET) == 0);
                printf("writing %c at offset 0...\n", write_buf[0]);
                assert(write(fd, write_buf, 4096) == 4096);
                count ++;

        }
        //pthread_exit((void *)0);
        close(fd);
        return NULL;
}

void * reader(void * arg)
{

        int fd = -1;
        int count = 0;
        /* this thread will open the file and write 4k data to it alternatively
         * of a different data set to the same offset
         */
        /* opening the file */
        assert((fd = open(datafile, O_CREAT|O_RDWR, 0777)) != -1);
        printf("reader thread has opened the file, fd : %d\n", fd);
        while (1) {

                memset(read_buf, '\0', 4096);
                assert(lseek(fd, 0, SEEK_SET) == 0);
                assert(read(fd, read_buf, 4096) == 4096);
                count ++;
                printf("reader..checking data integrity\n");
                int i=0;
                for (i=0; i < 4095; i++)
                {
                        int prev_char = read_buf[i];
                        int next_char = read_buf[i+1];
                        if (prev_char != next_char)
                        {
                                printf("reader.. corrupted data, at offset :

%d\n", i);
stop_write = 1;
int output_fd = open("res.txt", O_CREAT|O_RDWR,
0777);

                                assert(write(output_fd, read_buf, 4096) ==
4096);
                                close(output_fd);
                                close(fd);
                                return NULL;
                        }
                }


        }
        //pthread_exit((void *)0);
        close(fd);
        return NULL;
}
int main (int argc, char *argv[])
{
        pthread_attr_t attr;
        void * arg = NULL;
        int *status;
        int err = 0;

        if (argc != 2) {
                printf("usage : ./reader_writer <file pathname>\n");
                exit(1);
        }


        memset(datafile, '\0', sizeof(datafile));
        strcpy(datafile, argv[1]);

        pthread_attr_init(&attr);
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

        /* create the reader and writer thread */
        printf("creating the threads\n");
        if ((err = pthread_create(&writer_id, &attr, writer, (void *)arg)) !=
0) {
                printf ("pthread_create failed err no :%d\n", err);
        }
        if ((err = pthread_create(&reader_id, &attr, reader, (void *)arg)) !=
0) {
                printf ("pthread_create failed err no :%d\n", err);
        }
        pthread_attr_destroy(&attr);

        /* Wait on the other threads */
        assert(pthread_join(writer_id, (void *)&status) == 0);
        assert(pthread_join(reader_id, (void *)&status) == 0);

        pthread_exit(NULL);
}

How to run
gcc program.c -o ext4_program -lpthread
./ext4_program ext4_write

Signature · 3 lines
Configure bugmail: https://bugzilla.kernel.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are watching the assignee of the bug.
#1 lore raw

[Bug 50981] ext4 : DATA CORRUPTION read and write on same 4096 page range

https://bugzilla.kernel.org/show_bug.cgi?id=50981

--- Comment #1 from Yongqiang Yang <[email protected]> 2012-11-26 05:55:56 --- which block size does the filesystem use, 1K or 4K?

Yongqiang

Quoted 310 lines · On Mon, Nov 26, 2012 at 12:31 AM, <[email protected]>wrote:

https://bugzilla.kernel.org/show_bug.cgi?id=50981

Summary: ext4 : DATA CORRUPTION read and write on same 4096
page range
Product: File System
Version: 2.5
Kernel Version: 2.6.32 Red Hat Enterprise Linux Workstation release
6.2 (Santiago)
Platform: All
OS/Version: Linux
Tree: Mainline
Status: NEW
Severity: high
Priority: P1
Component: ext4
AssignedTo: [email protected]
ReportedBy: [email protected]
Regression: No

Kernal version and Red hat

2.6.32 , Red Hat Enterprise Linux Workstation release 6.2 (Santiago)

I have one scientific application, that is running on ext4 , after three to fours days, I have started to seen that data is not correct.. then i tried to
find simple reproducer for the same.

Pl. find the reproducer for the same with this issue is hitting easily.

Logs :

./sim ext4_write
creating the threads
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
reader thread has opened the file, fd : 4
reader..checking data integrity
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
reader..checking data integrity
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
reader..checking data integrity
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
reader..checking data integrity
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
reader..checking data integrity
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
reader..checking data integrity
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
reader..checking data integrity
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
reader..checking data integrity
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
reader..checking data integrity
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
reader..checking data integrity
writing B at offset 0...
writing A at offset 0...
reader..checking data integrity
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
reader..checking data integrity
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
reader..checking data integrity
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
reader..checking data integrity
writing A at offset 0...
writing B at offset 0...
writing A at offset 0...
writing B at offset 0...
reader..checking data integrity
writing A at offset 0...
reader.. corrupted data, at offset : 511
writing B at offset 0...

C program :
#include <stdio.h>
#include <fcntl.h>
#include <pthread.h>
#include <assert.h>

#include <errno.h>
       #include <sys/types.h>
       #include <sys/stat.h>
       #include <fcntl.h>
       #include <unistd.h>

#include <sys/mman.h>

pthread_t reader_id, writer_id;

char write_buf [4096] = {0,};
char read_buf[4096] = {0,};

char datafile[256] = {0,};
int stop_write = 0;

void * writer (void * arg)
{

        int fd = -1;
        int count = 0;
        /* this thread will open the file and write 4k data to it
alternatively
         * of a different data set to the same offset
         */
        /* opening the file */
        assert((fd = open(datafile, O_CREAT|O_RDWR, 0777)) != -1);

        while (1) {

                if (stop_write)
                {
                        close(fd);
                        printf("write stopped\n");
                        return NULL;
                }
                if (count % 2 == 0)
                        memset(write_buf, 'A', sizeof(write_buf));
                else
                        memset(write_buf, 'B', sizeof(write_buf));


                assert(lseek(fd, 0, SEEK_SET) == 0);
                printf("writing %c at offset 0...\n", write_buf[0]);
                assert(write(fd, write_buf, 4096) == 4096);
                count ++;

        }
        //pthread_exit((void *)0);
        close(fd);
        return NULL;
}

void * reader(void * arg)
{

        int fd = -1;
        int count = 0;
        /* this thread will open the file and write 4k data to it
alternatively
         * of a different data set to the same offset
         */
        /* opening the file */
        assert((fd = open(datafile, O_CREAT|O_RDWR, 0777)) != -1);
        printf("reader thread has opened the file, fd : %d\n", fd);
        while (1) {

                memset(read_buf, '\0', 4096);
                assert(lseek(fd, 0, SEEK_SET) == 0);
                assert(read(fd, read_buf, 4096) == 4096);
                count ++;
                printf("reader..checking data integrity\n");
                int i=0;
                for (i=0; i < 4095; i++)
                {
                        int prev_char = read_buf[i];
                        int next_char = read_buf[i+1];
                        if (prev_char != next_char)
                        {
                                printf("reader.. corrupted data, at offset

:
%d\n", i);
stop_write = 1;
int output_fd = open("res.txt",
O_CREAT|O_RDWR,
0777);

                                assert(write(output_fd, read_buf, 4096) ==
4096);
                                close(output_fd);
                                close(fd);
                                return NULL;
                        }
                }


        }
        //pthread_exit((void *)0);
        close(fd);
        return NULL;
}
int main (int argc, char *argv[])
{
        pthread_attr_t attr;
        void * arg = NULL;
        int *status;
        int err = 0;

        if (argc != 2) {
                printf("usage : ./reader_writer <file pathname>\n");
                exit(1);
        }


        memset(datafile, '\0', sizeof(datafile));
        strcpy(datafile, argv[1]);

        pthread_attr_init(&attr);
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

        /* create the reader and writer thread */
        printf("creating the threads\n");
        if ((err = pthread_create(&writer_id, &attr, writer, (void *)arg))
!=
0) {
                printf ("pthread_create failed err no :%d\n", err);
        }
        if ((err = pthread_create(&reader_id, &attr, reader, (void *)arg))
!=
0) {
                printf ("pthread_create failed err no :%d\n", err);
        }
        pthread_attr_destroy(&attr);

        /* Wait on the other threads */
        assert(pthread_join(writer_id, (void *)&status) == 0);
        assert(pthread_join(reader_id, (void *)&status) == 0);

        pthread_exit(NULL);
}

How to run
gcc program.c -o ext4_program -lpthread
./ext4_program ext4_write

--
Configure bugmail: https://bugzilla.kernel.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are watching the assignee of the bug.
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 3 lines
Configure bugmail: https://bugzilla.kernel.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are watching the assignee of the bug.
#2 lore raw

[Bug 50981] ext4 : DATA CORRUPTION read and write on same 4096 page range

In reply to [email protected]

https://bugzilla.kernel.org/show_bug.cgi?id=50981

Lukas Czerner <[email protected]> changed:

What |Removed |Added
----------------------------------------------------------------------------
CC| |[email protected]

--- Comment #2 from Lukas Czerner <[email protected]> 2012-11-26 08:34:18 --- This is present upstream as well (3.7.0-rc7). In fact it is not even ext4 specific. I can easily reproduce this on btrfs, ext3, vfat. I suspect that this would be reproducible on every file system which does not implement its own read/write exclusion as xfs does.

MM people should really take a look at this as well since we are expecting the read/write to/from the single page to be atomic, but this looks like that it might not be true.

Thanks!
-Lukas

Signature · 3 lines
Configure bugmail: https://bugzilla.kernel.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are watching the assignee of the bug.
#3 lore raw

[Bug 50981] ext4 : DATA CORRUPTION read and write on same 4096 page range

In reply to [email protected]

https://bugzilla.kernel.org/show_bug.cgi?id=50981

Zheng Liu <[email protected]> changed:

What |Removed |Added
----------------------------------------------------------------------------
CC| |[email protected]

--- Comment #3 from Zheng Liu <[email protected]> 2012-11-26 10:16:19 --- IMHO, the reason seems to be that no any locking is taken by generic_file_aio_read(). When ext4 does a buffered write, it will take i_mutex to ensure that there is no other writer. But ext4 (ext3, btrfs, and vfat) uses generic_file_aio_read() to do a buffered read, and it doesn't take i_mutex. So it is easy to read a inconsistent data while doing a write. I am not very familiar with xfs, but a rwlock will be taken when a read and/or a write is being done. So that is why xfs hasn't this problem.

Signature · 3 lines
Configure bugmail: https://bugzilla.kernel.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are watching the assignee of the bug.
#4 lore raw

[Bug 50981] ext4 : DATA CORRUPTION read and write on same 4096 page range

In reply to [email protected]

https://bugzilla.kernel.org/show_bug.cgi?id=50981

--- Comment #4 from Lukas Czerner <[email protected]> 2012-11-26 10:30:13 --- Yes, that's what I said XFS has its own read/write exclusion. However we're reading/writing a single page here and page read/write shoud be atomic so we should _not_ see page with mixed data. Basically the page should be locked when we copy data from/to it,

-Lukas

Signature · 3 lines
Configure bugmail: https://bugzilla.kernel.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are watching the assignee of the bug.
#5 lore raw

[Bug 50981] ext4 : DATA CORRUPTION read and write on same 4096 page range

In reply to [email protected]

https://bugzilla.kernel.org/show_bug.cgi?id=50981

--- Comment #5 from Zheng Liu <[email protected]> 2012-11-26 11:18:38 --- (In reply to comment #4)

Quoted 4 lines

Yes, that's what I said XFS has its own read/write exclusion. However we're reading/writing a single page here and page read/write shoud be atomic so we should _not_ see page with mixed data. Basically the page should be locked when we copy data from/to it,

Sorry, as my understanding, a page won't be locked when it is accessed if it has been mark uptodate. If we write a page that has been written recently, the uptodate flag won't be clear. So reader won't try to lock page, and maybe that is not atomic. Am I missing something?

Regards,
Zheng

Signature · 3 lines
Configure bugmail: https://bugzilla.kernel.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are watching the assignee of the bug.
#6 lore raw

[Bug 50981] ext4 : DATA CORRUPTION read and write on same 4096 page range

In reply to [email protected]

https://bugzilla.kernel.org/show_bug.cgi?id=50981

--- Comment #6 from Lukas Czerner <[email protected]> 2012-11-26 11:27:04 --- It might be, as I said the problem appears to be in mm code, most likely there is a problem with page locking. However I am not familiar enough with the mm code to know that for sure.

Signature · 3 lines
Configure bugmail: https://bugzilla.kernel.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are watching the assignee of the bug.
#7 lore raw

[Bug 50981] ext4 : DATA CORRUPTION read and write on same 4096 page range

In reply to [email protected]

https://bugzilla.kernel.org/show_bug.cgi?id=50981

--- Comment #7 from Zheng Liu <[email protected]> 2012-11-26 11:32:35 --- (In reply to comment #6)

Quoted 3 lines

It might be, as I said the problem appears to be in mm code, most likely there is a problem with page locking. However I am not familiar enough with the mm code to know that for sure.

Understood, thanks. :-)

Regards,
Zheng

Signature · 3 lines
Configure bugmail: https://bugzilla.kernel.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are watching the assignee of the bug.
#8 lore raw

[Bug 50981] ext4 : DATA CORRUPTION read and write on same 4096 page range

In reply to [email protected]

https://bugzilla.kernel.org/show_bug.cgi?id=50981

Alan <[email protected]> changed:

What |Removed |Added
----------------------------------------------------------------------------

                 CC|                            |[email protected],
                   |                            |[email protected]
     Kernel Version|2.6.32 Red Hat Enterprise   |3.7-rc
                   |Linux Workstation release   |
                   |6.2 (Santiago)              |
Signature · 3 lines
Configure bugmail: https://bugzilla.kernel.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are watching the assignee of the bug.
#9 lore raw

[Bug 50981] ext4 : DATA CORRUPTION read and write on same 4096 page range

In reply to [email protected]

https://bugzilla.kernel.org/show_bug.cgi?id=50981

--- Comment #8 from Alan <[email protected]> 2012-11-26 12:17:52 --- (retagged for 3.7-rc as per Lukas email, otherwise my scripts will keep wanting to close it as RHEL and not for upstream)

Signature · 3 lines
Configure bugmail: https://bugzilla.kernel.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are watching the assignee of the bug.
#10 lore raw

[Bug 50981] ext4 : DATA CORRUPTION read and write on same 4096 page range

In reply to [email protected]

https://bugzilla.kernel.org/show_bug.cgi?id=50981

--- Comment #9 from Lukas Czerner <[email protected]> 2012-11-26 12:22:42 --- Alan could you please also change the component and maybe even subject of the bug since it is not ext4 specific ?

Thanks!
-Lukas

Signature · 3 lines
Configure bugmail: https://bugzilla.kernel.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are watching the assignee of the bug.
#11 lore raw

[Bug 50981] generic_file_aio_read ?: No locking means DATA CORRUPTION read and write on same 4096 page range

In reply to [email protected]

https://bugzilla.kernel.org/show_bug.cgi?id=50981

Alan <[email protected]> changed:

What |Removed |Added
----------------------------------------------------------------------------

          Component|ext4                        |Other
         AssignedTo|[email protected] |[email protected]
                   |g                           |
            Product|File System                 |Memory Management
            Summary|ext4 : DATA CORRUPTION read |generic_file_aio_read ?: No
                   |and write on same 4096 page |locking means DATA
                   | range                      |CORRUPTION read and write
                   |                            |on same 4096 page  range
Signature · 3 lines
Configure bugmail: https://bugzilla.kernel.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are watching the assignee of the bug.
#12 lore raw

Re: [Bug 50981] generic_file_aio_read ?: No locking means DATA CORRUPTION read and write on same 4096 page range

Quoted 9 lines · On Mon, Nov 26, 2012 at 12:26:08PM +0000, [email protected]…

https://bugzilla.kernel.org/show_bug.cgi?id=50981

Alan <[email protected]> changed:

What |Removed |Added
----------------------------------------------------------------------------

          Component|ext4                        |Other
         AssignedTo|[email protected] |[email protected]
                   |g                           |

Note: now this bug has been removed from linux-ext4, people on the linux-ext4 mailing list who want to follow this bug will need to explicitly add themselves to the cc list on the bugzilla.kernel.org.

- Ted