Added a "reenter" parameter to the {read|write}_pages() functions to give file

systems a chance to know if they have locked already.
This fixes a locking problem in BFS where one thread tried to acquire two read
locks (where someone else trying to acquire a write lock would have caused a
dead lock).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17108 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2006-04-12 13:34:04 +00:00
parent 4d89d3e7e1
commit 97e069713b
18 changed files with 104 additions and 80 deletions

View File

@ -1,6 +1,6 @@
/* File System Interface Layer Definition
*
* Copyright 2004-2005, Haiku Inc. All Rights Reserved.
* Copyright 2004-2006, Haiku Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _FS_INTERFACE_H
@ -87,8 +87,10 @@ typedef struct file_system_module_info {
/* VM file access */
bool (*can_page)(fs_volume fs, fs_vnode vnode, fs_cookie cookie);
status_t (*read_pages)(fs_volume fs, fs_vnode vnode, fs_cookie cookie, off_t pos, const iovec *vecs, size_t count, size_t *_numBytes);
status_t (*write_pages)(fs_volume fs, fs_vnode vnode, fs_cookie cookie, off_t pos, const iovec *vecs, size_t count, size_t *_numBytes);
status_t (*read_pages)(fs_volume fs, fs_vnode vnode, fs_cookie cookie, off_t pos,
const iovec *vecs, size_t count, size_t *_numBytes, bool reenter);
status_t (*write_pages)(fs_volume fs, fs_vnode vnode, fs_cookie cookie, off_t pos,
const iovec *vecs, size_t count, size_t *_numBytes, bool reenter);
/* cache file access */
status_t (*get_file_map)(fs_volume fs, fs_vnode vnode, off_t offset, size_t size, struct file_io_vec *vecs, size_t *_count);

View File

@ -87,9 +87,9 @@ void vfs_acquire_vnode(void *vnode);
status_t vfs_get_cookie_from_fd(int fd, void **_cookie);
bool vfs_can_page(void *vnode, void *cookie);
status_t vfs_read_pages(void *vnode, void *cookie, off_t pos,
const iovec *vecs, size_t count, size_t *_numBytes);
const iovec *vecs, size_t count, size_t *_numBytes, bool fsReenter);
status_t vfs_write_pages(void *vnode, void *cookie, off_t pos,
const iovec *vecs, size_t count, size_t *_numBytes);
const iovec *vecs, size_t count, size_t *_numBytes, bool fsReenter);
status_t vfs_get_vnode_cache(void *vnode, struct vm_cache_ref **_cache, bool allocate);
status_t vfs_get_file_map( void *_vnode, off_t offset, size_t size,
struct file_io_vec *vecs, size_t *_count);

View File

@ -27,7 +27,7 @@ void vm_cache_release_ref(vm_cache_ref *cache_ref);
vm_page *vm_cache_lookup_page(vm_cache_ref *cacheRef, off_t page);
void vm_cache_insert_page(vm_cache_ref *cacheRef, vm_page *page, off_t offset);
void vm_cache_remove_page(vm_cache_ref *cacheRef, vm_page *page);
status_t vm_cache_write_modified(vm_cache_ref *ref);
status_t vm_cache_write_modified(vm_cache_ref *ref, bool fsReenter);
status_t vm_cache_set_minimal_commitment(vm_cache_ref *ref, off_t commitment);
status_t vm_cache_resize(vm_cache_ref *cacheRef, off_t newSize);
status_t vm_cache_insert_area(vm_cache_ref *cacheRef, vm_area *area);

View File

