2003-05-28 17:45:31

by Rob van Nieuwkerk

[permalink] [raw]
Subject: 2.4 bug: fifo-write causes diskwrites to read-only fs !

Hi all,

It turns out that Linux is updating inode timestamps of fifos (named
pipes) that are written to while residing on a read-only filesystem.
It is not only updating in-ram info, but it will issue *physical*
writes to the read-only fs on the disk !

I use a CompactFlash in an embedded application with a read-only root-fs
on it. There are several processes that communicate with each other
via fifos. This bug in Linux causes frequent writes to my CF and will
shorten it's lifetime enormously ..

I've posted a report on the "mysterious writes" before:
( http://www.ussg.iu.edu/hypermail/linux/kernel/0303.2/1753.html )
(incorrectly) linking it to a possible bug in O_SYNC. Nothing came out
of it.

But now I've completely tracked down the bug (logging all diskaccesses
and seeing it undoubtly write in disksectors containing time-stamp
info of fifo's). Looking back it would have been easier to prove that
something is wrong: the modified time-stamps survive power-cycles.
This is not supposed to happen on a read-only fs.

I've tried reading the kernel source to find where the bug lives,
But I'm not too familiar with it. Anyone out there who can
pin it down ?

greetings,
Rob van Nieuwkerk


Sysinfo:
--------
- various 2.4 kernels including RH-2.4.20-13.9,
but also straight 2.4(ac) ones.
- CompactFlash (= IDE disk)
- Geode GX1 CPU (i586 compatible)


2003-05-28 18:39:20

by Rob van Nieuwkerk

[permalink] [raw]
Subject: Re: 2.4 bug: fifo-write causes diskwrites to read-only fs !


I wrote:
> It turns out that Linux is updating inode timestamps of fifos (named
> pipes) that are written to while residing on a read-only filesystem.
> It is not only updating in-ram info, but it will issue *physical*
> writes to the read-only fs on the disk !
.
.
.
> Sysinfo:
> --------
> - various 2.4 kernels including RH-2.4.20-13.9,
> but also straight 2.4(ac) ones.
> - CompactFlash (= IDE disk)
> - Geode GX1 CPU (i586 compatible)

Forgot to mention: I use an ext2 fs, but maybe it's a generic,
fs-independant problem.

greetings,
Rob van Nieuwkerk

2003-05-28 19:04:45

by Nuno Silva

[permalink] [raw]
Subject: Re: 2.4 bug: fifo-write causes diskwrites to read-only fs !



Rob van Nieuwkerk wrote:
> Hi all,
>
> It turns out that Linux is updating inode timestamps of fifos (named
> pipes) that are written to while residing on a read-only filesystem.
> It is not only updating in-ram info, but it will issue *physical*
> writes to the read-only fs on the disk !

Hi!

I can't give a solution but the workaround is obvious:
mount -t ramfs none /myFifos

Regards,
Nuno Silva



2003-05-28 19:01:24

by Richard B. Johnson

[permalink] [raw]
Subject: Re: 2.4 bug: fifo-write causes diskwrites to read-only fs !

On Wed, 28 May 2003, Rob van Nieuwkerk wrote:

>
> I wrote:
> > It turns out that Linux is updating inode timestamps of fifos (named
> > pipes) that are written to while residing on a read-only filesystem.
> > It is not only updating in-ram info, but it will issue *physical*
> > writes to the read-only fs on the disk !
> .
> .
> .
> > Sysinfo:
> > --------
> > - various 2.4 kernels including RH-2.4.20-13.9,
> > but also straight 2.4(ac) ones.
> > - CompactFlash (= IDE disk)
> > - Geode GX1 CPU (i586 compatible)
>
> Forgot to mention: I use an ext2 fs, but maybe it's a generic,
> fs-independant problem.
>
> greetings,
> Rob van Nieuwkerk

How does it 'know' it's a R/O file-system? Have you mounted it
R/O, mounted it noatime, or just taken whatever you get when
you boot from a ramdisk?

FYI, I created a FIFO with mkfifo, remounted the file-system
R/O, executed `cat` with it's input coming from the FIFO, and
then waited for a few minutes. I then wrote to the FIFO.
The atime did not change with 2.4.20.

Cheers,
Dick Johnson
Penguin : Linux version 2.4.20 on an i686 machine (797.90 BogoMips).
Why is the government concerned about the lunatic fringe? Think about it.

2003-05-28 19:21:14

by Rob van Nieuwkerk

[permalink] [raw]
Subject: Re: 2.4 bug: fifo-write causes diskwrites to read-only fs !

> On Wed, 28 May 2003, Rob van Nieuwkerk wrote:
>
> >
> > I wrote:
> > > It turns out that Linux is updating inode timestamps of fifos (named
> > > pipes) that are written to while residing on a read-only filesystem.
> > > It is not only updating in-ram info, but it will issue *physical*
> > > writes to the read-only fs on the disk !
> > .
> > .
> > .
> > > Sysinfo:
> > > --------
> > > - various 2.4 kernels including RH-2.4.20-13.9,
> > > but also straight 2.4(ac) ones.
> > > - CompactFlash (= IDE disk)
> > > - Geode GX1 CPU (i586 compatible)
> >
> > Forgot to mention: I use an ext2 fs, but maybe it's a generic,
> > fs-independant problem.
> >
> > greetings,
> > Rob van Nieuwkerk
>
> How does it 'know' it's a R/O file-system? Have you mounted it
> R/O, mounted it noatime, or just taken whatever you get when
> you boot from a ramdisk?

Hi Richard,

The kernel has the "ro" commandline-parameter.
There is no remount after the system boots.
"touch /bla" gives a read-only fs error.

> FYI, I created a FIFO with mkfifo, remounted the file-system
> R/O, executed `cat` with it's input coming from the FIFO, and
> then waited for a few minutes. I then wrote to the FIFO.
> The atime did not change with 2.4.20.

Just did the same here (on my workstation). And the times *did* change ..
More precisely: the "modification" & "change" were updated, the "access"
time remained unchanged.

RH9, kernel-2.4.20-13.9

greetings,
Rob van Nieuwkerk

2003-05-28 19:23:55

by Rob van Nieuwkerk

[permalink] [raw]
Subject: Re: 2.4 bug: fifo-write causes diskwrites to read-only fs !

>
>
> Rob van Nieuwkerk wrote:
> > Hi all,
> >
> > It turns out that Linux is updating inode timestamps of fifos (named
> > pipes) that are written to while residing on a read-only filesystem.
> > It is not only updating in-ram info, but it will issue *physical*
> > writes to the read-only fs on the disk !
>
> Hi!
>
> I can't give a solution but the workaround is obvious:
> mount -t ramfs none /myFifos

Hi Nuno,

Yup, already thought of that.
But would be nice if the bug was fixed too !

greetings,
Rob van Nieuwkerk

2003-05-28 20:06:33

by Richard B. Johnson

[permalink] [raw]
Subject: Re: 2.4 bug: fifo-write causes diskwrites to read-only fs !

On Wed, 28 May 2003, Rob van Nieuwkerk wrote:

> > On Wed, 28 May 2003, Rob van Nieuwkerk wrote:
> >
> > >
> > > I wrote:
> > > > It turns out that Linux is updating inode timestamps of fifos (named
> > > > pipes) that are written to while residing on a read-only filesystem.
> > > > It is not only updating in-ram info, but it will issue *physical*
> > > > writes to the read-only fs on the disk !
> > > .
> > > .
> > > .
> > > > Sysinfo:
> > > > --------
> > > > - various 2.4 kernels including RH-2.4.20-13.9,
> > > > but also straight 2.4(ac) ones.
> > > > - CompactFlash (= IDE disk)
> > > > - Geode GX1 CPU (i586 compatible)
> > >
> > > Forgot to mention: I use an ext2 fs, but maybe it's a generic,
> > > fs-independant problem.
> > >
> > > greetings,
> > > Rob van Nieuwkerk
> >
> > How does it 'know' it's a R/O file-system? Have you mounted it
> > R/O, mounted it noatime, or just taken whatever you get when
> > you boot from a ramdisk?
>
> Hi Richard,
>
> The kernel has the "ro" commandline-parameter.
> There is no remount after the system boots.
> "touch /bla" gives a read-only fs error.
>
> > FYI, I created a FIFO with mkfifo, remounted the file-system
> > R/O, executed `cat` with it's input coming from the FIFO, and
> > then waited for a few minutes. I then wrote to the FIFO.
> > The atime did not change with 2.4.20.
>
> Just did the same here (on my workstation). And the times *did* change ..
> More precisely: the "modification" & "change" were updated, the "access"
> time remained unchanged.
>

Okay. I can now verify the problem. There are two problems as this
script will show:

Script started on Wed May 28 16:10:13 2003
# cat xxx.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/wait.h>

int main(void);
static const char fifo[]="/alt/FIFO";
void reaper(int unused)
{
while(wait3(&unused, WNOHANG, NULL) > 0)
;
}
int main()
{
int fd;
int i;
char buf[0x1000];
struct stat sb;

(void)mkfifo(fifo, 0644);
(void)signal(SIGCHLD, reaper);
if((fd = open(fifo, O_RDWR)) < 0)
exit(EXIT_FAILURE);
switch(fork())
{
case 0:
for(;;)
{
if(read(fd, buf, sizeof(buf)) < 0)
exit(EXIT_FAILURE);
if(*buf == (char) 0xa5) exit(EXIT_SUCCESS);
}
break; /* Not reached */
case -1:
fprintf(stderr, "Can't fork()\n");
exit(EXIT_FAILURE);
break; /* Not reached */
default:
break; /* Now required */
}
memset(buf, 0x00, sizeof(buf));
for(i=0; i< 0x10; i++)
{
(void)write(fd, buf, sizeof(buf));
(void)fstat(fd, &sb);
printf("atime = %08lx\n", sb.st_atime);
printf("mtime = %08lx\n", sb.st_mtime);
printf("ctime = %08lx\n", sb.st_ctime);
sleep(1);
}
*buf = (char)0xa5;
(void)write(fd, buf, 0x01);
(void)close(fd);
// (void)unlink(fifo);
return 0;
}

# gcc -O2 -o xxx -Wall xxx.c
# ./xxx
atime = 3ed51750
mtime = 3ed517c5
ctime = 3ed517c5
atime = 3ed51750
mtime = 3ed517c6
ctime = 3ed517c6
atime = 3ed51750
mtime = 3ed517c7
ctime = 3ed517c7
atime = 3ed51750
mtime = 3ed517c8
ctime = 3ed517c8
atime = 3ed51750
mtime = 3ed517c9
ctime = 3ed517c9
atime = 3ed51750
mtime = 3ed517ca
ctime = 3ed517ca
atime = 3ed51750
mtime = 3ed517cb
ctime = 3ed517cb
atime = 3ed51750
mtime = 3ed517cc
ctime = 3ed517cc
atime = 3ed51750
mtime = 3ed517cd
ctime = 3ed517cd
atime = 3ed51750
mtime = 3ed517ce
ctime = 3ed517ce
atime = 3ed51750
mtime = 3ed517cf
ctime = 3ed517cf
atime = 3ed51750
mtime = 3ed517d0
ctime = 3ed517d0
atime = 3ed51750
mtime = 3ed517d1
ctime = 3ed517d1
atime = 3ed51750
mtime = 3ed517d2
ctime = 3ed517d2
atime = 3ed51750
mtime = 3ed517d3
ctime = 3ed517d3
atime = 3ed51750
mtime = 3ed517d4
ctime = 3ed517d4
# >/alt/foo
bash: /alt/foo: Read-only file system
# exit
exit
Script done on Wed May 28 16:11:12 2003

As you can clearly see, access time (atime) is not changed.
However, both ctime and mtime are both changed with every
FIFO access. Since this FIFO is provably on a R/O file system,
nothing should change.

Now, somebody will probably claim that this is the correct
POSIX defined behavior <sigh> so you might have to make some
work-around like use a pipe or socket instead of the FIFO??

Cheers,
Dick Johnson
Penguin : Linux version 2.4.20 on an i686 machine (797.90 BogoMips).
Why is the government concerned about the lunatic fringe? Think about it.

2003-05-28 20:39:27

by Rob van Nieuwkerk

[permalink] [raw]
Subject: Re: 2.4 bug: fifo-write causes diskwrites to read-only fs !


Hi Richard,

> > > > > It turns out that Linux is updating inode timestamps of fifos (named
> > > > > pipes) that are written to while residing on a read-only filesystem.
> > > > > It is not only updating in-ram info, but it will issue *physical*
> > > > > writes to the read-only fs on the disk !

> > > FYI, I created a FIFO with mkfifo, remounted the file-system
> > > R/O, executed `cat` with it's input coming from the FIFO, and
> > > then waited for a few minutes. I then wrote to the FIFO.
> > > The atime did not change with 2.4.20.
> >
> > Just did the same here (on my workstation). And the times *did* change ..
> > More precisely: the "modification" & "change" were updated, the "access"
> > time remained unchanged.
> >
>
> Okay. I can now verify the problem. There are two problems as this

Yeah !, I'm no longer alone .. :-)
.
.
> As you can clearly see, access time (atime) is not changed.
> However, both ctime and mtime are both changed with every
> FIFO access. Since this FIFO is provably on a R/O file system,
> nothing should change.

Note that the fact that you see the times changing in the fs while it
is mounted doesn't imply a problem in itself: serial and tty device
nodes get their time-stamps updated too on a read-only fs when they
are written. But these changes are in ram only: when you reboot you
get the old values back.

But with FIFOs the changes *do* get written out to the read-only fs !

Hmm, wonder what happens if you try it on a real read-only medium like
a CDR. Maybe kernel errors/panic ..

> Now, somebody will probably claim that this is the correct
> POSIX defined behavior <sigh> so you might have to make some
> work-around like use a pipe or socket instead of the FIFO??

Seems very stupid to me if POSIX specifies this.
I don't have the POSIX spec, but maybe it specifies what "read-only"
is supposed to mean somewhere too ..

But let's wait & see .. :-)

greetings,
Rob van Nieuwkerk

2003-05-30 13:07:59

by Stephen C. Tweedie

[permalink] [raw]
Subject: Re: 2.4 bug: fifo-write causes diskwrites to read-only fs !

Hi,

On Wed, May 28, 2003 at 10:52:30PM +0200, Rob van Nieuwkerk wrote:

> I don't have the POSIX spec, but maybe it specifies what "read-only"
> is supposed to mean somewhere too ..

SingleUnix says:

http://www.opengroup.org/onlinepubs/007904975/basedefs/xbd_chap04.html#tag_04_07

"Marks for update, and updates themselves, are not done for files on
read-only file systems"

So we're wrong here. Patch below fixes it for me for 2.4.

Cheers,
Stephen


Attachments:
(No filename) (455.00 B)
4202-vfs-mctime-rofs.patch (1.56 kB)
Download all attachments

2003-05-30 14:45:13

by Christoph Hellwig

[permalink] [raw]
Subject: Re: 2.4 bug: fifo-write causes diskwrites to read-only fs !

On Fri, May 30, 2003 at 02:21:12PM +0100, Stephen C. Tweedie wrote:
> +void update_mctime (struct inode *inode)
> +{
> + if (inode->i_mtime == CURRENT_TIME && inode->i_ctime == CURRENT_TIME)
> + return;
> + if ( IS_RDONLY (inode) ) return;
> + inode->i_ctime = inode->i_mtime = CURRENT_TIME;
> + mark_inode_dirty (inode);
> +} /* End Function update_mctime */
> +

Yikes, this looks like devfs code! Please try to use proper kernel style..

2003-05-30 15:05:39

by Stephen C. Tweedie

[permalink] [raw]
Subject: Re: 2.4 bug: fifo-write causes diskwrites to read-only fs !

--- linux-2.4-odirect/fs/inode.c.=K0001=.orig
+++ linux-2.4-odirect/fs/inode.c
@@ -1187,12 +1187,34 @@ void update_atime (struct inode *inode)
{
if (inode->i_atime == CURRENT_TIME)
return;
- if ( IS_NOATIME (inode) ) return;
- if ( IS_NODIRATIME (inode) && S_ISDIR (inode->i_mode) ) return;
- if ( IS_RDONLY (inode) ) return;
+ if (IS_NOATIME(inode))
+ return;
+ if (IS_NODIRATIME(inode) && S_ISDIR(inode->i_mode))
+ return;
+ if (IS_RDONLY(inode))
+ return;
inode->i_atime = CURRENT_TIME;
mark_inode_dirty_sync (inode);
-} /* End Function update_atime */
+}
+
+/**
+ * update_mctime - update the mtime and ctime
+ * @inode: inode accessed
+ *
+ * Update the modified and changed times on an inode for writes to special
+ * files such as fifos. No change is forced if the timestamps are already
+ * up-to-date or if the filesystem is readonly.
+ */
+
+void update_mctime (struct inode *inode)
+{
+ if (inode->i_mtime == CURRENT_TIME && inode->i_ctime == CURRENT_TIME)
+ return;
+ if (IS_RDONLY(inode))
+ return;
+ inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ mark_inode_dirty (inode);
+}


