mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-02 07:28:21 +00:00
vmmcache: fix dirty list race
This commit is contained in:
@@ -15,6 +15,7 @@
|
|||||||
#define PAGE_FLAGS_DIRTY 8
|
#define PAGE_FLAGS_DIRTY 8
|
||||||
#define PAGE_FLAGS_READY 16
|
#define PAGE_FLAGS_READY 16
|
||||||
#define PAGE_FLAGS_ERROR 32
|
#define PAGE_FLAGS_ERROR 32
|
||||||
|
#define PAGE_FLAGS_VNODE_SYNCING 64
|
||||||
|
|
||||||
typedef struct page_t {
|
typedef struct page_t {
|
||||||
struct vnode_t *backing;
|
struct vnode_t *backing;
|
||||||
|
|||||||
@@ -338,7 +338,7 @@ int vmmcache_syncvnode(vnode_t *vnode, uintmax_t offset, size_t size) {
|
|||||||
page_t *page = vnode->pages;
|
page_t *page = vnode->pages;
|
||||||
page_t *vnodedirtylist = NULL;
|
page_t *vnodedirtylist = NULL;
|
||||||
for (; page; page = page->vnodenext) {
|
for (; page; page = page->vnodenext) {
|
||||||
if (page->offset < offset || page->offset >= top || (page->flags & PAGE_FLAGS_DIRTY) == 0)
|
if (page->offset < offset || page->offset >= top || (page->flags & PAGE_FLAGS_DIRTY) == 0 || (page->flags & PAGE_FLAGS_VNODE_SYNCING))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// remove from write list and add to an internal list using the write pointers
|
// remove from write list and add to an internal list using the write pointers
|
||||||
@@ -355,6 +355,7 @@ int vmmcache_syncvnode(vnode_t *vnode, uintmax_t offset, size_t size) {
|
|||||||
|
|
||||||
page->writenext = vnodedirtylist;
|
page->writenext = vnodedirtylist;
|
||||||
page->writeprev = NULL;
|
page->writeprev = NULL;
|
||||||
|
page->flags |= PAGE_FLAGS_VNODE_SYNCING;
|
||||||
vnodedirtylist = page;
|
vnodedirtylist = page;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,6 +369,7 @@ int vmmcache_syncvnode(vnode_t *vnode, uintmax_t offset, size_t size) {
|
|||||||
page_t *page = vnodedirtylist;
|
page_t *page = vnodedirtylist;
|
||||||
vnodedirtylist = vnodedirtylist->writenext;
|
vnodedirtylist = vnodedirtylist->writenext;
|
||||||
page->writenext = NULL;
|
page->writenext = NULL;
|
||||||
|
page->flags &= ~PAGE_FLAGS_VNODE_SYNCING;
|
||||||
|
|
||||||
// another thread could already have synced this page, verify if it is still dirty
|
// another thread could already have synced this page, verify if it is still dirty
|
||||||
if (page->flags & PAGE_FLAGS_DIRTY) {
|
if (page->flags & PAGE_FLAGS_DIRTY) {
|
||||||
@@ -414,6 +416,7 @@ int vmmcache_makedirty(page_t *page) {
|
|||||||
// page is neither dirty nor truncated, add to dirty list and hold the page and vnode
|
// page is neither dirty nor truncated, add to dirty list and hold the page and vnode
|
||||||
page->flags |= PAGE_FLAGS_DIRTY;
|
page->flags |= PAGE_FLAGS_DIRTY;
|
||||||
|
|
||||||
|
if ((page->flags & PAGE_FLAGS_VNODE_SYNCING) == 0) {
|
||||||
page->writeprev = NULL;
|
page->writeprev = NULL;
|
||||||
page->writenext = dirtylist;
|
page->writenext = dirtylist;
|
||||||
if (dirtylist)
|
if (dirtylist)
|
||||||
@@ -422,6 +425,8 @@ int vmmcache_makedirty(page_t *page) {
|
|||||||
dirtylistend = page;
|
dirtylistend = page;
|
||||||
|
|
||||||
dirtylist = page;
|
dirtylist = page;
|
||||||
|
}
|
||||||
|
|
||||||
pmm_hold(pmm_getpageaddress(page));
|
pmm_hold(pmm_getpageaddress(page));
|
||||||
__assert(page->backing);
|
__assert(page->backing);
|
||||||
VOP_HOLD(page->backing);
|
VOP_HOLD(page->backing);
|
||||||
|
|||||||
Reference in New Issue
Block a user