@ -34,7 +34,7 @@ status_t vm_page_set_state(vm_page *page, int state);
size_t vm_page_num_pages(void);
size_t vm_page_num_free_pages(void);
status_t vm_page_write_modified(vm_cache *cache);
status_t vm_page_write_modified(vm_cache *cache, bool fsReenter);
vm_page *vm_page_allocate_page(int state);
status_t vm_page_allocate_pages(int pageState, vm_page **pages, uint32 numPages);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
@ -137,9 +137,12 @@ typedef struct vm_store_ops {
void (*destroy)(struct vm_store *backing_store);
status_t (*commit)(struct vm_store *backing_store, off_t size);
bool (*has_page)(struct vm_store *backing_store, off_t offset);
status_t (*read)(struct vm_store *backing_store, off_t offset, const iovec *vecs, size_t count, size_t *_numBytes);
status_t (*write)(struct vm_store *backing_store, off_t offset, const iovec *vecs, size_t count, size_t *_numBytes);
status_t (*fault)(struct vm_store *backing_store, struct vm_address_space *aspace, off_t offset);
status_t (*read)(struct vm_store *backing_store, off_t offset, const iovec *vecs,
size_t count, size_t *_numBytes, bool fsReenter);
status_t (*write)(struct vm_store *backing_store, off_t offset, const iovec *vecs,
size_t count, size_t *_numBytes, bool fsReenter);
status_t (*fault)(struct vm_store *backing_store, struct vm_address_space *aspace,
off_t offset);
void (*acquire_ref)(struct vm_store *backing_store);
void (*release_ref)(struct vm_store *backing_store);
} vm_store_ops;

View File

@ -369,53 +369,45 @@ bfs_can_page(fs_volume _fs, fs_vnode _v, fs_cookie _cookie)
static status_t
bfs_read_pages(fs_volume _fs, fs_vnode _node, fs_cookie _cookie, off_t pos,
const iovec *vecs, size_t count, size_t *_numBytes)
const iovec *vecs, size_t count, size_t *_numBytes, bool reenter)
{
Inode *inode = (Inode *)_node;
if (inode->FileCache() == NULL)
RETURN_ERROR(B_BAD_VALUE);
ReadLocked locked(inode->Lock());
return file_cache_read_pages(inode->FileCache(), pos, vecs, count, _numBytes);
#if 0
for (uint32 i = 0; i < count; i++) {
if (pos >= inode->Size()) {
memset(vecs[i].iov_base, 0, vecs[i].iov_len);
pos += vecs[i].iov_len;
*_numBytes -= vecs[i].iov_len;
} else {
uint32 length = vecs[i].iov_len;
if (length > inode->Size() - pos)
length = inode->Size() - pos;
if (!reenter)
inode->Lock().Lock();
inode->ReadAt(pos, (uint8 *)vecs[i].iov_base, &length);
status_t status = file_cache_read_pages(inode->FileCache(), pos, vecs, count,
_numBytes);
if (length < vecs[i].iov_len) {
memset((char *)vecs[i].iov_base + length, 0, vecs[i].iov_len - length);
*_numBytes -= vecs[i].iov_len - length;
}
if (!reenter)
inode->Lock().Unlock();
pos += vecs[i].iov_len;
}
}
return B_OK;
#endif
return status;
}
static status_t
bfs_write_pages(fs_volume _fs, fs_vnode _node, fs_cookie _cookie, off_t pos,
const iovec *vecs, size_t count, size_t *_numBytes)
const iovec *vecs, size_t count, size_t *_numBytes, bool reenter)
{
Inode *inode = (Inode *)_node;
if (inode->FileCache() == NULL)
RETURN_ERROR(B_BAD_VALUE);
ReadLocked locked(inode->Lock());
return file_cache_write_pages(inode->FileCache(), pos, vecs, count, _numBytes);
if (!reenter)
inode->Lock().Lock();
status_t status = file_cache_write_pages(inode->FileCache(), pos, vecs, count,
_numBytes);
if (!reenter)
inode->Lock().Unlock();
return status;
}

View File