/*
--- linux-2.4-odirect/fs/pipe.c.=K0001=.orig
+++ linux-2.4-odirect/fs/pipe.c
@@ -230,8 +230,7 @@ pipe_write(struct file *filp, const char
/* Signal readers asynchronously that there is more data. */
wake_up_interruptible(PIPE_WAIT(*inode));

- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
- mark_inode_dirty(inode);
+ update_mctime(inode);

out:
up(PIPE_SEM(*inode));
--- linux-2.4-odirect/include/linux/fs.h.=K0001=.orig
+++ linux-2.4-odirect/include/linux/fs.h
@@ -201,6 +201,7 @@ extern int leases_enable, dir_notify_ena
#include <asm/byteorder.h>

extern void update_atime (struct inode *);
+extern void update_mctime (struct inode *);
#define UPDATE_ATIME(inode) update_atime (inode)

extern void buffer_init(unsigned long);


Attachments:
4202-vfs-mctime-rofs.patch (1.83 kB)

2003-05-30 16:22:47

by Andrew Morton

[permalink] [raw]
Subject: Re: 2.4 bug: fifo-write causes diskwrites to read-only fs !

"Stephen C. Tweedie" <[email protected]> wrote:
>
> It's pure cut-and-paste from the update_atime immediately above it. But
> sure, we can clean them both up while we're at it if you want.

2.5 seems to have gained a handy library function.

diff -puN fs/pipe.c~pipe-rofs-fix fs/pipe.c
--- 25/fs/pipe.c~pipe-rofs-fix 2003-05-30 09:33:29.000000000 -0700
+++ 25-akpm/fs/pipe.c 2003-05-30 09:34:08.000000000 -0700
@@ -208,10 +208,8 @@ pipe_write(struct file *filp, const char
wake_up_interruptible(PIPE_WAIT(*inode));
kill_fasync(PIPE_FASYNC_READERS(*inode), SIGIO, POLL_IN);
}
- if (ret > 0) {
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
- mark_inode_dirty(inode);
- }
+ if (ret > 0)
+ inode_update_time(inode, 1); /* mtime and ctime */
return ret;
}


_