VM: readd support for forgetting cached FS blocks
Not all services involved in block I/O go through VM to access the blocks they need. As a result, the blocks in VM may become stale, possibly causing corruption when the stale copy is restored by a service that does go through VM later on. This patch restores support for forgetting cached blocks that belong to a particular device, and makes the relevant file systems use this functionality 1) when requested by VFS through REQ_FLUSH, and 2) upon unmount. Change-Id: I0758c5ed8fe4b5ba81d432595d2113175776aff8
This commit is contained in:
parent
df724f2e14
commit
b48542d914
15 changed files with 75 additions and 14 deletions
|
@ -734,6 +734,7 @@ struct
|
||||||
{ "PROCCTL", VM_PROCCTL },
|
{ "PROCCTL", VM_PROCCTL },
|
||||||
{ "MAPCACHEPAGE", VM_MAPCACHEPAGE },
|
{ "MAPCACHEPAGE", VM_MAPCACHEPAGE },
|
||||||
{ "SETCACHEPAGE", VM_SETCACHEPAGE },
|
{ "SETCACHEPAGE", VM_SETCACHEPAGE },
|
||||||
|
{ "CLEARCACHE", VM_CLEARCACHE },
|
||||||
{ "VFS_MMAP", VM_VFS_MMAP },
|
{ "VFS_MMAP", VM_VFS_MMAP },
|
||||||
{ "VFS_REPLY", VM_VFS_REPLY },
|
{ "VFS_REPLY", VM_VFS_REPLY },
|
||||||
{ NULL, 0 },
|
{ NULL, 0 },
|
||||||
|
|
|
@ -110,7 +110,7 @@ service mfs
|
||||||
{
|
{
|
||||||
ipc ALL_SYS; # All system ipc targets allowed
|
ipc ALL_SYS; # All system ipc targets allowed
|
||||||
system BASIC; # Only basic kernel calls allowed
|
system BASIC; # Only basic kernel calls allowed
|
||||||
vm MAPCACHEPAGE SETCACHEPAGE;
|
vm MAPCACHEPAGE SETCACHEPAGE CLEARCACHE;
|
||||||
io NONE; # No I/O range allowed
|
io NONE; # No I/O range allowed
|
||||||
irq NONE; # No IRQ allowed
|
irq NONE; # No IRQ allowed
|
||||||
sigmgr rs; # Signal manager is RS
|
sigmgr rs; # Signal manager is RS
|
||||||
|
@ -137,7 +137,7 @@ service ext2
|
||||||
{
|
{
|
||||||
ipc ALL_SYS; # All system ipc targets allowed
|
ipc ALL_SYS; # All system ipc targets allowed
|
||||||
system BASIC; # Only basic kernel calls allowed
|
system BASIC; # Only basic kernel calls allowed
|
||||||
vm MAPCACHEPAGE SETCACHEPAGE;
|
vm MAPCACHEPAGE SETCACHEPAGE CLEARCACHE;
|
||||||
io NONE; # No I/O range allowed
|
io NONE; # No I/O range allowed
|
||||||
irq NONE; # No IRQ allowed
|
irq NONE; # No IRQ allowed
|
||||||
sigmgr rs; # Signal manager is RS
|
sigmgr rs; # Signal manager is RS
|
||||||
|
@ -150,7 +150,7 @@ service pfs
|
||||||
{
|
{
|
||||||
ipc ALL_SYS; # All system ipc targets allowed
|
ipc ALL_SYS; # All system ipc targets allowed
|
||||||
system BASIC; # Only basic kernel calls allowed
|
system BASIC; # Only basic kernel calls allowed
|
||||||
vm MAPCACHEPAGE SETCACHEPAGE;
|
vm MAPCACHEPAGE SETCACHEPAGE CLEARCACHE;
|
||||||
io NONE; # No I/O range allowed
|
io NONE; # No I/O range allowed
|
||||||
irq NONE; # No IRQ allowed
|
irq NONE; # No IRQ allowed
|
||||||
sigmgr rs; # Signal manager is RS
|
sigmgr rs; # Signal manager is RS
|
||||||
|
|
|
@ -978,6 +978,9 @@
|
||||||
/* To VM: identify cache block in FS */
|
/* To VM: identify cache block in FS */
|
||||||
#define VM_SETCACHEPAGE (VM_RQ_BASE+27)
|
#define VM_SETCACHEPAGE (VM_RQ_BASE+27)
|
||||||
|
|
||||||
|
/* To VM: clear all cache blocks for a device */
|
||||||
|
#define VM_CLEARCACHE (VM_RQ_BASE+28)
|
||||||
|
|
||||||
/* To VFS: fields for request from VM. */
|
/* To VFS: fields for request from VM. */
|
||||||
# define VFS_VMCALL_REQ m10_i1
|
# define VFS_VMCALL_REQ m10_i1
|
||||||
# define VFS_VMCALL_FD m10_i2
|
# define VFS_VMCALL_FD m10_i2
|
||||||
|
|
|
@ -72,6 +72,8 @@ int vm_set_cacheblock(void *block, u32_t dev, u64_t dev_offset,
|
||||||
void *vm_map_cacheblock(u32_t dev, u64_t dev_offset,
|
void *vm_map_cacheblock(u32_t dev, u64_t dev_offset,
|
||||||
u64_t ino, u64_t ino_offset, u32_t *flags, int blocksize);
|
u64_t ino, u64_t ino_offset, u32_t *flags, int blocksize);
|
||||||
|
|
||||||
|
int vm_clear_cache(u32_t dev);
|
||||||
|
|
||||||
/* flags for vm cache functions */
|
/* flags for vm cache functions */
|
||||||
#define VMMC_FLAGS_LOCKED 0x01 /* someone is updating the flags; don't read/write */
|
#define VMMC_FLAGS_LOCKED 0x01 /* someone is updating the flags; don't read/write */
|
||||||
#define VMMC_DIRTY 0x02 /* dirty buffer and it may not be evicted */
|
#define VMMC_DIRTY 0x02 /* dirty buffer and it may not be evicted */
|
||||||
|
|
|
@ -577,6 +577,8 @@ void lmfs_invalidate(
|
||||||
bp->data = NULL;
|
bp->data = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vm_clear_cache(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
|
|
@ -60,3 +60,17 @@ int vm_set_cacheblock(void *block, u32_t dev, u64_t dev_offset,
|
||||||
return vm_cachecall(&m, VM_SETCACHEPAGE, block, dev, dev_offset,
|
return vm_cachecall(&m, VM_SETCACHEPAGE, block, dev, dev_offset,
|
||||||
ino, ino_offset, flags, blocksize);
|
ino, ino_offset, flags, blocksize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
vm_clear_cache(u32_t dev)
|
||||||
|
{
|
||||||
|
message m;
|
||||||
|
|
||||||
|
assert(dev != NO_DEV);
|
||||||
|
|
||||||
|
memset(&m, 0, sizeof(m));
|
||||||
|
|
||||||
|
m.m_u.m_vmmcp.dev = dev;
|
||||||
|
|
||||||
|
return _taskcall(VM_PROC_NR, VM_CLEARCACHE, &m);
|
||||||
|
}
|
||||||
|
|
|
@ -241,6 +241,9 @@ int fs_unmount()
|
||||||
/* Close the device the file system lives on. */
|
/* Close the device the file system lives on. */
|
||||||
bdev_close(fs_dev);
|
bdev_close(fs_dev);
|
||||||
|
|
||||||
|
/* Throw all blocks out of the VM cache, to prevent corruption later. */
|
||||||
|
lmfs_invalidate(fs_dev);
|
||||||
|
|
||||||
/* Finish off the unmount. */
|
/* Finish off the unmount. */
|
||||||
superblock->s_dev = NO_DEV;
|
superblock->s_dev = NO_DEV;
|
||||||
unmountdone = TRUE;
|
unmountdone = TRUE;
|
||||||
|
|
|
@ -187,6 +187,9 @@ int fs_unmount()
|
||||||
/* Close the device the file system lives on. */
|
/* Close the device the file system lives on. */
|
||||||
bdev_close(fs_dev);
|
bdev_close(fs_dev);
|
||||||
|
|
||||||
|
/* Throw out blocks out of the VM cache, to prevent corruption later. */
|
||||||
|
lmfs_invalidate(fs_dev);
|
||||||
|
|
||||||
/* Finish off the unmount. */
|
/* Finish off the unmount. */
|
||||||
superblock.s_dev = NO_DEV;
|
superblock.s_dev = NO_DEV;
|
||||||
unmountdone = TRUE;
|
unmountdone = TRUE;
|
||||||
|
|
|
@ -304,6 +304,25 @@ int cache_freepages(int pages)
|
||||||
return freed;
|
return freed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove all pages that are associated with the given device.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
clear_cache_bydev(dev_t dev)
|
||||||
|
{
|
||||||
|
struct cached_page *cp, *ncp;
|
||||||
|
int h;
|
||||||
|
|
||||||
|
for (h = 0; h < HASHSIZE; h++) {
|
||||||
|
for (cp = cache_hash_bydev[h]; cp != NULL; cp = ncp) {
|
||||||
|
ncp = cp->hash_next_dev;
|
||||||
|
|
||||||
|
if (cp->dev == dev)
|
||||||
|
rmcache(cp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void get_stats_info(struct vm_stats_info *vsi)
|
void get_stats_info(struct vm_stats_info *vsi)
|
||||||
{
|
{
|
||||||
vsi->vsi_cached = cached_pages;
|
vsi->vsi_cached = cached_pages;
|
||||||
|
|
|
@ -485,6 +485,7 @@ void init_vm(void)
|
||||||
/* Cache blocks. */
|
/* Cache blocks. */
|
||||||
CALLMAP(VM_MAPCACHEPAGE, do_mapcache);
|
CALLMAP(VM_MAPCACHEPAGE, do_mapcache);
|
||||||
CALLMAP(VM_SETCACHEPAGE, do_setcache);
|
CALLMAP(VM_SETCACHEPAGE, do_setcache);
|
||||||
|
CALLMAP(VM_CLEARCACHE, do_clearcache);
|
||||||
|
|
||||||
/* getrusage */
|
/* getrusage */
|
||||||
CALLMAP(VM_GETRUSAGE, do_getrusage);
|
CALLMAP(VM_GETRUSAGE, do_getrusage);
|
||||||
|
|
|
@ -238,3 +238,17 @@ do_setcache(message *msg)
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A file system wants to invalidate all pages belonging to a certain device.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
do_clearcache(message *msg)
|
||||||
|
{
|
||||||
|
dev_t dev;
|
||||||
|
|
||||||
|
dev = msg->m_u.m_vmmcp.dev;
|
||||||
|
|
||||||
|
clear_cache_bydev(dev);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
|
@ -218,6 +218,7 @@ void shared_setsource(struct vir_region *vr, endpoint_t ep, struct vir_region *s
|
||||||
/* mem_cache.c */
|
/* mem_cache.c */
|
||||||
int do_mapcache(message *m);
|
int do_mapcache(message *m);
|
||||||
int do_setcache(message *m);
|
int do_setcache(message *m);
|
||||||
|
int do_clearcache(message *m);
|
||||||
|
|
||||||
/* cache.c */
|
/* cache.c */
|
||||||
struct cached_page *find_cached_page_bydev(dev_t dev, u64_t dev_off,
|
struct cached_page *find_cached_page_bydev(dev_t dev, u64_t dev_off,
|
||||||
|
@ -229,6 +230,7 @@ int cache_freepages(int pages);
|
||||||
void get_stats_info(struct vm_stats_info *vsi);
|
void get_stats_info(struct vm_stats_info *vsi);
|
||||||
void cache_lru_touch(struct cached_page *hb);
|
void cache_lru_touch(struct cached_page *hb);
|
||||||
void rmcache(struct cached_page *cp);
|
void rmcache(struct cached_page *cp);
|
||||||
|
void clear_cache_bydev(dev_t dev);
|
||||||
|
|
||||||
/* vfs.c */
|
/* vfs.c */
|
||||||
int vfs_request(int reqno, int fd, struct vmproc *vmp, u64_t offset,
|
int vfs_request(int reqno, int fd, struct vmproc *vmp, u64_t offset,
|
||||||
|
|
|
@ -224,16 +224,6 @@ panic(const char *fmt, ...)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int vm_forgetblock(u64_t id)
|
|
||||||
{
|
|
||||||
return ENOSYS;
|
|
||||||
}
|
|
||||||
|
|
||||||
void vm_forgetblocks(void)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
vm_info_stats(struct vm_stats_info *vsi)
|
vm_info_stats(struct vm_stats_info *vsi)
|
||||||
{
|
{
|
||||||
|
@ -274,6 +264,11 @@ void *vm_map_cacheblock(u32_t dev, u64_t dev_offset,
|
||||||
return MAP_FAILED;
|
return MAP_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int vm_clear_cache(u32_t dev)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
|
|
@ -177,6 +177,8 @@ main(int argc, char *argv[])
|
||||||
|
|
||||||
writepipe(&info);
|
writepipe(&info);
|
||||||
|
|
||||||
|
vm_clear_cache(MYDEV);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
service testvm {
|
service testvm {
|
||||||
ipc ALL; # All system ipc targets allowed
|
ipc ALL; # All system ipc targets allowed
|
||||||
system BASIC; # Only basic kernel calls allowed
|
system BASIC; # Only basic kernel calls allowed
|
||||||
vm MAPCACHEPAGE SETCACHEPAGE;
|
vm MAPCACHEPAGE SETCACHEPAGE CLEARCACHE;
|
||||||
io NONE; # No I/O range allowed
|
io NONE; # No I/O range allowed
|
||||||
irq NONE; # No IRQ allowed
|
irq NONE; # No IRQ allowed
|
||||||
sigmgr rs; # Signal manager is RS
|
sigmgr rs; # Signal manager is RS
|
||||||
|
|
Loading…
Reference in a new issue