@ -317,7 +317,8 @@ pages_io(file_cache_ref *ref, off_t offset, const iovec *vecs, size_t count,
if (size > numBytes)
size = numBytes;
status = vfs_read_pages(ref->device, ref->cookie, fileVecs[0].offset, vecs, count, &size);
status = vfs_read_pages(ref->device, ref->cookie, fileVecs[0].offset, vecs,
count, &size, false);
if (status < B_OK)
return status;
@ -394,10 +395,13 @@ pages_io(file_cache_ref *ref, off_t offset, const iovec *vecs, size_t count,
}
size_t bytes = size;
if (doWrite)
status = vfs_write_pages(ref->device, ref->cookie, fileVec.offset, tempVecs, tempCount, &bytes);
else
status = vfs_read_pages(ref->device, ref->cookie, fileVec.offset, tempVecs, tempCount, &bytes);
if (doWrite) {
status = vfs_write_pages(ref->device, ref->cookie, fileVec.offset, tempVecs,
tempCount, &bytes, false);
} else {
status = vfs_read_pages(ref->device, ref->cookie, fileVec.offset, tempVecs,
tempCount, &bytes, false);
}
if (status < B_OK)
return status;
@ -1221,7 +1225,7 @@ file_cache_sync(void *_cacheRef)
if (ref == NULL)
return B_BAD_VALUE;
return vm_cache_write_modified(ref->cache);
return vm_cache_write_modified(ref->cache, true);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2004-2006, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
@ -41,12 +41,14 @@ store_has_page(struct vm_store *_store, off_t offset)
static status_t
store_read(struct vm_store *_store, off_t offset, const iovec *vecs, size_t count, size_t *_numBytes)
store_read(struct vm_store *_store, off_t offset, const iovec *vecs, size_t count,
size_t *_numBytes, bool fsReenter)
{
vnode_store *store = (vnode_store *)_store;
size_t bytesUntouched = *_numBytes;
status_t status = vfs_read_pages(store->vnode, NULL, offset, vecs, count, _numBytes);
status_t status = vfs_read_pages(store->vnode, NULL, offset, vecs, count,
_numBytes, fsReenter);
bytesUntouched -= *_numBytes;
@ -70,10 +72,11 @@ store_read(struct vm_store *_store, off_t offset, const iovec *vecs, size_t coun
static status_t
store_write(struct vm_store *_store, off_t offset, const iovec *vecs, size_t count, size_t *_numBytes)
store_write(struct vm_store *_store, off_t offset, const iovec *vecs, size_t count,
size_t *_numBytes, bool fsReenter)
{
vnode_store *store = (vnode_store *)_store;
return vfs_write_pages(store->vnode, NULL, offset, vecs, count, _numBytes);
return vfs_write_pages(store->vnode, NULL, offset, vecs, count, _numBytes, fsReenter);
}

View File

@ -1643,7 +1643,8 @@ devfs_can_page(fs_volume _fs, fs_vnode _vnode, fs_cookie cookie)
static status_t
devfs_read_pages(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, off_t pos, const iovec *vecs, size_t count, size_t *_numBytes)
devfs_read_pages(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, off_t pos,
const iovec *vecs, size_t count, size_t *_numBytes, bool reenter)
{
struct devfs_vnode *vnode = (devfs_vnode *)_vnode;
struct devfs_cookie *cookie = (struct devfs_cookie *)_cookie;
@ -1663,7 +1664,8 @@ devfs_read_pages(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, off_t pos, c
static status_t
devfs_write_pages(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, off_t pos, const iovec *vecs, size_t count, size_t *_numBytes)
devfs_write_pages(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, off_t pos,
const iovec *vecs, size_t count, size_t *_numBytes, bool reenter)
{
struct devfs_vnode *vnode = (devfs_vnode *)_vnode;
struct devfs_cookie *cookie = (struct devfs_cookie *)_cookie;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2003-2006, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
@ -1571,14 +1571,16 @@ pipefs_can_page(fs_volume _volume, fs_vnode _v, fs_cookie cookie)
static status_t
pipefs_read_pages(fs_volume _volume, fs_vnode _v, fs_cookie cookie, off_t pos, const iovec *vecs, size_t count, size_t *_numBytes)
pipefs_read_pages(fs_volume _volume, fs_vnode _v, fs_cookie cookie, off_t pos,
const iovec *vecs, size_t count, size_t *_numBytes, bool reenter)
{
return EPERM;
}
static status_t
pipefs_write_pages(fs_volume _volume, fs_vnode _v, fs_cookie cookie, off_t pos, const iovec *vecs, size_t count, size_t *_numBytes)
pipefs_write_pages(fs_volume _volume, fs_vnode _v, fs_cookie cookie, off_t pos,
const iovec *vecs, size_t count, size_t *_numBytes, bool reenter)
{
return EPERM;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
@ -769,14 +769,16 @@ rootfs_can_page(fs_volume _fs, fs_vnode _v, fs_cookie cookie)
static status_t
rootfs_read_pages(fs_volume _fs, fs_vnode _v, fs_cookie cookie, off_t pos, const iovec *vecs, size_t count, size_t *_numBytes)
rootfs_read_pages(fs_volume _fs, fs_vnode _v, fs_cookie cookie, off_t pos,
const iovec *vecs, size_t count, size_t *_numBytes, bool reenter)
{
return B_NOT_ALLOWED;
}
static status_t
rootfs_write_pages(fs_volume _fs, fs_vnode _v, fs_cookie cookie, off_t pos, const iovec *vecs, size_t count, size_t *_numBytes)
rootfs_write_pages(fs_volume _fs, fs_vnode _v, fs_cookie cookie, off_t pos,
const iovec *vecs, size_t count, size_t *_numBytes, bool reenter)
{
return B_NOT_ALLOWED;
}

View File

@ -3005,24 +3005,28 @@ vfs_can_page(void *_vnode, void *cookie)
extern "C" status_t
vfs_read_pages(void *_vnode, void *cookie, off_t pos, const iovec *vecs, size_t count, size_t *_numBytes)
vfs_read_pages(void *_vnode, void *cookie, off_t pos, const iovec *vecs, size_t count,
size_t *_numBytes, bool fsReenter)
{
struct vnode *vnode = (struct vnode *)_vnode;
FUNCTION(("vfs_read_pages: vnode %p, vecs %p, pos %Ld\n", vnode, vecs, pos));
return FS_CALL(vnode, read_pages)(vnode->mount->cookie, vnode->private_node, cookie, pos, vecs, count, _numBytes);
return FS_CALL(vnode, read_pages)(vnode->mount->cookie, vnode->private_node,
cookie, pos, vecs, count, _numBytes, fsReenter);
}
extern "C" status_t
vfs_write_pages(void *_vnode, void *cookie, off_t pos, const iovec *vecs, size_t count, size_t *_numBytes)
vfs_write_pages(void *_vnode, void *cookie, off_t pos, const iovec *vecs, size_t count,
size_t *_numBytes, bool fsReenter)
{
struct vnode *vnode = (struct vnode *)_vnode;
FUNCTION(("vfs_write_pages: vnode %p, vecs %p, pos %Ld\n", vnode, vecs, pos));
return FS_CALL(vnode, write_pages)(vnode->mount->cookie, vnode->private_node, cookie, pos, vecs, count, _numBytes);
return FS_CALL(vnode, write_pages)(vnode->mount->cookie, vnode->private_node,
cookie, pos, vecs, count, _numBytes, fsReenter);
}

View File

@ -1382,7 +1382,7 @@ _vm_put_area(vm_area *area, bool aspaceLocked)
addressSpace = area->address_space;
// ToDo: do that only for vnode stores
vm_cache_write_modified(area->cache_ref);
vm_cache_write_modified(area->cache_ref, false);
arch_vm_unset_memory_type(area);
remove_area_from_address_space(addressSpace, area, aspaceLocked);
@ -2630,7 +2630,8 @@ vm_soft_fault(addr_t originalAddress, bool isWrite, bool isUser)
addressSpace->translation_map.ops->get_physical_page(page->physical_page_number * B_PAGE_SIZE, (addr_t *)&vec.iov_base, PHYSICAL_PAGE_CAN_WAIT);
// ToDo: handle errors here
err = cache_ref->cache->store->ops->read(cache_ref->cache->store, cacheOffset, &vec, 1, &bytesRead);
err = cache_ref->cache->store->ops->read(cache_ref->cache->store,
cacheOffset, &vec, 1, &bytesRead, false);
addressSpace->translation_map.ops->put_physical_page((addr_t)vec.iov_base);
mutex_lock(&cache_ref->lock);

View File

@ -311,14 +311,14 @@ vm_cache_remove_page(vm_cache_ref *cacheRef, vm_page *page)
status_t
vm_cache_write_modified(vm_cache_ref *ref)
vm_cache_write_modified(vm_cache_ref *ref, bool fsReenter)
{
status_t status;
TRACE(("vm_cache_write_modified(ref = %p)\n", ref));
mutex_lock(&ref->lock);
status = vm_page_write_modified(ref->cache);
status = vm_page_write_modified(ref->cache, fsReenter);
mutex_unlock(&ref->lock);
return status;

View File

@ -134,7 +134,7 @@ move_page_to_queue(page_queue *from_q, page_queue *to_q, vm_page *page)
static status_t
write_page(vm_page *page)
write_page(vm_page *page, bool fsReenter)
{
vm_store *store = page->cache->store;
size_t length = B_PAGE_SIZE;
@ -150,7 +150,7 @@ write_page(vm_page *page)
vecs->iov_len = B_PAGE_SIZE;
status = store->ops->write(store, (off_t)page->cache_offset << PAGE_SHIFT,
vecs, 1, &length);
vecs, 1, &length, fsReenter);
vm_put_physical_page((addr_t)vecs[0].iov_base);
@ -164,7 +164,7 @@ write_page(vm_page *page)
status_t
vm_page_write_modified(vm_cache *cache)
vm_page_write_modified(vm_cache *cache, bool fsReenter)
{
vm_page *page = cache->page_list;
@ -230,7 +230,7 @@ vm_page_write_modified(vm_cache *cache)
continue;
mutex_unlock(&cache->ref->lock);
status = write_page(page);
status = write_page(page, fsReenter);
mutex_lock(&cache->ref->lock);
if (status == B_OK) {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
@ -77,7 +77,8 @@ anonymous_has_page(struct vm_store *store, off_t offset)
static status_t
anonymous_read(struct vm_store *store, off_t offset, const iovec *vecs, size_t count, size_t *_numBytes)
anonymous_read(struct vm_store *store, off_t offset, const iovec *vecs, size_t count,
size_t *_numBytes, bool fsReenter)
{
panic("anonymous_store: read called. Invalid!\n");
return B_ERROR;
@ -85,7 +86,8 @@ anonymous_read(struct vm_store *store, off_t offset, const iovec *vecs, size_t c
static status_t
anonymous_write(struct vm_store *store, off_t offset, const iovec *vecs, size_t count, size_t *_numBytes)
anonymous_write(struct vm_store *store, off_t offset, const iovec *vecs, size_t count,
size_t *_numBytes, bool fsReenter)
{
// no place to write, this will cause the page daemon to skip this store
return 0;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2004-2006, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
@ -45,7 +45,8 @@ device_has_page(struct vm_store *store, off_t offset)
static status_t
device_read(struct vm_store *store, off_t offset, const iovec *vecs, size_t count, size_t *_numBytes)
device_read(struct vm_store *store, off_t offset, const iovec *vecs, size_t count,
size_t *_numBytes, bool fsReenter)
{
panic("device_store: read called. Invalid!\n");
return B_ERROR;
@ -53,7 +54,8 @@ device_read(struct vm_store *store, off_t offset, const iovec *vecs, size_t coun
static status_t
device_write(struct vm_store *store, off_t offset, const iovec *vecs, size_t count, size_t *_numBytes)
device_write(struct vm_store *store, off_t offset, const iovec *vecs, size_t count,
size_t *_numBytes, bool fsReenter)
{
// no place to write, this will cause the page daemon to skip this store
return B_OK;

View File

@ -1,7 +1,10 @@
/*
** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
** Distributed under the terms of the NewOS License.
*/
* Copyright 2004-2006, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
* Distributed under the terms of the NewOS License.
*/
#include "vm_store_null.h"
@ -32,14 +35,16 @@ null_has_page(struct vm_store *store, off_t offset)
static status_t
null_read(struct vm_store *store, off_t offset, const iovec *vecs, size_t count, size_t *_numBytes)
null_read(struct vm_store *store, off_t offset, const iovec *vecs, size_t count,
size_t *_numBytes, bool fsReenter)
{
return -1;
}
static status_t
null_write(struct vm_store *store, off_t offset, const iovec *vecs, size_t count, size_t *_numBytes)
null_write(struct vm_store *store, off_t offset, const iovec *vecs, size_t count,
size_t *_numBytes, bool fsReenter)
{
return -1;
}