Re99: how to flush out cache.?
Matthew Dillon
dillon at apollo.backplane.com
Thu Apr 22 20:26:13 PDT 2004
: (taking hackers off to reduce noise)
oops. I guess I didn't take it off hackers. Sorry about that.
Yah yah, I know, 'Matt's making a billion postings again'.
In anycase, I sent a patch set to Stephan and julian, and since I didn't
take it off the list like I said I would I guess I might as well post the
patch set and the revised test program too for anyone following along.
Note that the patch set is against DragonFly, but should easily patch into
4.x. Stephan and Julian will deal with 4.xisms and 5.xisms.
The idea with the fix is as follows:
* It's hard to make the VM system invalidate buffers, so don't try.
Instead, make UFS recognize the IO_INVAL ioflag and mark the buffer
appropriately in the putpages -> generic put pages -> VOP_WRITE() path.
This only occurs if the msync'd map was writable. If the msync'd map was
only readable, then the data is not flushed through the vnode system and
the pages will not be removed if there happens to be a buffer associated
with them, even if the buffer is clean.
I think this is reasonable. Not perfect, but reasonable.
* Set clean_only to TRUE when calling vm_object_page_remove(), which
causes vm_object_page_remove() to ignore wired or dirty pages. This
code is called for both readable and writable maps so we can't just
remove the page unconditionallty, hence clean_only should be
set to TRUE.
This means that any pages associated with the buffer cache will NOT
be removed if the map was read-only. If the map was writable, then
the IO_INVAL fix above will destroy the buffer and the page should
wind up not being wired any more, and thus will be properly removed.
That's it!
-Matt
/*
* y.c
*/
#include <sys/types.h>
#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int
main(int ac, char **av)
{
int fd;
char *ptr1;
char *ptr2;
char buf[4096];
fd = open("test.dat", O_RDWR|O_CREAT|O_TRUNC, 0666);
ftruncate(fd, 4096);
ptr1 = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
*ptr1 = 'A';
read(fd, buf, 4096);
ptr2 = mmap(NULL, 4096, PROT_READ, MAP_SHARED, fd, 0);
if (msync(ptr1, 4096, MS_INVALIDATE | MS_SYNC) < 0)
perror("msync");
sleep(4);
printf("contents of *ptr1 is %d\n", *ptr1);
printf("contents of *ptr2 is %d\n", *ptr2);
return(0);
}
Index: vm/vm_map.c
===================================================================
RCS file: /cvs/src/sys/vm/vm_map.c,v
retrieving revision 1.24
diff -u -r1.24 vm_map.c
--- vm/vm_map.c 23 Mar 2004 22:54:32 -0000 1.24
+++ vm/vm_map.c 23 Apr 2004 02:56:17 -0000
@@ -2212,7 +2212,7 @@
vm_object_page_remove(object,
OFF_TO_IDX(offset),
OFF_TO_IDX(offset + size + PAGE_MASK),
- FALSE);
+ TRUE);
vm_object_deallocate(object);
}
start += size;
Index: vfs/ufs/ufs_readwrite.c
===================================================================
RCS file: /cvs/src/sys/vfs/ufs/ufs_readwrite.c,v
retrieving revision 1.9
diff -u -r1.9 ufs_readwrite.c
--- vfs/ufs/ufs_readwrite.c 26 Jul 2003 22:04:27 -0000 1.9
+++ vfs/ufs/ufs_readwrite.c 23 Apr 2004 03:05:50 -0000
@@ -531,6 +531,8 @@
bp->b_flags |= B_DIRECT;
if (ioflag & IO_NOWDRAIN)
bp->b_flags |= B_NOWDRAIN;
+ if ((ioflag & (IO_SYNC|IO_INVAL)) == (IO_SYNC|IO_INVAL))
+ bp->b_flags |= B_NOCACHE;
if (uio->uio_offset + xfersize > ip->i_size) {
ip->i_size = uio->uio_offset + xfersize;
More information about the freebsd-hackers
mailing list