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)
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
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
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.
> 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
>
>
> 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
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.
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
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
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..
--- 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);
"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;
}
_