* Extracted file_map API out of the file cache - it's now an optional service
that can be used by file systems.
* Changed the way the file cache works: instead of reading/writing to the
underlying device directly, it can now be used for any data source, ie.
also network file systems.
* As a result, the former pages_io() moved to the VFS layer, and can now be
called by a file system via {read|write}_file_io_vec_pages() (naming
suggestions are always welcomed :-)). It now gets an FD, and uses that to
communicate with the device (via its fs_{read|write}_pages() hooks).
* The file_cache_{read|write}() functions must now be called without holding
an I/O relevant file system lock. That allows the file cache to prepare the
pages without colliding with the page writer, IOW the "mayBlock" flag can
go into the attic again (yay!).
* This also results in a much better performance when the system does I/O and
is low on memory, as the page writer can now finally write back some pages,
and that even without maxing out the CPU :)
* The API changes put slightly more burden on the fs_{read|write}_pages()
hooks, but in combination with the file_map it's still pretty straight
forward. It just will have to dispatch the call to the underlying device
directly, usually it will just call its fs_{read|write}_pages() hooks
via the above mentioned calls.
* Ported BFS and FAT to the new API, the latter has not been tested, though.
* Also ported the API changes to the fs_shell. I also completely removed its
file cache level page handling - the downside is that device access is no
longer cached (ie. depends on the host OS now), the upside is that the code
is greatly simplified.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22886 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -56,23 +56,24 @@ extern status_t block_cache_set_dirty(void *_cache, off_t blockNumber,
|
|||||||
extern void block_cache_put(void *_cache, off_t blockNumber);
|
extern void block_cache_put(void *_cache, off_t blockNumber);
|
||||||
|
|
||||||
/* file cache */
|
/* file cache */
|
||||||
extern void *file_cache_create(dev_t mountID, ino_t vnodeID, off_t size,
|
extern void *file_cache_create(dev_t mountID, ino_t vnodeID, off_t size);
|
||||||
int fd);
|
|
||||||
extern void file_cache_delete(void *_cacheRef);
|
extern void file_cache_delete(void *_cacheRef);
|
||||||
extern status_t file_cache_set_size(void *_cacheRef, off_t size);
|
extern status_t file_cache_set_size(void *_cacheRef, off_t size);
|
||||||
extern status_t file_cache_sync(void *_cache);
|
extern status_t file_cache_sync(void *_cache);
|
||||||
extern status_t file_cache_invalidate_file_map(void *_cacheRef, off_t offset,
|
|
||||||
off_t size);
|
|
||||||
|
|
||||||
extern status_t file_cache_read_pages(void *_cacheRef, off_t offset,
|
extern status_t file_cache_read(void *_cacheRef, void *cookie, off_t offset,
|
||||||
const iovec *vecs, size_t count, size_t *_numBytes);
|
void *bufferBase, size_t *_size);
|
||||||
extern status_t file_cache_write_pages(void *_cacheRef, off_t offset,
|
extern status_t file_cache_write(void *_cacheRef, void *cookie, off_t offset,
|
||||||
const iovec *vecs, size_t count, size_t *_numBytes);
|
|
||||||
extern status_t file_cache_read(void *_cacheRef, off_t offset, void *bufferBase,
|
|
||||||
size_t *_size);
|
|
||||||
extern status_t file_cache_write(void *_cacheRef, off_t offset,
|
|
||||||
const void *buffer, size_t *_size);
|
const void *buffer, size_t *_size);
|
||||||
|
|
||||||
|
/* file map */
|
||||||
|
extern void *file_map_create(dev_t mountID, ino_t vnodeID);
|
||||||
|
extern void file_map_delete(void *_map);
|
||||||
|
extern void file_map_set_size(void *_map, off_t size);
|
||||||
|
extern void file_map_invalidate(void *_map, off_t offset, off_t size);
|
||||||
|
extern status_t file_map_translate(void *_map, off_t offset, size_t size,
|
||||||
|
struct file_io_vec *vecs, size_t *_count);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -92,10 +92,10 @@ typedef struct file_system_module_info {
|
|||||||
bool (*can_page)(fs_volume fs, fs_vnode vnode, fs_cookie cookie);
|
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,
|
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,
|
off_t pos, const iovec *vecs, size_t count, size_t *_numBytes,
|
||||||
bool mayBlock, bool reenter);
|
bool reenter);
|
||||||
status_t (*write_pages)(fs_volume fs, fs_vnode vnode, fs_cookie cookie,
|
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,
|
off_t pos, const iovec *vecs, size_t count, size_t *_numBytes,
|
||||||
bool mayBlock, bool reenter);
|
bool reenter);
|
||||||
|
|
||||||
/* cache file access */
|
/* cache file access */
|
||||||
status_t (*get_file_map)(fs_volume fs, fs_vnode vnode, off_t offset,
|
status_t (*get_file_map)(fs_volume fs, fs_vnode vnode, off_t offset,
|
||||||
@@ -251,6 +251,18 @@ extern status_t remove_vnode(dev_t mountID, ino_t vnodeID);
|
|||||||
extern status_t unremove_vnode(dev_t mountID, ino_t vnodeID);
|
extern status_t unremove_vnode(dev_t mountID, ino_t vnodeID);
|
||||||
extern status_t get_vnode_removed(dev_t mountID, ino_t vnodeID,
|
extern status_t get_vnode_removed(dev_t mountID, ino_t vnodeID,
|
||||||
bool* removed);
|
bool* removed);
|
||||||
|
extern status_t read_pages(int fd, off_t pos, const struct iovec *vecs,
|
||||||
|
size_t count, size_t *_numBytes, bool fsReenter);
|
||||||
|
extern status_t write_pages(int fd, off_t pos, const struct iovec *vecs,
|
||||||
|
size_t count, size_t *_numBytes, bool fsReenter);
|
||||||
|
extern status_t read_file_io_vec_pages(int fd,
|
||||||
|
const struct file_io_vec *fileVecs, size_t fileVecCount,
|
||||||
|
const struct iovec *vecs, size_t vecCount,
|
||||||
|
uint32 *_vecIndex, size_t *_vecOffset, size_t *_bytes);
|
||||||
|
extern status_t write_file_io_vec_pages(int fd,
|
||||||
|
const struct file_io_vec *fileVecs, size_t fileVecCount,
|
||||||
|
const struct iovec *vecs, size_t vecCount,
|
||||||
|
uint32 *_vecIndex, size_t *_vecOffset, size_t *_bytes);
|
||||||
|
|
||||||
// Deprecated! Will disappear soon!
|
// Deprecated! Will disappear soon!
|
||||||
extern status_t notify_listener(int op, dev_t device, ino_t parentNode,
|
extern status_t notify_listener(int op, dev_t device, ino_t parentNode,
|
||||||
|
|||||||
@@ -820,13 +820,16 @@
|
|||||||
#define file_cache_delete fssh_file_cache_delete
|
#define file_cache_delete fssh_file_cache_delete
|
||||||
#define file_cache_set_size fssh_file_cache_set_size
|
#define file_cache_set_size fssh_file_cache_set_size
|
||||||
#define file_cache_sync fssh_file_cache_sync
|
#define file_cache_sync fssh_file_cache_sync
|
||||||
#define file_cache_invalidate_file_map fssh_file_cache_invalidate_file_map
|
|
||||||
|
|
||||||
#define file_cache_read_pages fssh_file_cache_read_pages
|
|
||||||
#define file_cache_write_pages fssh_file_cache_write_pages
|
|
||||||
#define file_cache_read fssh_file_cache_read
|
#define file_cache_read fssh_file_cache_read
|
||||||
#define file_cache_write fssh_file_cache_write
|
#define file_cache_write fssh_file_cache_write
|
||||||
|
|
||||||
|
/* file map */
|
||||||
|
#define file_map_create fssh_file_map_create
|
||||||
|
#define file_map_delete fssh_file_map_delete
|
||||||
|
#define file_map_set_size fssh_file_map_set_size
|
||||||
|
#define file_map_invalidate fssh_file_map_invalidate
|
||||||
|
#define file_map_translate fssh_file_map_translate
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// #pragma mark - fssh_fs_index.h
|
// #pragma mark - fssh_fs_index.h
|
||||||
@@ -893,6 +896,10 @@
|
|||||||
#define remove_vnode fssh_remove_vnode
|
#define remove_vnode fssh_remove_vnode
|
||||||
#define unremove_vnode fssh_unremove_vnode
|
#define unremove_vnode fssh_unremove_vnode
|
||||||
#define get_vnode_removed fssh_get_vnode_removed
|
#define get_vnode_removed fssh_get_vnode_removed
|
||||||
|
#define read_pages fssh_read_pages
|
||||||
|
#define write_pages fssh_write_pages
|
||||||
|
#define read_file_io_vec_pages fssh_read_file_io_vec_pages
|
||||||
|
#define write_file_io_vec_pages fssh_write_file_io_vec_pages
|
||||||
|
|
||||||
#define notify_entry_created fssh_notify_entry_created
|
#define notify_entry_created fssh_notify_entry_created
|
||||||
#define notify_entry_removed fssh_notify_entry_removed
|
#define notify_entry_removed fssh_notify_entry_removed
|
||||||
|
|||||||
@@ -69,26 +69,30 @@ extern void fssh_block_cache_put(void *_cache,
|
|||||||
|
|
||||||
/* file cache */
|
/* file cache */
|
||||||
extern void * fssh_file_cache_create(fssh_mount_id mountID,
|
extern void * fssh_file_cache_create(fssh_mount_id mountID,
|
||||||
fssh_vnode_id vnodeID, fssh_off_t size, int fd);
|
fssh_vnode_id vnodeID, fssh_off_t size);
|
||||||
extern void fssh_file_cache_delete(void *_cacheRef);
|
extern void fssh_file_cache_delete(void *_cacheRef);
|
||||||
extern fssh_status_t fssh_file_cache_set_size(void *_cacheRef,
|
extern fssh_status_t fssh_file_cache_set_size(void *_cacheRef,
|
||||||
fssh_off_t size);
|
fssh_off_t size);
|
||||||
extern fssh_status_t fssh_file_cache_sync(void *_cache);
|
extern fssh_status_t fssh_file_cache_sync(void *_cache);
|
||||||
extern fssh_status_t fssh_file_cache_invalidate_file_map(void *_cacheRef,
|
|
||||||
fssh_off_t offset, fssh_off_t size);
|
|
||||||
|
|
||||||
extern fssh_status_t fssh_file_cache_read_pages(void *_cacheRef,
|
extern fssh_status_t fssh_file_cache_read(void *_cacheRef, void *cookie,
|
||||||
fssh_off_t offset, const fssh_iovec *vecs,
|
fssh_off_t offset, void *bufferBase,
|
||||||
fssh_size_t count, fssh_size_t *_numBytes);
|
fssh_size_t *_size);
|
||||||
extern fssh_status_t fssh_file_cache_write_pages(void *_cacheRef,
|
extern fssh_status_t fssh_file_cache_write(void *_cacheRef, void *cookie,
|
||||||
fssh_off_t offset, const fssh_iovec *vecs,
|
|
||||||
fssh_size_t count, fssh_size_t *_numBytes);
|
|
||||||
extern fssh_status_t fssh_file_cache_read(void *_cacheRef, fssh_off_t offset,
|
|
||||||
void *bufferBase, fssh_size_t *_size);
|
|
||||||
extern fssh_status_t fssh_file_cache_write(void *_cacheRef,
|
|
||||||
fssh_off_t offset, const void *buffer,
|
fssh_off_t offset, const void *buffer,
|
||||||
fssh_size_t *_size);
|
fssh_size_t *_size);
|
||||||
|
|
||||||
|
/* file map */
|
||||||
|
extern void * fssh_file_map_create(fssh_mount_id mountID,
|
||||||
|
fssh_vnode_id vnodeID);
|
||||||
|
extern void fssh_file_map_delete(void *_map);
|
||||||
|
extern void fssh_file_map_set_size(void *_map, fssh_off_t size);
|
||||||
|
extern void fssh_file_map_invalidate(void *_map, fssh_off_t offset,
|
||||||
|
fssh_off_t size);
|
||||||
|
extern fssh_status_t fssh_file_map_translate(void *_map, fssh_off_t offset,
|
||||||
|
fssh_size_t size, struct fssh_file_io_vec *vecs,
|
||||||
|
fssh_size_t *_count);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -96,12 +96,10 @@ typedef struct fssh_file_system_module_info {
|
|||||||
fssh_fs_cookie cookie);
|
fssh_fs_cookie cookie);
|
||||||
fssh_status_t (*read_pages)(fssh_fs_volume fs, fssh_fs_vnode vnode,
|
fssh_status_t (*read_pages)(fssh_fs_volume fs, fssh_fs_vnode vnode,
|
||||||
fssh_fs_cookie cookie, fssh_off_t pos, const fssh_iovec *vecs,
|
fssh_fs_cookie cookie, fssh_off_t pos, const fssh_iovec *vecs,
|
||||||
fssh_size_t count, fssh_size_t *_numBytes, bool mayBlock,
|
fssh_size_t count, fssh_size_t *_numBytes, bool reenter);
|
||||||
bool reenter);
|
|
||||||
fssh_status_t (*write_pages)(fssh_fs_volume fs, fssh_fs_vnode vnode,
|
fssh_status_t (*write_pages)(fssh_fs_volume fs, fssh_fs_vnode vnode,
|
||||||
fssh_fs_cookie cookie, fssh_off_t pos, const fssh_iovec *vecs,
|
fssh_fs_cookie cookie, fssh_off_t pos, const fssh_iovec *vecs,
|
||||||
fssh_size_t count, fssh_size_t *_numBytes, bool mayBlock,
|
fssh_size_t count, fssh_size_t *_numBytes, bool reenter);
|
||||||
bool reenter);
|
|
||||||
|
|
||||||
/* cache file access */
|
/* cache file access */
|
||||||
fssh_status_t (*get_file_map)(fssh_fs_volume fs, fssh_fs_vnode vnode,
|
fssh_status_t (*get_file_map)(fssh_fs_volume fs, fssh_fs_vnode vnode,
|
||||||
@@ -293,6 +291,22 @@ extern fssh_status_t fssh_unremove_vnode(fssh_mount_id mountID,
|
|||||||
fssh_vnode_id vnodeID);
|
fssh_vnode_id vnodeID);
|
||||||
extern fssh_status_t fssh_get_vnode_removed(fssh_mount_id mountID,
|
extern fssh_status_t fssh_get_vnode_removed(fssh_mount_id mountID,
|
||||||
fssh_vnode_id vnodeID, bool* removed);
|
fssh_vnode_id vnodeID, bool* removed);
|
||||||
|
extern fssh_status_t fssh_read_pages(int fd, fssh_off_t pos,
|
||||||
|
const struct fssh_iovec *vecs, fssh_size_t count,
|
||||||
|
fssh_size_t *_numBytes, bool fsReenter);
|
||||||
|
extern fssh_status_t fssh_write_pages(int fd, fssh_off_t pos,
|
||||||
|
const struct fssh_iovec *vecs, fssh_size_t count,
|
||||||
|
fssh_size_t *_numBytes, bool fsReenter);
|
||||||
|
extern fssh_status_t fssh_read_file_io_vec_pages(int fd,
|
||||||
|
const struct fssh_file_io_vec *fileVecs,
|
||||||
|
fssh_size_t fileVecCount, const struct fssh_iovec *vecs,
|
||||||
|
fssh_size_t vecCount, uint32_t *_vecIndex,
|
||||||
|
fssh_size_t *_vecOffset, fssh_size_t *_bytes);
|
||||||
|
extern fssh_status_t fssh_write_file_io_vec_pages(int fd,
|
||||||
|
const struct fssh_file_io_vec *fileVecs,
|
||||||
|
fssh_size_t fileVecCount, const struct fssh_iovec *vecs,
|
||||||
|
fssh_size_t vecCount, uint32_t *_vecIndex,
|
||||||
|
fssh_size_t *_vecOffset, fssh_size_t *_bytes);
|
||||||
|
|
||||||
extern fssh_status_t fssh_notify_entry_created(fssh_mount_id device,
|
extern fssh_status_t fssh_notify_entry_created(fssh_mount_id device,
|
||||||
fssh_vnode_id directory, const char *name, fssh_vnode_id node);
|
fssh_vnode_id directory, const char *name, fssh_vnode_id node);
|
||||||
|
|||||||
@@ -94,11 +94,9 @@ void vfs_acquire_vnode(struct vnode *vnode);
|
|||||||
status_t vfs_get_cookie_from_fd(int fd, void **_cookie);
|
status_t vfs_get_cookie_from_fd(int fd, void **_cookie);
|
||||||
bool vfs_can_page(struct vnode *vnode, void *cookie);
|
bool vfs_can_page(struct vnode *vnode, void *cookie);
|
||||||
status_t vfs_read_pages(struct vnode *vnode, void *cookie, off_t pos,
|
status_t vfs_read_pages(struct vnode *vnode, void *cookie, off_t pos,
|
||||||
const iovec *vecs, size_t count, size_t *_numBytes, bool mayBlock,
|
const iovec *vecs, size_t count, size_t *_numBytes, bool fsReenter);
|
||||||
bool fsReenter);
|
|
||||||
status_t vfs_write_pages(struct vnode *vnode, void *cookie, off_t pos,
|
status_t vfs_write_pages(struct vnode *vnode, void *cookie, off_t pos,
|
||||||
const iovec *vecs, size_t count, size_t *_numBytes, bool mayBlock,
|
const iovec *vecs, size_t count, size_t *_numBytes, bool fsReenter);
|
||||||
bool fsReenter);
|
|
||||||
status_t vfs_get_vnode_cache(struct vnode *vnode, struct vm_cache **_cache,
|
status_t vfs_get_vnode_cache(struct vnode *vnode, struct vm_cache **_cache,
|
||||||
bool allocate);
|
bool allocate);
|
||||||
status_t vfs_get_file_map(struct vnode *vnode, off_t offset, size_t size,
|
status_t vfs_get_file_map(struct vnode *vnode, off_t offset, size_t size,
|
||||||
|
|||||||
@@ -223,11 +223,9 @@ typedef struct vm_store_ops {
|
|||||||
status_t (*commit)(struct vm_store *backingStore, off_t size);
|
status_t (*commit)(struct vm_store *backingStore, off_t size);
|
||||||
bool (*has_page)(struct vm_store *backingStore, off_t offset);
|
bool (*has_page)(struct vm_store *backingStore, off_t offset);
|
||||||
status_t (*read)(struct vm_store *backingStore, off_t offset,
|
status_t (*read)(struct vm_store *backingStore, off_t offset,
|
||||||
const iovec *vecs, size_t count, size_t *_numBytes, bool mayBlock,
|
const iovec *vecs, size_t count, size_t *_numBytes, bool fsReenter);
|
||||||
bool fsReenter);
|
|
||||||
status_t (*write)(struct vm_store *backingStore, off_t offset,
|
status_t (*write)(struct vm_store *backingStore, off_t offset,
|
||||||
const iovec *vecs, size_t count, size_t *_numBytes, bool mayBlock,
|
const iovec *vecs, size_t count, size_t *_numBytes, bool fsReenter);
|
||||||
bool fsReenter);
|
|
||||||
status_t (*fault)(struct vm_store *backingStore,
|
status_t (*fault)(struct vm_store *backingStore,
|
||||||
struct vm_address_space *aspace, off_t offset);
|
struct vm_address_space *aspace, off_t offset);
|
||||||
status_t (*acquire_unreferenced_ref)(struct vm_store *backingStore);
|
status_t (*acquire_unreferenced_ref)(struct vm_store *backingStore);
|
||||||
|
|||||||
@@ -47,7 +47,7 @@
|
|||||||
// D()
|
// D()
|
||||||
// the statements in D() are only included if DEBUG is defined
|
// the statements in D() are only included if DEBUG is defined
|
||||||
|
|
||||||
#ifdef DEBUG
|
#if 0//DEBUG
|
||||||
#define PRINT(x) { __out("bfs: "); __out x; }
|
#define PRINT(x) { __out("bfs: "); __out x; }
|
||||||
#define REPORT_ERROR(status) \
|
#define REPORT_ERROR(status) \
|
||||||
__out("bfs: %s:%d: %s\n", __FUNCTION__, __LINE__, strerror(status));
|
__out("bfs: %s:%d: %s\n", __FUNCTION__, __LINE__, strerror(status));
|
||||||
|
|||||||
@@ -171,7 +171,8 @@ Inode::Inode(Volume *volume, ino_t id)
|
|||||||
fID(id),
|
fID(id),
|
||||||
fTree(NULL),
|
fTree(NULL),
|
||||||
fAttributes(NULL),
|
fAttributes(NULL),
|
||||||
fCache(NULL)
|
fCache(NULL),
|
||||||
|
fMap(NULL)
|
||||||
{
|
{
|
||||||
PRINT(("Inode::Inode(volume = %p, id = %Ld) @ %p\n", volume, id, this));
|
PRINT(("Inode::Inode(volume = %p, id = %Ld) @ %p\n", volume, id, this));
|
||||||
|
|
||||||
@@ -189,8 +190,10 @@ Inode::Inode(Volume *volume, ino_t id)
|
|||||||
|
|
||||||
if (IsContainer())
|
if (IsContainer())
|
||||||
fTree = new BPlusTree(this);
|
fTree = new BPlusTree(this);
|
||||||
if (IsFile() || IsAttribute())
|
if (IsFile() || IsAttribute()) {
|
||||||
SetFileCache(file_cache_create(fVolume->ID(), ID(), Size(), fVolume->Device()));
|
SetFileCache(file_cache_create(fVolume->ID(), ID(), Size()));
|
||||||
|
SetMap(file_map_create(volume->ID(), ID()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -201,7 +204,8 @@ Inode::Inode(Volume *volume, Transaction &transaction, ino_t id, mode_t mode,
|
|||||||
fID(id),
|
fID(id),
|
||||||
fTree(NULL),
|
fTree(NULL),
|
||||||
fAttributes(NULL),
|
fAttributes(NULL),
|
||||||
fCache(NULL)
|
fCache(NULL),
|
||||||
|
fMap(NULL)
|
||||||
{
|
{
|
||||||
PRINT(("Inode::Inode(volume = %p, transaction = %p, id = %Ld) @ %p\n",
|
PRINT(("Inode::Inode(volume = %p, transaction = %p, id = %Ld) @ %p\n",
|
||||||
volume, &transaction, id, this));
|
volume, &transaction, id, this));
|
||||||
@@ -242,6 +246,7 @@ Inode::~Inode()
|
|||||||
PRINT(("Inode::~Inode() @ %p\n", this));
|
PRINT(("Inode::~Inode() @ %p\n", this));
|
||||||
|
|
||||||
file_cache_delete(FileCache());
|
file_cache_delete(FileCache());
|
||||||
|
file_map_delete(Map());
|
||||||
delete fTree;
|
delete fTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,8 +389,8 @@ Inode::_MakeSpaceForSmallData(Transaction &transaction, bfs_inode *node,
|
|||||||
// Luckily, this doesn't cause any index updates
|
// Luckily, this doesn't cause any index updates
|
||||||
|
|
||||||
Inode *attribute;
|
Inode *attribute;
|
||||||
status_t status = CreateAttribute(transaction, item->Name(), item->Type(),
|
status_t status = CreateAttribute(transaction, item->Name(),
|
||||||
&attribute);
|
item->Type(), &attribute);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
RETURN_ERROR(status);
|
RETURN_ERROR(status);
|
||||||
|
|
||||||
@@ -1233,12 +1238,16 @@ Inode::ReadAt(off_t pos, uint8 *buffer, size_t *_length)
|
|||||||
if (pos < 0)
|
if (pos < 0)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
ReadLocked locker(Lock());
|
||||||
|
|
||||||
if (pos >= Size() || length == 0) {
|
if (pos >= Size() || length == 0) {
|
||||||
*_length = 0;
|
*_length = 0;
|
||||||
return B_NO_ERROR;
|
return B_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return file_cache_read(FileCache(), pos, buffer, _length);
|
locker.Unlock();
|
||||||
|
|
||||||
|
return file_cache_read(FileCache(), NULL, pos, buffer, _length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1246,6 +1255,10 @@ status_t
|
|||||||
Inode::WriteAt(Transaction &transaction, off_t pos, const uint8 *buffer,
|
Inode::WriteAt(Transaction &transaction, off_t pos, const uint8 *buffer,
|
||||||
size_t *_length)
|
size_t *_length)
|
||||||
{
|
{
|
||||||
|
WriteLocked locker(Lock());
|
||||||
|
if (locker.IsLocked() < B_OK)
|
||||||
|
RETURN_ERROR(B_ERROR);
|
||||||
|
|
||||||
// update the last modification time in memory, it will be written
|
// update the last modification time in memory, it will be written
|
||||||
// back to the inode, and the index when the file is closed
|
// back to the inode, and the index when the file is closed
|
||||||
// ToDo: should update the internal last modified time only at this point!
|
// ToDo: should update the internal last modified time only at this point!
|
||||||
@@ -1298,7 +1311,9 @@ Inode::WriteAt(Transaction &transaction, off_t pos, const uint8 *buffer,
|
|||||||
if (length == 0)
|
if (length == 0)
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
return file_cache_write(FileCache(), pos, buffer, _length);
|
locker.Unlock();
|
||||||
|
|
||||||
|
return file_cache_write(FileCache(), NULL, pos, buffer, _length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1945,6 +1960,8 @@ Inode::SetFileSize(Transaction &transaction, off_t size)
|
|||||||
return status;
|
return status;
|
||||||
|
|
||||||
file_cache_set_size(FileCache(), size);
|
file_cache_set_size(FileCache(), size);
|
||||||
|
file_map_set_size(Map(), size);
|
||||||
|
|
||||||
return WriteBack(transaction);
|
return WriteBack(transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2400,7 +2417,8 @@ Inode::Create(Transaction &transaction, Inode *parent, const char *name,
|
|||||||
|
|
||||||
if (inode->IsFile() || inode->IsAttribute()) {
|
if (inode->IsFile() || inode->IsAttribute()) {
|
||||||
inode->SetFileCache(file_cache_create(volume->ID(), inode->ID(),
|
inode->SetFileCache(file_cache_create(volume->ID(), inode->ID(),
|
||||||
inode->Size(), volume->Device()));
|
inode->Size()));
|
||||||
|
inode->SetMap(file_map_create(volume->ID(), inode->ID()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_created)
|
if (_created)
|
||||||
|
|||||||
@@ -156,6 +156,8 @@ class Inode {
|
|||||||
// file cache
|
// file cache
|
||||||
void *FileCache() const { return fCache; }
|
void *FileCache() const { return fCache; }
|
||||||
void SetFileCache(void *cache) { fCache = cache; }
|
void SetFileCache(void *cache) { fCache = cache; }
|
||||||
|
void *Map() const { return fMap; }
|
||||||
|
void SetMap(void *map) { fMap = map; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Inode(const Inode &);
|
Inode(const Inode &);
|
||||||
@@ -198,6 +200,7 @@ class Inode {
|
|||||||
BPlusTree *fTree;
|
BPlusTree *fTree;
|
||||||
Inode *fAttributes;
|
Inode *fAttributes;
|
||||||
void *fCache;
|
void *fCache;
|
||||||
|
void *fMap;
|
||||||
bfs_inode fNode;
|
bfs_inode fNode;
|
||||||
|
|
||||||
off_t fOldSize;
|
off_t fOldSize;
|
||||||
|
|||||||
@@ -447,11 +447,19 @@ class ReadLocked {
|
|||||||
fLock.Unlock();
|
fLock.Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t IsLocked()
|
status_t
|
||||||
|
IsLocked()
|
||||||
{
|
{
|
||||||
return fStatus;
|
return fStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Unlock()
|
||||||
|
{
|
||||||
|
fLock.Unlock();
|
||||||
|
fStatus = B_NO_INIT;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ReadWriteLock &fLock;
|
ReadWriteLock &fLock;
|
||||||
status_t fStatus;
|
status_t fStatus;
|
||||||
@@ -480,11 +488,19 @@ class WriteLocked {
|
|||||||
fLock->UnlockWrite();
|
fLock->UnlockWrite();
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t IsLocked()
|
status_t
|
||||||
|
IsLocked()
|
||||||
{
|
{
|
||||||
return fStatus;
|
return fStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Unlock()
|
||||||
|
{
|
||||||
|
fLock->UnlockWrite();
|
||||||
|
fStatus = B_NO_INIT;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ReadWriteLock *fLock;
|
ReadWriteLock *fLock;
|
||||||
status_t fStatus;
|
status_t fStatus;
|
||||||
|
|||||||
@@ -331,23 +331,42 @@ bfs_can_page(fs_volume _fs, fs_vnode _v, fs_cookie _cookie)
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
bfs_read_pages(fs_volume _fs, fs_vnode _node, fs_cookie _cookie, off_t pos,
|
bfs_read_pages(fs_volume _fs, fs_vnode _node, fs_cookie _cookie, off_t pos,
|
||||||
const iovec *vecs, size_t count, size_t *_numBytes, bool mayBlock,
|
const iovec *vecs, size_t count, size_t *_numBytes, bool reenter)
|
||||||
bool reenter)
|
|
||||||
{
|
{
|
||||||
|
Volume *volume = (Volume *)_fs;
|
||||||
Inode *inode = (Inode *)_node;
|
Inode *inode = (Inode *)_node;
|
||||||
|
|
||||||
if (inode->FileCache() == NULL)
|
if (inode->FileCache() == NULL)
|
||||||
RETURN_ERROR(B_BAD_VALUE);
|
RETURN_ERROR(B_BAD_VALUE);
|
||||||
|
|
||||||
if (!reenter) {
|
if (!reenter)
|
||||||
if (mayBlock)
|
|
||||||
inode->Lock().Lock();
|
inode->Lock().Lock();
|
||||||
else if (inode->Lock().TryLock() < B_OK)
|
|
||||||
return B_WOULD_BLOCK;
|
|
||||||
}
|
|
||||||
|
|
||||||
status_t status = file_cache_read_pages(inode->FileCache(), pos, vecs,
|
uint32 vecIndex = 0;
|
||||||
count, _numBytes);
|
size_t vecOffset = 0;
|
||||||
|
size_t bytesLeft = *_numBytes;
|
||||||
|
status_t status;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
file_io_vec fileVecs[8];
|
||||||
|
uint32 fileVecCount = 8;
|
||||||
|
|
||||||
|
status = file_map_translate(inode->Map(), pos, bytesLeft, fileVecs,
|
||||||
|
&fileVecCount);
|
||||||
|
if (status != B_OK && status != B_BUFFER_OVERFLOW)
|
||||||
|
break;
|
||||||
|
|
||||||
|
bool bufferOverflow = status == B_BUFFER_OVERFLOW;
|
||||||
|
|
||||||
|
size_t bytes;
|
||||||
|
status = read_file_io_vec_pages(volume->Device(), fileVecs,
|
||||||
|
fileVecCount, vecs, count, &vecIndex, &vecOffset, &bytes);
|
||||||
|
if (status != B_OK || !bufferOverflow)
|
||||||
|
break;
|
||||||
|
|
||||||
|
pos += bytes;
|
||||||
|
bytesLeft -= bytes;
|
||||||
|
}
|
||||||
|
|
||||||
if (!reenter)
|
if (!reenter)
|
||||||
inode->Lock().Unlock();
|
inode->Lock().Unlock();
|
||||||
@@ -358,23 +377,42 @@ bfs_read_pages(fs_volume _fs, fs_vnode _node, fs_cookie _cookie, off_t pos,
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
bfs_write_pages(fs_volume _fs, fs_vnode _node, fs_cookie _cookie, off_t pos,
|
bfs_write_pages(fs_volume _fs, fs_vnode _node, fs_cookie _cookie, off_t pos,
|
||||||
const iovec *vecs, size_t count, size_t *_numBytes, bool mayBlock,
|
const iovec *vecs, size_t count, size_t *_numBytes, bool reenter)
|
||||||
bool reenter)
|
|
||||||
{
|
{
|
||||||
|
Volume *volume = (Volume *)_fs;
|
||||||
Inode *inode = (Inode *)_node;
|
Inode *inode = (Inode *)_node;
|
||||||
|
|
||||||
if (inode->FileCache() == NULL)
|
if (inode->FileCache() == NULL)
|
||||||
RETURN_ERROR(B_BAD_VALUE);
|
RETURN_ERROR(B_BAD_VALUE);
|
||||||
|
|
||||||
if (!reenter) {
|
if (!reenter)
|
||||||
if (mayBlock)
|
|
||||||
inode->Lock().Lock();
|
inode->Lock().Lock();
|
||||||
else if (inode->Lock().TryLock() < B_OK)
|
|
||||||
return B_WOULD_BLOCK;
|
|
||||||
}
|
|
||||||
|
|
||||||
status_t status = file_cache_write_pages(inode->FileCache(), pos, vecs,
|
uint32 vecIndex = 0;
|
||||||
count, _numBytes);
|
size_t vecOffset = 0;
|
||||||
|
size_t bytesLeft = *_numBytes;
|
||||||
|
status_t status;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
file_io_vec fileVecs[8];
|
||||||
|
uint32 fileVecCount = 8;
|
||||||
|
|
||||||
|
status = file_map_translate(inode->Map(), pos, bytesLeft, fileVecs,
|
||||||
|
&fileVecCount);
|
||||||
|
if (status != B_OK && status != B_BUFFER_OVERFLOW)
|
||||||
|
break;
|
||||||
|
|
||||||
|
bool bufferOverflow = status == B_BUFFER_OVERFLOW;
|
||||||
|
|
||||||
|
size_t bytes;
|
||||||
|
status = write_file_io_vec_pages(volume->Device(), fileVecs,
|
||||||
|
fileVecCount, vecs, count, &vecIndex, &vecOffset, &bytes);
|
||||||
|
if (status != B_OK || !bufferOverflow)
|
||||||
|
break;
|
||||||
|
|
||||||
|
pos += bytes;
|
||||||
|
bytesLeft -= bytes;
|
||||||
|
}
|
||||||
|
|
||||||
if (!reenter)
|
if (!reenter)
|
||||||
inode->Lock().Unlock();
|
inode->Lock().Unlock();
|
||||||
@@ -818,8 +856,8 @@ bfs_create_symlink(void *_ns, void *_directory, const char *name,
|
|||||||
| INODE_LOGGED);
|
| INODE_LOGGED);
|
||||||
|
|
||||||
// links usually don't have a file cache attached - but we now need one
|
// links usually don't have a file cache attached - but we now need one
|
||||||
link->SetFileCache(file_cache_create(volume->ID(), link->ID(), 0,
|
link->SetFileCache(file_cache_create(volume->ID(), link->ID(), 0));
|
||||||
volume->Device()));
|
link->SetMap(file_map_create(volume->ID(), link->ID()));
|
||||||
|
|
||||||
// The following call will have to write the inode back, so
|
// The following call will have to write the inode back, so
|
||||||
// we don't have to do that here...
|
// we don't have to do that here...
|
||||||
@@ -1067,9 +1105,6 @@ bfs_rename(void *_ns, void *_oldDir, const char *oldName, void *_newDir, const c
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Opens the file with the specified mode.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
bfs_open(void *_fs, void *_node, int openMode, void **_cookie)
|
bfs_open(void *_fs, void *_node, int openMode, void **_cookie)
|
||||||
{
|
{
|
||||||
@@ -1133,12 +1168,9 @@ bfs_open(void *_fs, void *_node, int openMode, void **_cookie)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Read a file specified by node, using information in cookie
|
|
||||||
* and at offset specified by pos. read len bytes into buffer buf.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
bfs_read(void *_ns, void *_node, void *_cookie, off_t pos, void *buffer, size_t *_length)
|
bfs_read(void *_ns, void *_node, void *_cookie, off_t pos, void *buffer,
|
||||||
|
size_t *_length)
|
||||||
{
|
{
|
||||||
//FUNCTION();
|
//FUNCTION();
|
||||||
Inode *inode = (Inode *)_node;
|
Inode *inode = (Inode *)_node;
|
||||||
@@ -1148,19 +1180,15 @@ bfs_read(void *_ns, void *_node, void *_cookie, off_t pos, void *buffer, size_t
|
|||||||
RETURN_ERROR(B_BAD_VALUE);
|
RETURN_ERROR(B_BAD_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadLocked locked(inode->Lock());
|
|
||||||
return inode->ReadAt(pos, (uint8 *)buffer, _length);
|
return inode->ReadAt(pos, (uint8 *)buffer, _length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
bfs_write(void *_ns, void *_node, void *_cookie, off_t pos, const void *buffer, size_t *_length)
|
bfs_write(void *_ns, void *_node, void *_cookie, off_t pos, const void *buffer,
|
||||||
|
size_t *_length)
|
||||||
{
|
{
|
||||||
//FUNCTION();
|
//FUNCTION();
|
||||||
// uncomment to be more robust against a buggy vnode layer ;-)
|
|
||||||
//if (_ns == NULL || _node == NULL || _cookie == NULL)
|
|
||||||
// return B_BAD_VALUE;
|
|
||||||
|
|
||||||
Volume *volume = (Volume *)_ns;
|
Volume *volume = (Volume *)_ns;
|
||||||
Inode *inode = (Inode *)_node;
|
Inode *inode = (Inode *)_node;
|
||||||
|
|
||||||
@@ -1174,21 +1202,20 @@ bfs_write(void *_ns, void *_node, void *_cookie, off_t pos, const void *buffer,
|
|||||||
if (cookie->open_mode & O_APPEND)
|
if (cookie->open_mode & O_APPEND)
|
||||||
pos = inode->Size();
|
pos = inode->Size();
|
||||||
|
|
||||||
WriteLocked locked(inode->Lock());
|
|
||||||
if (locked.IsLocked() < B_OK)
|
|
||||||
RETURN_ERROR(B_ERROR);
|
|
||||||
|
|
||||||
Transaction transaction;
|
Transaction transaction;
|
||||||
// We are not starting the transaction here, since
|
// We are not starting the transaction here, since
|
||||||
// it might not be needed at all (the contents of
|
// it might not be needed at all (the contents of
|
||||||
// regular files aren't logged)
|
// regular files aren't logged)
|
||||||
|
|
||||||
status_t status = inode->WriteAt(transaction, pos, (const uint8 *)buffer, _length);
|
status_t status = inode->WriteAt(transaction, pos, (const uint8 *)buffer,
|
||||||
|
_length);
|
||||||
|
|
||||||
if (status == B_OK)
|
if (status == B_OK)
|
||||||
transaction.Done();
|
transaction.Done();
|
||||||
|
|
||||||
if (status == B_OK) {
|
if (status == B_OK) {
|
||||||
|
ReadLocked locker(inode->Lock());
|
||||||
|
|
||||||
// periodically notify if the file size has changed
|
// periodically notify if the file size has changed
|
||||||
// ToDo: should we better test for a change in the last_modified time only?
|
// ToDo: should we better test for a change in the last_modified time only?
|
||||||
if (!inode->IsDeleted() && cookie->last_size != inode->Size()
|
if (!inode->IsDeleted() && cookie->last_size != inode->Size()
|
||||||
|
|||||||
@@ -1574,8 +1574,7 @@ cdda_can_page(fs_volume _volume, fs_vnode _v, fs_cookie cookie)
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
cdda_read_pages(fs_volume _volume, fs_vnode _v, fs_cookie cookie, off_t pos,
|
cdda_read_pages(fs_volume _volume, fs_vnode _v, fs_cookie cookie, off_t pos,
|
||||||
const iovec *vecs, size_t count, size_t *_numBytes, bool mayBlock,
|
const iovec *vecs, size_t count, size_t *_numBytes, bool reenter)
|
||||||
bool reenter)
|
|
||||||
{
|
{
|
||||||
return B_NOT_ALLOWED;
|
return B_NOT_ALLOWED;
|
||||||
}
|
}
|
||||||
@@ -1583,8 +1582,7 @@ cdda_read_pages(fs_volume _volume, fs_vnode _v, fs_cookie cookie, off_t pos,
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
cdda_write_pages(fs_volume _volume, fs_vnode _v, fs_cookie cookie, off_t pos,
|
cdda_write_pages(fs_volume _volume, fs_vnode _v, fs_cookie cookie, off_t pos,
|
||||||
const iovec *vecs, size_t count, size_t *_numBytes, bool mayBlock,
|
const iovec *vecs, size_t count, size_t *_numBytes, bool reenter)
|
||||||
bool reenter)
|
|
||||||
{
|
{
|
||||||
return B_NOT_ALLOWED;
|
return B_NOT_ALLOWED;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1038,7 +1038,8 @@ dosfs_read_vnode(void *_vol, ino_t vnid, void **_node, bool reenter)
|
|||||||
entry->filename = malloc(sizeof(filename) + 1);
|
entry->filename = malloc(sizeof(filename) + 1);
|
||||||
if (entry->filename) strcpy(entry->filename, filename);
|
if (entry->filename) strcpy(entry->filename, filename);
|
||||||
#endif
|
#endif
|
||||||
entry->cache = file_cache_create(vol->id, vnid, entry->st_size, vol->fd);
|
entry->cache = file_cache_create(vol->id, vnid, entry->st_size);
|
||||||
|
entry->file_map = file_map_create(vol->id, vnid);
|
||||||
if (!(entry->mode & FAT_SUBDIR))
|
if (!(entry->mode & FAT_SUBDIR))
|
||||||
set_mime_type(entry, filename);
|
set_mime_type(entry, filename);
|
||||||
|
|
||||||
|
|||||||
@@ -65,12 +65,12 @@ typedef recursive_lock lock;
|
|||||||
|
|
||||||
#define VNODE_MAGIC 'treB'
|
#define VNODE_MAGIC 'treB'
|
||||||
|
|
||||||
typedef struct vnode
|
typedef struct vnode {
|
||||||
{
|
|
||||||
uint32 magic;
|
uint32 magic;
|
||||||
ino_t vnid; // self id
|
ino_t vnid; // self id
|
||||||
ino_t dir_vnid; // parent vnode id (directory containing entry)
|
ino_t dir_vnid; // parent vnode id (directory containing entry)
|
||||||
void *cache; // for file cache
|
void *cache;
|
||||||
|
void *file_map;
|
||||||
|
|
||||||
uint32 disk_image; // 0 = no, 1 = BEOS, 2 = IMAGE.BE
|
uint32 disk_image; // 0 = no, 1 = BEOS, 2 = IMAGE.BE
|
||||||
|
|
||||||
|
|||||||
@@ -141,8 +141,8 @@ dosfs_release_vnode(void *_vol, void *_node, bool reenter)
|
|||||||
|
|
||||||
if (node->vnid != vol->root_vnode.vnid) {
|
if (node->vnid != vol->root_vnode.vnid) {
|
||||||
node->magic = ~VNODE_MAGIC; // munge magic number to be safe
|
node->magic = ~VNODE_MAGIC; // munge magic number to be safe
|
||||||
if (node->cache != NULL)
|
|
||||||
file_cache_delete(node->cache);
|
file_cache_delete(node->cache);
|
||||||
|
file_map_delete(node->file_map);
|
||||||
free(node);
|
free(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -245,6 +245,7 @@ dosfs_wstat(void *_vol, void *_node, const struct stat *st, uint32 mask)
|
|||||||
node->iteration++;
|
node->iteration++;
|
||||||
dirty = true;
|
dirty = true;
|
||||||
file_cache_set_size(node->cache, node->st_size);
|
file_cache_set_size(node->cache, node->st_size);
|
||||||
|
file_map_set_size(node->file_map, node->st_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -393,7 +394,7 @@ dosfs_read(void *_vol, void *_node, void *_cookie, off_t pos,
|
|||||||
if (pos + *len >= node->st_size)
|
if (pos + *len >= node->st_size)
|
||||||
*len = node->st_size - pos;
|
*len = node->st_size - pos;
|
||||||
|
|
||||||
result = file_cache_read(node->cache, pos, buf, len);
|
result = file_cache_read(node->cache, cookie, pos, buf, len);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
||||||
@@ -595,9 +596,10 @@ dosfs_write(void *_vol, void *_node, void *_cookie, off_t pos,
|
|||||||
DPRINTF(0, ("setting file size to %Lx (%lx clusters)\n", node->st_size, clusters));
|
DPRINTF(0, ("setting file size to %Lx (%lx clusters)\n", node->st_size, clusters));
|
||||||
node->dirty = true;
|
node->dirty = true;
|
||||||
file_cache_set_size(node->cache, node->st_size);
|
file_cache_set_size(node->cache, node->st_size);
|
||||||
|
file_map_set_size(node->file_map, node->st_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = file_cache_write(node->cache, pos, buf, len);
|
result = file_cache_write(node->cache, cookie, pos, buf, len);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
if (cluster1 == 0xffffffff) {
|
if (cluster1 == 0xffffffff) {
|
||||||
@@ -1479,11 +1481,13 @@ dosfs_can_page(fs_volume _fs, fs_vnode _v, fs_cookie _cookie)
|
|||||||
|
|
||||||
status_t
|
status_t
|
||||||
dosfs_read_pages(fs_volume _fs, fs_vnode _node, fs_cookie _cookie, off_t pos,
|
dosfs_read_pages(fs_volume _fs, fs_vnode _node, fs_cookie _cookie, off_t pos,
|
||||||
const iovec *vecs, size_t count, size_t *_numBytes, bool mayBlock,
|
const iovec *vecs, size_t count, size_t *_numBytes, bool reenter)
|
||||||
bool reenter)
|
|
||||||
{
|
{
|
||||||
nspace *vol = (nspace *)_fs;
|
nspace *vol = (nspace *)_fs;
|
||||||
vnode *node = (vnode *)_node;
|
vnode *node = (vnode *)_node;
|
||||||
|
uint32 vecIndex = 0;
|
||||||
|
size_t vecOffset = 0;
|
||||||
|
size_t bytesLeft = *_numBytes;
|
||||||
status_t status;
|
status_t status;
|
||||||
|
|
||||||
if (check_nspace_magic(vol, "dosfs_read_pages")
|
if (check_nspace_magic(vol, "dosfs_read_pages")
|
||||||
@@ -1493,23 +1497,49 @@ dosfs_read_pages(fs_volume _fs, fs_vnode _node, fs_cookie _cookie, off_t pos,
|
|||||||
if (node->cache == NULL)
|
if (node->cache == NULL)
|
||||||
return(B_BAD_VALUE);
|
return(B_BAD_VALUE);
|
||||||
|
|
||||||
// TODO: respect "mayBlock"!
|
if (!reenter) {
|
||||||
LOCK_VOL(vol);
|
LOCK_VOL(vol);
|
||||||
status = file_cache_read_pages(node->cache, pos, vecs, count,
|
}
|
||||||
_numBytes);
|
|
||||||
UNLOCK_VOL(vol);
|
|
||||||
|
|
||||||
return status;
|
while (true) {
|
||||||
|
struct file_io_vec fileVecs[8];
|
||||||
|
uint32 fileVecCount = 8;
|
||||||
|
bool bufferOverflow;
|
||||||
|
size_t bytes;
|
||||||
|
|
||||||
|
status = file_map_translate(node->file_map, pos, bytesLeft, fileVecs,
|
||||||
|
&fileVecCount);
|
||||||
|
if (status != B_OK && status != B_BUFFER_OVERFLOW)
|
||||||
|
break;
|
||||||
|
|
||||||
|
bufferOverflow = status == B_BUFFER_OVERFLOW;
|
||||||
|
|
||||||
|
status = read_file_io_vec_pages(vol->fd, fileVecs,
|
||||||
|
fileVecCount, vecs, count, &vecIndex, &vecOffset, &bytes);
|
||||||
|
if (status != B_OK || !bufferOverflow)
|
||||||
|
break;
|
||||||
|
|
||||||
|
pos += bytes;
|
||||||
|
bytesLeft -= bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!reenter) {
|
||||||
|
UNLOCK_VOL(vol);
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
dosfs_write_pages(fs_volume _fs, fs_vnode _node, fs_cookie _cookie, off_t pos,
|
dosfs_write_pages(fs_volume _fs, fs_vnode _node, fs_cookie _cookie, off_t pos,
|
||||||
const iovec *vecs, size_t count, size_t *_numBytes, bool mayBlock,
|
const iovec *vecs, size_t count, size_t *_numBytes, bool reenter)
|
||||||
bool reenter)
|
|
||||||
{
|
{
|
||||||
nspace *vol = (nspace *)_fs;
|
nspace *vol = (nspace *)_fs;
|
||||||
vnode *node = (vnode *)_node;
|
vnode *node = (vnode *)_node;
|
||||||
|
uint32 vecIndex = 0;
|
||||||
|
size_t vecOffset = 0;
|
||||||
|
size_t bytesLeft = *_numBytes;
|
||||||
status_t status;
|
status_t status;
|
||||||
|
|
||||||
if (check_nspace_magic(vol, "dosfs_write_pages")
|
if (check_nspace_magic(vol, "dosfs_write_pages")
|
||||||
@@ -1519,13 +1549,37 @@ dosfs_write_pages(fs_volume _fs, fs_vnode _node, fs_cookie _cookie, off_t pos,
|
|||||||
if (node->cache == NULL)
|
if (node->cache == NULL)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
// TODO: respect "mayBlock"!
|
if (!reenter) {
|
||||||
LOCK_VOL(vol);
|
LOCK_VOL(vol);
|
||||||
status = file_cache_write_pages(node->cache, pos, vecs, count,
|
}
|
||||||
_numBytes);
|
|
||||||
UNLOCK_VOL(vol);
|
|
||||||
|
|
||||||
return status;
|
while (true) {
|
||||||
|
struct file_io_vec fileVecs[8];
|
||||||
|
uint32 fileVecCount = 8;
|
||||||
|
bool bufferOverflow;
|
||||||
|
size_t bytes;
|
||||||
|
|
||||||
|
status = file_map_translate(node->file_map, pos, bytesLeft, fileVecs,
|
||||||
|
&fileVecCount);
|
||||||
|
if (status != B_OK && status != B_BUFFER_OVERFLOW)
|
||||||
|
break;
|
||||||
|
|
||||||
|
bufferOverflow = status == B_BUFFER_OVERFLOW;
|
||||||
|
|
||||||
|
status = write_file_io_vec_pages(vol->fd, fileVecs,
|
||||||
|
fileVecCount, vecs, count, &vecIndex, &vecOffset, &bytes);
|
||||||
|
if (status != B_OK || !bufferOverflow)
|
||||||
|
break;
|
||||||
|
|
||||||
|
pos += bytes;
|
||||||
|
bytesLeft -= bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!reenter) {
|
||||||
|
UNLOCK_VOL(vol);
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ status_t dosfs_get_file_map(void *fs, void *node, off_t pos, size_t reqLen,
|
|||||||
struct file_io_vec *vecs, size_t *_count);
|
struct file_io_vec *vecs, size_t *_count);
|
||||||
bool dosfs_can_page(fs_volume _fs, fs_vnode _v, fs_cookie _cookie);
|
bool dosfs_can_page(fs_volume _fs, fs_vnode _v, fs_cookie _cookie);
|
||||||
status_t dosfs_read_pages(fs_volume _fs, fs_vnode _node, fs_cookie _cookie, off_t pos,
|
status_t dosfs_read_pages(fs_volume _fs, fs_vnode _node, fs_cookie _cookie, off_t pos,
|
||||||
const iovec *vecs, size_t count, size_t *_numBytes, bool mayBlock, bool reenter);
|
const iovec *vecs, size_t count, size_t *_numBytes, bool reenter);
|
||||||
status_t dosfs_write_pages(fs_volume _fs, fs_vnode _node, fs_cookie _cookie, off_t pos,
|
status_t dosfs_write_pages(fs_volume _fs, fs_vnode _node, fs_cookie _cookie, off_t pos,
|
||||||
const iovec *vecs, size_t count, size_t *_numBytes, bool mayBlock, bool reenter);
|
const iovec *vecs, size_t count, size_t *_numBytes, bool reenter);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -462,7 +462,8 @@ fs_read_vnode(void *_ns, ino_t vnid, void **node, bool reenter)
|
|||||||
result = ENOMEM;
|
result = ENOMEM;
|
||||||
|
|
||||||
if (result == B_OK && !(newNode->flags & ISO_ISDIR)) {
|
if (result == B_OK && !(newNode->flags & ISO_ISDIR)) {
|
||||||
newNode->cache = file_cache_create(ns->id, vnid, newNode->dataLen[FS_DATA_FORMAT], ns->fdOfSession);
|
newNode->cache = file_cache_create(ns->id, vnid,
|
||||||
|
newNode->dataLen[FS_DATA_FORMAT]);
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE(("fs_read_vnode - EXIT, result is %s\n", strerror(result)));
|
TRACE(("fs_read_vnode - EXIT, result is %s\n", strerror(result)));
|
||||||
@@ -763,7 +764,7 @@ fs_read(void *_ns, void *_node, void *cookie, off_t pos, void *buf, size_t *len)
|
|||||||
*len = 0;
|
*len = 0;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
return file_cache_read(node->cache, pos, buf, len);
|
return file_cache_read(node->cache, NULL, pos, buf, len);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
@@ -4,6 +4,7 @@ KernelMergeObject kernel_cache.o :
|
|||||||
block_allocator.cpp
|
block_allocator.cpp
|
||||||
block_cache.cpp
|
block_cache.cpp
|
||||||
file_cache.cpp
|
file_cache.cpp
|
||||||
|
file_map.cpp
|
||||||
vnode_store.cpp
|
vnode_store.cpp
|
||||||
|
|
||||||
: $(TARGET_KERNEL_PIC_CCFLAGS) -Wno-unused
|
: $(TARGET_KERNEL_PIC_CCFLAGS) -Wno-unused
|
||||||
|
|||||||
+69
-559
@@ -35,42 +35,13 @@
|
|||||||
// maximum number of iovecs per request
|
// maximum number of iovecs per request
|
||||||
#define MAX_IO_VECS 32 // 128 kB
|
#define MAX_IO_VECS 32 // 128 kB
|
||||||
#define MAX_FILE_IO_VECS 32
|
#define MAX_FILE_IO_VECS 32
|
||||||
#define MAX_TEMP_IO_VECS 8
|
|
||||||
|
|
||||||
#define CACHED_FILE_EXTENTS 2
|
|
||||||
// must be smaller than MAX_FILE_IO_VECS
|
|
||||||
// ToDo: find out how much of these are typically used
|
|
||||||
|
|
||||||
#define BYPASS_IO_SIZE 65536
|
#define BYPASS_IO_SIZE 65536
|
||||||
#define LAST_ACCESSES 3
|
#define LAST_ACCESSES 3
|
||||||
|
|
||||||
struct file_extent {
|
|
||||||
off_t offset;
|
|
||||||
file_io_vec disk;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct file_map {
|
|
||||||
file_map();
|
|
||||||
~file_map();
|
|
||||||
|
|
||||||
file_extent *operator[](uint32 index);
|
|
||||||
file_extent *ExtentAt(uint32 index);
|
|
||||||
status_t Add(file_io_vec *vecs, size_t vecCount, off_t &lastOffset);
|
|
||||||
void Free();
|
|
||||||
|
|
||||||
union {
|
|
||||||
file_extent direct[CACHED_FILE_EXTENTS];
|
|
||||||
file_extent *array;
|
|
||||||
};
|
|
||||||
size_t count;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct file_cache_ref {
|
struct file_cache_ref {
|
||||||
vm_cache *cache;
|
vm_cache *cache;
|
||||||
struct vnode *vnode;
|
struct vnode *vnode;
|
||||||
struct vnode *device;
|
|
||||||
void *cookie;
|
|
||||||
file_map map;
|
|
||||||
off_t last_access[LAST_ACCESSES];
|
off_t last_access[LAST_ACCESSES];
|
||||||
// TODO: it would probably be enough to only store the least
|
// TODO: it would probably be enough to only store the least
|
||||||
// significant 31 bits, and make this uint32 (one bit for
|
// significant 31 bits, and make this uint32 (one bit for
|
||||||
@@ -79,7 +50,7 @@ struct file_cache_ref {
|
|||||||
bool last_access_was_write;
|
bool last_access_was_write;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef status_t (*cache_func)(file_cache_ref *ref, off_t offset,
|
typedef status_t (*cache_func)(file_cache_ref *ref, void *cookie, off_t offset,
|
||||||
int32 pageOffset, addr_t buffer, size_t bufferSize,
|
int32 pageOffset, addr_t buffer, size_t bufferSize,
|
||||||
size_t lastReservedPages, size_t reservePages);
|
size_t lastReservedPages, size_t reservePages);
|
||||||
|
|
||||||
@@ -87,101 +58,6 @@ typedef status_t (*cache_func)(file_cache_ref *ref, off_t offset,
|
|||||||
static struct cache_module_info *sCacheModule;
|
static struct cache_module_info *sCacheModule;
|
||||||
|
|
||||||
|
|
||||||
file_map::file_map()
|
|
||||||
{
|
|
||||||
array = NULL;
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
file_map::~file_map()
|
|
||||||
{
|
|
||||||
Free();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
file_extent *
|
|
||||||
file_map::operator[](uint32 index)
|
|
||||||
{
|
|
||||||
return ExtentAt(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
file_extent *
|
|
||||||
file_map::ExtentAt(uint32 index)
|
|
||||||
{
|
|
||||||
if (index >= count)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (count > CACHED_FILE_EXTENTS)
|
|
||||||
return &array[index];
|
|
||||||
|
|
||||||
return &direct[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
file_map::Add(file_io_vec *vecs, size_t vecCount, off_t &lastOffset)
|
|
||||||
{
|
|
||||||
TRACE(("file_map::Add(vecCount = %ld)\n", vecCount));
|
|
||||||
|
|
||||||
off_t offset = 0;
|
|
||||||
|
|
||||||
if (vecCount <= CACHED_FILE_EXTENTS && count == 0) {
|
|
||||||
// just use the reserved area in the file_cache_ref structure
|
|
||||||
} else {
|
|
||||||
// TODO: once we can invalidate only parts of the file map,
|
|
||||||
// we might need to copy the previously cached file extends
|
|
||||||
// from the direct range
|
|
||||||
file_extent *newMap = (file_extent *)realloc(array,
|
|
||||||
(count + vecCount) * sizeof(file_extent));
|
|
||||||
if (newMap == NULL)
|
|
||||||
return B_NO_MEMORY;
|
|
||||||
|
|
||||||
array = newMap;
|
|
||||||
|
|
||||||
if (count != 0) {
|
|
||||||
file_extent *extent = ExtentAt(count - 1);
|
|
||||||
offset = extent->offset + extent->disk.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 start = count;
|
|
||||||
count += vecCount;
|
|
||||||
|
|
||||||
for (uint32 i = 0; i < vecCount; i++) {
|
|
||||||
file_extent *extent = ExtentAt(start + i);
|
|
||||||
|
|
||||||
extent->offset = offset;
|
|
||||||
extent->disk = vecs[i];
|
|
||||||
|
|
||||||
offset += extent->disk.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef TRACE_FILE_CACHE
|
|
||||||
for (uint32 i = 0; i < count; i++) {
|
|
||||||
file_extent *extent = ExtentAt(i);
|
|
||||||
dprintf("[%ld] extend offset %Ld, disk offset %Ld, length %Ld\n",
|
|
||||||
i, extent->offset, extent->disk.offset, extent->disk.length);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
lastOffset = offset;
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
file_map::Free()
|
|
||||||
{
|
|
||||||
if (count > CACHED_FILE_EXTENTS)
|
|
||||||
free(array);
|
|
||||||
|
|
||||||
array = NULL;
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
@@ -205,119 +81,6 @@ add_to_iovec(iovec *vecs, int32 &index, int32 max, addr_t address, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static file_extent *
|
|
||||||
find_file_extent(file_cache_ref *ref, off_t offset, uint32 *_index)
|
|
||||||
{
|
|
||||||
// TODO: do binary search
|
|
||||||
|
|
||||||
for (uint32 index = 0; index < ref->map.count; index++) {
|
|
||||||
file_extent *extent = ref->map[index];
|
|
||||||
|
|
||||||
if (extent->offset <= offset
|
|
||||||
&& extent->offset + extent->disk.length > offset) {
|
|
||||||
if (_index)
|
|
||||||
*_index = index;
|
|
||||||
return extent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
get_file_map(file_cache_ref *ref, off_t offset, size_t size,
|
|
||||||
file_io_vec *vecs, size_t *_count)
|
|
||||||
{
|
|
||||||
size_t maxVecs = *_count;
|
|
||||||
status_t status = B_OK;
|
|
||||||
|
|
||||||
if (ref->map.count == 0) {
|
|
||||||
// we don't yet have the map of this file, so let's grab it
|
|
||||||
// (ordered by offset, so that we can do a binary search on them)
|
|
||||||
|
|
||||||
MutexLocker _(ref->cache->lock);
|
|
||||||
|
|
||||||
// the file map could have been requested in the mean time
|
|
||||||
if (ref->map.count == 0) {
|
|
||||||
size_t vecCount = maxVecs;
|
|
||||||
off_t mapOffset = 0;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
status = vfs_get_file_map(ref->vnode, mapOffset, ~0UL, vecs,
|
|
||||||
&vecCount);
|
|
||||||
if (status < B_OK && status != B_BUFFER_OVERFLOW)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
status_t addStatus = ref->map.Add(vecs, vecCount, mapOffset);
|
|
||||||
if (addStatus != B_OK) {
|
|
||||||
// only clobber the status in case of failure
|
|
||||||
status = addStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status != B_BUFFER_OVERFLOW)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// when we are here, the map has been stored in the array, and
|
|
||||||
// the array size was still too small to cover the whole file
|
|
||||||
vecCount = maxVecs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status != B_OK) {
|
|
||||||
// We must invalidate the (part of the) map we already
|
|
||||||
// have, as we cannot know if it's complete or not
|
|
||||||
ref->map.Free();
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We now have cached the map of this file, we now need to
|
|
||||||
// translate it for the requested access.
|
|
||||||
|
|
||||||
uint32 index;
|
|
||||||
file_extent *fileExtent = find_file_extent(ref, offset, &index);
|
|
||||||
if (fileExtent == NULL) {
|
|
||||||
// access outside file bounds? But that's not our problem
|
|
||||||
*_count = 0;
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset -= fileExtent->offset;
|
|
||||||
vecs[0].offset = fileExtent->disk.offset + offset;
|
|
||||||
vecs[0].length = fileExtent->disk.length - offset;
|
|
||||||
|
|
||||||
if (vecs[0].length >= size || index >= ref->map.count - 1) {
|
|
||||||
*_count = 1;
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy the rest of the vecs
|
|
||||||
|
|
||||||
size -= vecs[0].length;
|
|
||||||
|
|
||||||
for (index = 1; index < ref->map.count;) {
|
|
||||||
fileExtent++;
|
|
||||||
|
|
||||||
vecs[index] = fileExtent->disk;
|
|
||||||
index++;
|
|
||||||
|
|
||||||
if (size <= fileExtent->disk.length)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (index >= maxVecs) {
|
|
||||||
*_count = index;
|
|
||||||
return B_BUFFER_OVERFLOW;
|
|
||||||
}
|
|
||||||
|
|
||||||
size -= fileExtent->disk.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
*_count = index;
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
access_is_sequential(file_cache_ref *ref)
|
access_is_sequential(file_cache_ref *ref)
|
||||||
{
|
{
|
||||||
@@ -397,212 +160,6 @@ reserve_pages(file_cache_ref *ref, size_t reservePages, bool isWrite)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Does the dirty work of translating the request into actual disk offsets
|
|
||||||
and reads to or writes from the supplied iovecs as specified by \a doWrite.
|
|
||||||
*/
|
|
||||||
static status_t
|
|
||||||
pages_io(file_cache_ref *ref, off_t offset, const iovec *vecs, size_t count,
|
|
||||||
size_t *_numBytes, bool doWrite)
|
|
||||||
{
|
|
||||||
TRACE(("pages_io: ref = %p, offset = %Ld, size = %lu, vecCount = %lu, %s\n",
|
|
||||||
ref, offset, *_numBytes, count, doWrite ? "write" : "read"));
|
|
||||||
|
|
||||||
// translate the iovecs into direct device accesses
|
|
||||||
file_io_vec fileVecs[MAX_FILE_IO_VECS];
|
|
||||||
size_t fileVecCount = MAX_FILE_IO_VECS;
|
|
||||||
size_t numBytes = *_numBytes;
|
|
||||||
|
|
||||||
push_access(ref, offset, numBytes, doWrite);
|
|
||||||
|
|
||||||
status_t status = get_file_map(ref, offset, numBytes, fileVecs,
|
|
||||||
&fileVecCount);
|
|
||||||
if (status < B_OK && status != B_BUFFER_OVERFLOW) {
|
|
||||||
TRACE(("get_file_map(offset = %Ld, numBytes = %lu) failed: %s\n",
|
|
||||||
offset, numBytes, strerror(status)));
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bufferOverflow = status == B_BUFFER_OVERFLOW;
|
|
||||||
|
|
||||||
#ifdef TRACE_FILE_CACHE
|
|
||||||
dprintf("got %lu file vecs for %Ld:%lu%s:\n", fileVecCount, offset,
|
|
||||||
numBytes, bufferOverflow ? " (array too small)" : "");
|
|
||||||
for (size_t i = 0; i < fileVecCount; i++) {
|
|
||||||
dprintf(" [%lu] offset = %Ld, size = %Ld\n",
|
|
||||||
i, fileVecs[i].offset, fileVecs[i].length);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (fileVecCount == 0) {
|
|
||||||
// There are no file vecs at this offset, so we're obviously trying
|
|
||||||
// to access the file outside of its bounds
|
|
||||||
TRACE(("pages_io: access outside of vnode %p at offset %Ld\n",
|
|
||||||
ref->vnode, offset));
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 fileVecIndex;
|
|
||||||
size_t size;
|
|
||||||
|
|
||||||
if (!doWrite) {
|
|
||||||
// now directly read the data from the device
|
|
||||||
// the first file_io_vec can be read directly
|
|
||||||
|
|
||||||
size = fileVecs[0].length;
|
|
||||||
if (size > numBytes)
|
|
||||||
size = numBytes;
|
|
||||||
|
|
||||||
status = vfs_read_pages(ref->device, ref->cookie, fileVecs[0].offset,
|
|
||||||
vecs, count, &size, true, false);
|
|
||||||
if (status < B_OK)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
// TODO: this is a work-around for buggy device drivers!
|
|
||||||
// When our own drivers honour the length, we can:
|
|
||||||
// a) also use this direct I/O for writes (otherwise, it would
|
|
||||||
// overwrite precious data)
|
|
||||||
// b) panic if the term below is true (at least for writes)
|
|
||||||
if (size > fileVecs[0].length) {
|
|
||||||
//dprintf("warning: device driver %p doesn't respect total length in read_pages() call!\n", ref->device);
|
|
||||||
size = fileVecs[0].length;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(size <= fileVecs[0].length);
|
|
||||||
|
|
||||||
// If the file portion was contiguous, we're already done now
|
|
||||||
if (size == numBytes)
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
// if we reached the end of the file, we can return as well
|
|
||||||
if (size != fileVecs[0].length) {
|
|
||||||
*_numBytes = size;
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
fileVecIndex = 1;
|
|
||||||
} else {
|
|
||||||
fileVecIndex = 0;
|
|
||||||
size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Too bad, let's process the rest of the file_io_vecs
|
|
||||||
|
|
||||||
size_t totalSize = size;
|
|
||||||
|
|
||||||
// first, find out where we have to continue in our iovecs
|
|
||||||
uint32 i = 0;
|
|
||||||
for (; i < count; i++) {
|
|
||||||
if (size < vecs[i].iov_len)
|
|
||||||
break;
|
|
||||||
|
|
||||||
size -= vecs[i].iov_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t vecOffset = size;
|
|
||||||
size_t bytesLeft = numBytes - size;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
for (; fileVecIndex < fileVecCount; fileVecIndex++) {
|
|
||||||
file_io_vec &fileVec = fileVecs[fileVecIndex];
|
|
||||||
off_t fileOffset = fileVec.offset;
|
|
||||||
off_t fileLeft = min_c(fileVec.length, bytesLeft);
|
|
||||||
|
|
||||||
TRACE(("FILE VEC [%lu] length %Ld\n", fileVecIndex, fileLeft));
|
|
||||||
|
|
||||||
// process the complete fileVec
|
|
||||||
while (fileLeft > 0) {
|
|
||||||
iovec tempVecs[MAX_TEMP_IO_VECS];
|
|
||||||
uint32 tempCount = 0;
|
|
||||||
|
|
||||||
// size tracks how much of what is left of the current fileVec
|
|
||||||
// (fileLeft) has been assigned to tempVecs
|
|
||||||
size = 0;
|
|
||||||
|
|
||||||
// assign what is left of the current fileVec to the tempVecs
|
|
||||||
for (size = 0; size < fileLeft && i < count
|
|
||||||
&& tempCount < MAX_TEMP_IO_VECS;) {
|
|
||||||
// try to satisfy one iovec per iteration (or as much as
|
|
||||||
// possible)
|
|
||||||
|
|
||||||
// bytes left of the current iovec
|
|
||||||
size_t vecLeft = vecs[i].iov_len - vecOffset;
|
|
||||||
if (vecLeft == 0) {
|
|
||||||
vecOffset = 0;
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE(("fill vec %ld, offset = %lu, size = %lu\n",
|
|
||||||
i, vecOffset, size));
|
|
||||||
|
|
||||||
// actually available bytes
|
|
||||||
size_t tempVecSize = min_c(vecLeft, fileLeft - size);
|
|
||||||
|
|
||||||
tempVecs[tempCount].iov_base
|
|
||||||
= (void *)((addr_t)vecs[i].iov_base + vecOffset);
|
|
||||||
tempVecs[tempCount].iov_len = tempVecSize;
|
|
||||||
tempCount++;
|
|
||||||
|
|
||||||
size += tempVecSize;
|
|
||||||
vecOffset += tempVecSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t bytes = size;
|
|
||||||
if (doWrite) {
|
|
||||||
status = vfs_write_pages(ref->device, ref->cookie,
|
|
||||||
fileOffset, tempVecs, tempCount, &bytes, true, false);
|
|
||||||
} else {
|
|
||||||
status = vfs_read_pages(ref->device, ref->cookie,
|
|
||||||
fileOffset, tempVecs, tempCount, &bytes, true, false);
|
|
||||||
}
|
|
||||||
if (status < B_OK)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
totalSize += bytes;
|
|
||||||
bytesLeft -= size;
|
|
||||||
fileOffset += size;
|
|
||||||
fileLeft -= size;
|
|
||||||
//dprintf("-> file left = %Lu\n", fileLeft);
|
|
||||||
|
|
||||||
if (size != bytes || i >= count) {
|
|
||||||
// there are no more bytes or iovecs, let's bail out
|
|
||||||
*_numBytes = totalSize;
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bufferOverflow) {
|
|
||||||
status = get_file_map(ref, offset + totalSize, bytesLeft, fileVecs,
|
|
||||||
&fileVecCount);
|
|
||||||
if (status < B_OK && status != B_BUFFER_OVERFLOW) {
|
|
||||||
TRACE(("get_file_map(offset = %Ld, numBytes = %lu) failed: %s\n",
|
|
||||||
offset, numBytes, strerror(status)));
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
bufferOverflow = status == B_BUFFER_OVERFLOW;
|
|
||||||
fileVecIndex = 0;
|
|
||||||
|
|
||||||
#ifdef TRACE_FILE_CACHE
|
|
||||||
dprintf("got %lu file vecs for %Ld:%lu%s:\n", fileVecCount,
|
|
||||||
offset + totalSize, numBytes,
|
|
||||||
bufferOverflow ? " (array too small)" : "");
|
|
||||||
for (size_t i = 0; i < fileVecCount; i++) {
|
|
||||||
dprintf(" [%lu] offset = %Ld, size = %Ld\n",
|
|
||||||
i, fileVecs[i].offset, fileVecs[i].length);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
*_numBytes = totalSize;
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*! Reads the requested amount of data into the cache, and allocates
|
/*! Reads the requested amount of data into the cache, and allocates
|
||||||
pages needed to fulfill that request. This function is called by cache_io().
|
pages needed to fulfill that request. This function is called by cache_io().
|
||||||
It can only handle a certain amount of bytes, and the caller must make
|
It can only handle a certain amount of bytes, and the caller must make
|
||||||
@@ -611,9 +168,9 @@ pages_io(file_cache_ref *ref, off_t offset, const iovec *vecs, size_t count,
|
|||||||
operation it will unlock the cache, though.
|
operation it will unlock the cache, though.
|
||||||
*/
|
*/
|
||||||
static status_t
|
static status_t
|
||||||
read_into_cache(file_cache_ref *ref, off_t offset, int32 pageOffset,
|
read_into_cache(file_cache_ref *ref, void *cookie, off_t offset,
|
||||||
addr_t buffer, size_t bufferSize, size_t lastReservedPages,
|
int32 pageOffset, addr_t buffer, size_t bufferSize,
|
||||||
size_t reservePages)
|
size_t lastReservedPages, size_t reservePages)
|
||||||
{
|
{
|
||||||
TRACE(("read_into_cache(offset = %Ld, pageOffset = %ld, buffer = %#lx, "
|
TRACE(("read_into_cache(offset = %Ld, pageOffset = %ld, buffer = %#lx, "
|
||||||
"bufferSize = %lu\n", offset, pageOffset, buffer, bufferSize));
|
"bufferSize = %lu\n", offset, pageOffset, buffer, bufferSize));
|
||||||
@@ -650,11 +207,13 @@ read_into_cache(file_cache_ref *ref, off_t offset, int32 pageOffset,
|
|||||||
// TODO: check if the array is large enough (currently panics)!
|
// TODO: check if the array is large enough (currently panics)!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
push_access(ref, offset, bufferSize, false);
|
||||||
mutex_unlock(&cache->lock);
|
mutex_unlock(&cache->lock);
|
||||||
vm_page_unreserve_pages(lastReservedPages);
|
vm_page_unreserve_pages(lastReservedPages);
|
||||||
|
|
||||||
// read file into reserved pages
|
// read file into reserved pages
|
||||||
status_t status = pages_io(ref, offset, vecs, vecCount, &numBytes, false);
|
status_t status = vfs_read_pages(ref->vnode, cookie, offset, vecs,
|
||||||
|
vecCount, &numBytes, false);
|
||||||
if (status < B_OK) {
|
if (status < B_OK) {
|
||||||
// reading failed, free allocated pages
|
// reading failed, free allocated pages
|
||||||
|
|
||||||
@@ -718,18 +277,20 @@ read_into_cache(file_cache_ref *ref, off_t offset, int32 pageOffset,
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
read_from_file(file_cache_ref *ref, off_t offset, int32 pageOffset,
|
read_from_file(file_cache_ref *ref, void *cookie, off_t offset,
|
||||||
addr_t buffer, size_t bufferSize, size_t lastReservedPages,
|
int32 pageOffset, addr_t buffer, size_t bufferSize,
|
||||||
size_t reservePages)
|
size_t lastReservedPages, size_t reservePages)
|
||||||
{
|
{
|
||||||
iovec vec;
|
iovec vec;
|
||||||
vec.iov_base = (void *)buffer;
|
vec.iov_base = (void *)buffer;
|
||||||
vec.iov_len = bufferSize;
|
vec.iov_len = bufferSize;
|
||||||
|
|
||||||
|
push_access(ref, offset, bufferSize, false);
|
||||||
mutex_unlock(&ref->cache->lock);
|
mutex_unlock(&ref->cache->lock);
|
||||||
vm_page_unreserve_pages(lastReservedPages);
|
vm_page_unreserve_pages(lastReservedPages);
|
||||||
|
|
||||||
status_t status = pages_io(ref, offset, &vec, 1, &bufferSize, false);
|
status_t status = vfs_read_pages(ref->vnode, cookie, offset, &vec, 1,
|
||||||
|
&bufferSize, false);
|
||||||
if (status == B_OK)
|
if (status == B_OK)
|
||||||
reserve_pages(ref, reservePages, false);
|
reserve_pages(ref, reservePages, false);
|
||||||
|
|
||||||
@@ -745,9 +306,9 @@ read_from_file(file_cache_ref *ref, off_t offset, int32 pageOffset,
|
|||||||
The same restrictions apply.
|
The same restrictions apply.
|
||||||
*/
|
*/
|
||||||
static status_t
|
static status_t
|
||||||
write_to_cache(file_cache_ref *ref, off_t offset, int32 pageOffset,
|
write_to_cache(file_cache_ref *ref, void *cookie, off_t offset,
|
||||||
addr_t buffer, size_t bufferSize, size_t lastReservedPages,
|
int32 pageOffset, addr_t buffer, size_t bufferSize,
|
||||||
size_t reservePages)
|
size_t lastReservedPages, size_t reservePages)
|
||||||
{
|
{
|
||||||
// TODO: We're using way too much stack! Rather allocate a sufficiently
|
// TODO: We're using way too much stack! Rather allocate a sufficiently
|
||||||
// large chunk on the heap.
|
// large chunk on the heap.
|
||||||
@@ -783,6 +344,7 @@ write_to_cache(file_cache_ref *ref, off_t offset, int32 pageOffset,
|
|||||||
// ToDo: check if the array is large enough!
|
// ToDo: check if the array is large enough!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
push_access(ref, offset, bufferSize, true);
|
||||||
mutex_unlock(&ref->cache->lock);
|
mutex_unlock(&ref->cache->lock);
|
||||||
vm_page_unreserve_pages(lastReservedPages);
|
vm_page_unreserve_pages(lastReservedPages);
|
||||||
|
|
||||||
@@ -794,10 +356,11 @@ write_to_cache(file_cache_ref *ref, off_t offset, int32 pageOffset,
|
|||||||
iovec readVec = { vecs[0].iov_base, B_PAGE_SIZE };
|
iovec readVec = { vecs[0].iov_base, B_PAGE_SIZE };
|
||||||
size_t bytesRead = B_PAGE_SIZE;
|
size_t bytesRead = B_PAGE_SIZE;
|
||||||
|
|
||||||
status = pages_io(ref, offset, &readVec, 1, &bytesRead, false);
|
status = vfs_read_pages(ref->vnode, cookie, offset, &readVec, 1,
|
||||||
|
&bytesRead, false);
|
||||||
// ToDo: handle errors for real!
|
// ToDo: handle errors for real!
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
panic("1. pages_io() failed: %s!\n", strerror(status));
|
panic("1. vfs_read_pages() failed: %s!\n", strerror(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
addr_t lastPageOffset = (pageOffset + bufferSize) & (B_PAGE_SIZE - 1);
|
addr_t lastPageOffset = (pageOffset + bufferSize) & (B_PAGE_SIZE - 1);
|
||||||
@@ -816,11 +379,12 @@ write_to_cache(file_cache_ref *ref, off_t offset, int32 pageOffset,
|
|||||||
iovec readVec = { (void *)last, B_PAGE_SIZE };
|
iovec readVec = { (void *)last, B_PAGE_SIZE };
|
||||||
size_t bytesRead = B_PAGE_SIZE;
|
size_t bytesRead = B_PAGE_SIZE;
|
||||||
|
|
||||||
status = pages_io(ref, PAGE_ALIGN(offset + pageOffset + bufferSize)
|
status = vfs_read_pages(ref->vnode, cookie,
|
||||||
- B_PAGE_SIZE, &readVec, 1, &bytesRead, false);
|
PAGE_ALIGN(offset + pageOffset + bufferSize) - B_PAGE_SIZE,
|
||||||
|
&readVec, 1, &bytesRead, false);
|
||||||
// ToDo: handle errors for real!
|
// ToDo: handle errors for real!
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
panic("pages_io() failed: %s!\n", strerror(status));
|
panic("vfs_read_pages() failed: %s!\n", strerror(status));
|
||||||
|
|
||||||
if (bytesRead < B_PAGE_SIZE) {
|
if (bytesRead < B_PAGE_SIZE) {
|
||||||
// the space beyond the file size needs to be cleaned
|
// the space beyond the file size needs to be cleaned
|
||||||
@@ -846,8 +410,8 @@ write_to_cache(file_cache_ref *ref, off_t offset, int32 pageOffset,
|
|||||||
|
|
||||||
if (writeThrough) {
|
if (writeThrough) {
|
||||||
// write cached pages back to the file if we were asked to do that
|
// write cached pages back to the file if we were asked to do that
|
||||||
status_t status = pages_io(ref, offset, vecs, vecCount, &numBytes,
|
status_t status = vfs_write_pages(ref->vnode, cookie, offset, vecs,
|
||||||
true);
|
vecCount, &numBytes, false);
|
||||||
if (status < B_OK) {
|
if (status < B_OK) {
|
||||||
// ToDo: remove allocated pages, ...?
|
// ToDo: remove allocated pages, ...?
|
||||||
panic("file_cache: remove allocated pages! write pages failed: %s\n",
|
panic("file_cache: remove allocated pages! write pages failed: %s\n",
|
||||||
@@ -886,7 +450,7 @@ write_to_cache(file_cache_ref *ref, off_t offset, int32 pageOffset,
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
write_to_file(file_cache_ref *ref, off_t offset, int32 pageOffset,
|
write_to_file(file_cache_ref *ref, void *cookie, off_t offset, int32 pageOffset,
|
||||||
addr_t buffer, size_t bufferSize, size_t lastReservedPages,
|
addr_t buffer, size_t bufferSize, size_t lastReservedPages,
|
||||||
size_t reservePages)
|
size_t reservePages)
|
||||||
{
|
{
|
||||||
@@ -894,10 +458,12 @@ write_to_file(file_cache_ref *ref, off_t offset, int32 pageOffset,
|
|||||||
vec.iov_base = (void *)buffer;
|
vec.iov_base = (void *)buffer;
|
||||||
vec.iov_len = bufferSize;
|
vec.iov_len = bufferSize;
|
||||||
|
|
||||||
|
push_access(ref, offset, bufferSize, true);
|
||||||
mutex_unlock(&ref->cache->lock);
|
mutex_unlock(&ref->cache->lock);
|
||||||
vm_page_unreserve_pages(lastReservedPages);
|
vm_page_unreserve_pages(lastReservedPages);
|
||||||
|
|
||||||
status_t status = pages_io(ref, offset, &vec, 1, &bufferSize, true);
|
status_t status = vfs_write_pages(ref->vnode, cookie, offset, &vec, 1,
|
||||||
|
&bufferSize, false);
|
||||||
if (status == B_OK)
|
if (status == B_OK)
|
||||||
reserve_pages(ref, reservePages, true);
|
reserve_pages(ref, reservePages, true);
|
||||||
|
|
||||||
@@ -908,10 +474,10 @@ write_to_file(file_cache_ref *ref, off_t offset, int32 pageOffset,
|
|||||||
|
|
||||||
|
|
||||||
static inline status_t
|
static inline status_t
|
||||||
satisfy_cache_io(file_cache_ref *ref, cache_func function, off_t offset,
|
satisfy_cache_io(file_cache_ref *ref, void *cookie, cache_func function,
|
||||||
addr_t buffer, int32 &pageOffset, size_t bytesLeft, size_t &reservePages,
|
off_t offset, addr_t buffer, int32 &pageOffset, size_t bytesLeft,
|
||||||
off_t &lastOffset, addr_t &lastBuffer, int32 &lastPageOffset,
|
size_t &reservePages, off_t &lastOffset, addr_t &lastBuffer,
|
||||||
size_t &lastLeft, size_t &lastReservedPages)
|
int32 &lastPageOffset, size_t &lastLeft, size_t &lastReservedPages)
|
||||||
{
|
{
|
||||||
if (lastBuffer == buffer)
|
if (lastBuffer == buffer)
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -920,8 +486,8 @@ satisfy_cache_io(file_cache_ref *ref, cache_func function, off_t offset,
|
|||||||
reservePages = min_c(MAX_IO_VECS, (lastLeft - requestSize
|
reservePages = min_c(MAX_IO_VECS, (lastLeft - requestSize
|
||||||
+ lastPageOffset + B_PAGE_SIZE - 1) >> PAGE_SHIFT);
|
+ lastPageOffset + B_PAGE_SIZE - 1) >> PAGE_SHIFT);
|
||||||
|
|
||||||
status_t status = function(ref, lastOffset, lastPageOffset, lastBuffer,
|
status_t status = function(ref, cookie, lastOffset, lastPageOffset,
|
||||||
requestSize, lastReservedPages, reservePages);
|
lastBuffer, requestSize, lastReservedPages, reservePages);
|
||||||
if (status == B_OK) {
|
if (status == B_OK) {
|
||||||
lastReservedPages = reservePages;
|
lastReservedPages = reservePages;
|
||||||
lastBuffer = buffer;
|
lastBuffer = buffer;
|
||||||
@@ -935,8 +501,8 @@ satisfy_cache_io(file_cache_ref *ref, cache_func function, off_t offset,
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
cache_io(void *_cacheRef, off_t offset, addr_t buffer, size_t *_size,
|
cache_io(void *_cacheRef, void *cookie, off_t offset, addr_t buffer,
|
||||||
bool doWrite)
|
size_t *_size, bool doWrite)
|
||||||
{
|
{
|
||||||
if (_cacheRef == NULL)
|
if (_cacheRef == NULL)
|
||||||
panic("cache_io() called with NULL ref!\n");
|
panic("cache_io() called with NULL ref!\n");
|
||||||
@@ -1005,9 +571,9 @@ cache_io(void *_cacheRef, off_t offset, addr_t buffer, size_t *_size,
|
|||||||
// in the near future, we need to satisfy the request of the pages
|
// in the near future, we need to satisfy the request of the pages
|
||||||
// we didn't get yet (to make sure no one else interferes in the
|
// we didn't get yet (to make sure no one else interferes in the
|
||||||
// mean time).
|
// mean time).
|
||||||
status_t status = satisfy_cache_io(ref, function, offset, buffer,
|
status_t status = satisfy_cache_io(ref, cookie, function, offset,
|
||||||
pageOffset, bytesLeft, reservePages, lastOffset, lastBuffer,
|
buffer, pageOffset, bytesLeft, reservePages, lastOffset,
|
||||||
lastPageOffset, lastLeft, lastReservedPages);
|
lastBuffer, lastPageOffset, lastLeft, lastReservedPages);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
@@ -1073,9 +639,9 @@ cache_io(void *_cacheRef, off_t offset, addr_t buffer, size_t *_size,
|
|||||||
offset += B_PAGE_SIZE;
|
offset += B_PAGE_SIZE;
|
||||||
|
|
||||||
if (buffer - lastBuffer + lastPageOffset >= kMaxChunkSize) {
|
if (buffer - lastBuffer + lastPageOffset >= kMaxChunkSize) {
|
||||||
status_t status = satisfy_cache_io(ref, function, offset, buffer,
|
status_t status = satisfy_cache_io(ref, cookie, function, offset,
|
||||||
pageOffset, bytesLeft, reservePages, lastOffset, lastBuffer,
|
buffer, pageOffset, bytesLeft, reservePages, lastOffset,
|
||||||
lastPageOffset, lastLeft, lastReservedPages);
|
lastBuffer, lastPageOffset, lastLeft, lastReservedPages);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -1083,8 +649,8 @@ cache_io(void *_cacheRef, off_t offset, addr_t buffer, size_t *_size,
|
|||||||
|
|
||||||
// fill the last remaining bytes of the request (either write or read)
|
// fill the last remaining bytes of the request (either write or read)
|
||||||
|
|
||||||
return function(ref, lastOffset, lastPageOffset, lastBuffer, lastLeft,
|
return function(ref, cookie, lastOffset, lastPageOffset, lastBuffer,
|
||||||
lastReservedPages, 0);
|
lastLeft, lastReservedPages, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1303,10 +869,10 @@ file_cache_init(void)
|
|||||||
|
|
||||||
|
|
||||||
extern "C" void *
|
extern "C" void *
|
||||||
file_cache_create(dev_t mountID, ino_t vnodeID, off_t size, int fd)
|
file_cache_create(dev_t mountID, ino_t vnodeID, off_t size)
|
||||||
{
|
{
|
||||||
TRACE(("file_cache_create(mountID = %ld, vnodeID = %Ld, size = %Ld, "
|
TRACE(("file_cache_create(mountID = %ld, vnodeID = %Ld, size = %Ld)\n",
|
||||||
"fd = %d)\n", mountID, vnodeID, size, fd));
|
mountID, vnodeID, size));
|
||||||
|
|
||||||
file_cache_ref *ref = new file_cache_ref;
|
file_cache_ref *ref = new file_cache_ref;
|
||||||
if (ref == NULL)
|
if (ref == NULL)
|
||||||
@@ -1325,29 +891,19 @@ file_cache_create(dev_t mountID, ino_t vnodeID, off_t size, int fd)
|
|||||||
// use atomic_test_and_set(), and free the resources again
|
// use atomic_test_and_set(), and free the resources again
|
||||||
// when that fails...
|
// when that fails...
|
||||||
|
|
||||||
// Get the vnode of the underlying device
|
|
||||||
if (vfs_get_vnode_from_fd(fd, true, &ref->device) != B_OK)
|
|
||||||
goto err1;
|
|
||||||
|
|
||||||
// We also need the cookie of the underlying device to properly access it
|
|
||||||
if (vfs_get_cookie_from_fd(fd, &ref->cookie) != B_OK)
|
|
||||||
goto err2;
|
|
||||||
|
|
||||||
// Get the vnode for the object
|
// Get the vnode for the object
|
||||||
// (note, this does not grab a reference to the node)
|
// (note, this does not grab a reference to the node)
|
||||||
if (vfs_lookup_vnode(mountID, vnodeID, &ref->vnode) != B_OK)
|
if (vfs_lookup_vnode(mountID, vnodeID, &ref->vnode) != B_OK)
|
||||||
goto err2;
|
goto err1;
|
||||||
|
|
||||||
// Gets (usually creates) the cache for the node
|
// Gets (usually creates) the cache for the node
|
||||||
if (vfs_get_vnode_cache(ref->vnode, &ref->cache, true) != B_OK)
|
if (vfs_get_vnode_cache(ref->vnode, &ref->cache, true) != B_OK)
|
||||||
goto err2;
|
goto err1;
|
||||||
|
|
||||||
ref->cache->virtual_size = size;
|
ref->cache->virtual_size = size;
|
||||||
((vnode_store *)ref->cache->store)->file_cache_ref = ref;
|
((vnode_store *)ref->cache->store)->file_cache_ref = ref;
|
||||||
return ref;
|
return ref;
|
||||||
|
|
||||||
err2:
|
|
||||||
vfs_put_vnode(ref->device);
|
|
||||||
err1:
|
err1:
|
||||||
delete ref;
|
delete ref;
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1365,7 +921,6 @@ file_cache_delete(void *_cacheRef)
|
|||||||
TRACE(("file_cache_delete(ref = %p)\n", ref));
|
TRACE(("file_cache_delete(ref = %p)\n", ref));
|
||||||
|
|
||||||
vm_cache_release_ref(ref->cache);
|
vm_cache_release_ref(ref->cache);
|
||||||
vfs_put_vnode(ref->device);
|
|
||||||
delete ref;
|
delete ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1380,7 +935,7 @@ file_cache_set_size(void *_cacheRef, off_t newSize)
|
|||||||
if (ref == NULL)
|
if (ref == NULL)
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
mutex_lock(&ref->cache->lock);
|
MutexLocker _(ref->cache->lock);
|
||||||
|
|
||||||
off_t offset = ref->cache->virtual_size;
|
off_t offset = ref->cache->virtual_size;
|
||||||
off_t size = newSize;
|
off_t size = newSize;
|
||||||
@@ -1390,12 +945,7 @@ file_cache_set_size(void *_cacheRef, off_t newSize)
|
|||||||
} else
|
} else
|
||||||
size = newSize - offset;
|
size = newSize - offset;
|
||||||
|
|
||||||
status_t status = vm_cache_resize(ref->cache, newSize);
|
return vm_cache_resize(ref->cache, newSize);
|
||||||
mutex_unlock(&ref->cache->lock);
|
|
||||||
|
|
||||||
file_cache_invalidate_file_map(_cacheRef, offset, size);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1411,51 +961,26 @@ file_cache_sync(void *_cacheRef)
|
|||||||
|
|
||||||
|
|
||||||
extern "C" status_t
|
extern "C" status_t
|
||||||
file_cache_read_pages(void *_cacheRef, off_t offset, const iovec *vecs,
|
file_cache_read(void *_cacheRef, void *cookie, off_t offset, void *buffer,
|
||||||
size_t count, size_t *_numBytes)
|
|
||||||
{
|
|
||||||
file_cache_ref *ref = (file_cache_ref *)_cacheRef;
|
|
||||||
|
|
||||||
return pages_io(ref, offset, vecs, count, _numBytes, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
extern "C" status_t
|
|
||||||
file_cache_write_pages(void *_cacheRef, off_t offset, const iovec *vecs,
|
|
||||||
size_t count, size_t *_numBytes)
|
|
||||||
{
|
|
||||||
file_cache_ref *ref = (file_cache_ref *)_cacheRef;
|
|
||||||
|
|
||||||
status_t status = pages_io(ref, offset, vecs, count, _numBytes, true);
|
|
||||||
|
|
||||||
TRACE(("file_cache_write_pages(ref = %p, offset = %Ld, vecs = %p, "
|
|
||||||
"count = %lu, bytes = %lu) = %ld\n", ref, offset, vecs, count,
|
|
||||||
*_numBytes, status));
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
extern "C" status_t
|
|
||||||
file_cache_read(void *_cacheRef, off_t offset, void *bufferBase, size_t *_size)
|
|
||||||
{
|
|
||||||
file_cache_ref *ref = (file_cache_ref *)_cacheRef;
|
|
||||||
|
|
||||||
TRACE(("file_cache_read(ref = %p, offset = %Ld, buffer = %p, size = %lu)\n",
|
|
||||||
ref, offset, bufferBase, *_size));
|
|
||||||
|
|
||||||
return cache_io(ref, offset, (addr_t)bufferBase, _size, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
extern "C" status_t
|
|
||||||
file_cache_write(void *_cacheRef, off_t offset, const void *buffer,
|
|
||||||
size_t *_size)
|
size_t *_size)
|
||||||
{
|
{
|
||||||
file_cache_ref *ref = (file_cache_ref *)_cacheRef;
|
file_cache_ref *ref = (file_cache_ref *)_cacheRef;
|
||||||
|
|
||||||
status_t status = cache_io(ref, offset, (addr_t)const_cast<void *>(buffer),
|
TRACE(("file_cache_read(ref = %p, offset = %Ld, buffer = %p, size = %lu)\n",
|
||||||
_size, true);
|
ref, offset, buffer, *_size));
|
||||||
|
|
||||||
|
return cache_io(ref, cookie, offset, (addr_t)buffer, _size, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" status_t
|
||||||
|
file_cache_write(void *_cacheRef, void *cookie, off_t offset,
|
||||||
|
const void *buffer, size_t *_size)
|
||||||
|
{
|
||||||
|
file_cache_ref *ref = (file_cache_ref *)_cacheRef;
|
||||||
|
|
||||||
|
status_t status = cache_io(ref, cookie, offset,
|
||||||
|
(addr_t)const_cast<void *>(buffer), _size, true);
|
||||||
|
|
||||||
TRACE(("file_cache_write(ref = %p, offset = %Ld, buffer = %p, size = %lu)"
|
TRACE(("file_cache_write(ref = %p, offset = %Ld, buffer = %p, size = %lu)"
|
||||||
" = %ld\n", ref, offset, buffer, *_size, status));
|
" = %ld\n", ref, offset, buffer, *_size, status));
|
||||||
@@ -1463,18 +988,3 @@ file_cache_write(void *_cacheRef, off_t offset, const void *buffer,
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extern "C" status_t
|
|
||||||
file_cache_invalidate_file_map(void *_cacheRef, off_t offset, off_t size)
|
|
||||||
{
|
|
||||||
file_cache_ref *ref = (file_cache_ref *)_cacheRef;
|
|
||||||
|
|
||||||
// ToDo: honour offset/size parameters
|
|
||||||
|
|
||||||
TRACE(("file_cache_invalidate_file_map(offset = %Ld, size = %Ld)\n", offset,
|
|
||||||
size));
|
|
||||||
|
|
||||||
MutexLocker _(ref->cache->lock);
|
|
||||||
ref->map.Free();
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|||||||
Vendored
+19
-1
@@ -128,7 +128,7 @@ file_map::Add(file_io_vec *vecs, size_t vecCount, off_t &lastOffset)
|
|||||||
offset += extent->disk.length;
|
offset += extent->disk.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TRACE_FILE_CACHE
|
#ifdef TRACE_FILE_MAP
|
||||||
for (uint32 i = 0; i < count; i++) {
|
for (uint32 i = 0; i < count; i++) {
|
||||||
file_extent *extent = ExtentAt(i);
|
file_extent *extent = ExtentAt(i);
|
||||||
dprintf("[%ld] extend offset %Ld, disk offset %Ld, length %Ld\n",
|
dprintf("[%ld] extend offset %Ld, disk offset %Ld, length %Ld\n",
|
||||||
@@ -210,9 +210,24 @@ file_map_delete(void *_map)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" void
|
||||||
|
file_map_set_size(void *_map, off_t size)
|
||||||
|
{
|
||||||
|
if (_map == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// TODO: honour offset/size parameters
|
||||||
|
file_map *map = (file_map *)_map;
|
||||||
|
map->Free();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
extern "C" void
|
extern "C" void
|
||||||
file_map_invalidate(void *_map, off_t offset, off_t size)
|
file_map_invalidate(void *_map, off_t offset, off_t size)
|
||||||
{
|
{
|
||||||
|
if (_map == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
// TODO: honour offset/size parameters
|
// TODO: honour offset/size parameters
|
||||||
file_map *map = (file_map *)_map;
|
file_map *map = (file_map *)_map;
|
||||||
map->Free();
|
map->Free();
|
||||||
@@ -223,6 +238,9 @@ extern "C" status_t
|
|||||||
file_map_translate(void *_map, off_t offset, size_t size, file_io_vec *vecs,
|
file_map_translate(void *_map, off_t offset, size_t size, file_io_vec *vecs,
|
||||||
size_t *_count)
|
size_t *_count)
|
||||||
{
|
{
|
||||||
|
if (_map == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
file_map &map = *(file_map *)_map;
|
file_map &map = *(file_map *)_map;
|
||||||
size_t maxVecs = *_count;
|
size_t maxVecs = *_count;
|
||||||
status_t status = B_OK;
|
status_t status = B_OK;
|
||||||
|
|||||||
+4
-4
@@ -42,13 +42,13 @@ store_has_page(struct vm_store *_store, off_t offset)
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
store_read(struct vm_store *_store, off_t offset, const iovec *vecs,
|
store_read(struct vm_store *_store, off_t offset, const iovec *vecs,
|
||||||
size_t count, size_t *_numBytes, bool mayBlock, bool fsReenter)
|
size_t count, size_t *_numBytes, bool fsReenter)
|
||||||
{
|
{
|
||||||
vnode_store *store = (vnode_store *)_store;
|
vnode_store *store = (vnode_store *)_store;
|
||||||
size_t bytesUntouched = *_numBytes;
|
size_t bytesUntouched = *_numBytes;
|
||||||
|
|
||||||
status_t status = vfs_read_pages(store->vnode, NULL, offset, vecs, count,
|
status_t status = vfs_read_pages(store->vnode, NULL, offset, vecs, count,
|
||||||
_numBytes, mayBlock, fsReenter);
|
_numBytes, fsReenter);
|
||||||
|
|
||||||
bytesUntouched -= *_numBytes;
|
bytesUntouched -= *_numBytes;
|
||||||
|
|
||||||
@@ -75,11 +75,11 @@ store_read(struct vm_store *_store, off_t offset, const iovec *vecs,
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
store_write(struct vm_store *_store, off_t offset, const iovec *vecs,
|
store_write(struct vm_store *_store, off_t offset, const iovec *vecs,
|
||||||
size_t count, size_t *_numBytes, bool mayBlock, bool fsReenter)
|
size_t count, size_t *_numBytes, bool fsReenter)
|
||||||
{
|
{
|
||||||
vnode_store *store = (vnode_store *)_store;
|
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,
|
||||||
mayBlock, fsReenter);
|
fsReenter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1884,8 +1884,7 @@ devfs_can_page(fs_volume _fs, fs_vnode _vnode, fs_cookie cookie)
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
devfs_read_pages(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, off_t pos,
|
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 mayBlock,
|
const iovec *vecs, size_t count, size_t *_numBytes, bool reenter)
|
||||||
bool reenter)
|
|
||||||
{
|
{
|
||||||
struct devfs_vnode *vnode = (devfs_vnode *)_vnode;
|
struct devfs_vnode *vnode = (devfs_vnode *)_vnode;
|
||||||
struct devfs_cookie *cookie = (struct devfs_cookie *)_cookie;
|
struct devfs_cookie *cookie = (struct devfs_cookie *)_cookie;
|
||||||
@@ -1944,8 +1943,7 @@ devfs_read_pages(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, off_t pos,
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
devfs_write_pages(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, off_t pos,
|
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 mayBlock,
|
const iovec *vecs, size_t count, size_t *_numBytes, bool reenter)
|
||||||
bool reenter)
|
|
||||||
{
|
{
|
||||||
struct devfs_vnode *vnode = (devfs_vnode *)_vnode;
|
struct devfs_vnode *vnode = (devfs_vnode *)_vnode;
|
||||||
struct devfs_cookie *cookie = (struct devfs_cookie *)_cookie;
|
struct devfs_cookie *cookie = (struct devfs_cookie *)_cookie;
|
||||||
|
|||||||
@@ -1596,8 +1596,7 @@ pipefs_can_page(fs_volume _volume, fs_vnode _v, fs_cookie cookie)
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
pipefs_read_pages(fs_volume _volume, fs_vnode _v, fs_cookie cookie, off_t pos,
|
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 mayBlock,
|
const iovec *vecs, size_t count, size_t *_numBytes, bool reenter)
|
||||||
bool reenter)
|
|
||||||
{
|
{
|
||||||
return B_NOT_ALLOWED;
|
return B_NOT_ALLOWED;
|
||||||
}
|
}
|
||||||
@@ -1605,8 +1604,7 @@ pipefs_read_pages(fs_volume _volume, fs_vnode _v, fs_cookie cookie, off_t pos,
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
pipefs_write_pages(fs_volume _volume, fs_vnode _v, fs_cookie cookie, off_t pos,
|
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 mayBlock,
|
const iovec *vecs, size_t count, size_t *_numBytes, bool reenter)
|
||||||
bool reenter)
|
|
||||||
{
|
{
|
||||||
return B_NOT_ALLOWED;
|
return B_NOT_ALLOWED;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -787,8 +787,7 @@ rootfs_can_page(fs_volume _fs, fs_vnode _v, fs_cookie cookie)
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
rootfs_read_pages(fs_volume _fs, fs_vnode _v, fs_cookie cookie, off_t pos,
|
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 mayBlock,
|
const iovec *vecs, size_t count, size_t *_numBytes, bool reenter)
|
||||||
bool reenter)
|
|
||||||
{
|
{
|
||||||
return B_NOT_ALLOWED;
|
return B_NOT_ALLOWED;
|
||||||
}
|
}
|
||||||
@@ -796,8 +795,7 @@ rootfs_read_pages(fs_volume _fs, fs_vnode _v, fs_cookie cookie, off_t pos,
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
rootfs_write_pages(fs_volume _fs, fs_vnode _v, fs_cookie cookie, off_t pos,
|
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 mayBlock,
|
const iovec *vecs, size_t count, size_t *_numBytes, bool reenter)
|
||||||
bool reenter)
|
|
||||||
{
|
{
|
||||||
return B_NOT_ALLOWED;
|
return B_NOT_ALLOWED;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,6 +191,8 @@ static struct vnode *sRoot;
|
|||||||
static hash_table *sMountsTable;
|
static hash_table *sMountsTable;
|
||||||
static dev_t sNextMountID = 1;
|
static dev_t sNextMountID = 1;
|
||||||
|
|
||||||
|
#define MAX_TEMP_IO_VECS 8
|
||||||
|
|
||||||
mode_t __gUmask = 022;
|
mode_t __gUmask = 022;
|
||||||
|
|
||||||
/* function declarations */
|
/* function declarations */
|
||||||
@@ -2567,6 +2569,161 @@ dump_vnode_usage(int argc, char **argv)
|
|||||||
|
|
||||||
#endif // ADD_DEBUGGER_COMMANDS
|
#endif // ADD_DEBUGGER_COMMANDS
|
||||||
|
|
||||||
|
/*! Does the dirty work of combining the file_io_vecs with the iovecs
|
||||||
|
and calls the file system hooks to read/write the request to disk.
|
||||||
|
*/
|
||||||
|
static status_t
|
||||||
|
common_file_io_vec_pages(struct vnode *vnode, void *cookie,
|
||||||
|
const file_io_vec *fileVecs, size_t fileVecCount, const iovec *vecs,
|
||||||
|
size_t vecCount, uint32 *_vecIndex, size_t *_vecOffset, size_t *_numBytes,
|
||||||
|
bool doWrite)
|
||||||
|
{
|
||||||
|
if (fileVecCount == 0) {
|
||||||
|
// There are no file vecs at this offset, so we're obviously trying
|
||||||
|
// to access the file outside of its bounds
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t numBytes = *_numBytes;
|
||||||
|
uint32 fileVecIndex;
|
||||||
|
size_t vecOffset = *_vecOffset;
|
||||||
|
uint32 vecIndex = *_vecIndex;
|
||||||
|
status_t status;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
if (!doWrite) {
|
||||||
|
// now directly read the data from the device
|
||||||
|
// the first file_io_vec can be read directly
|
||||||
|
|
||||||
|
size = fileVecs[0].length;
|
||||||
|
if (size > numBytes)
|
||||||
|
size = numBytes;
|
||||||
|
|
||||||
|
status = FS_CALL(vnode, read_pages)(vnode->mount->cookie,
|
||||||
|
vnode->private_node, cookie, fileVecs[0].offset, vecs, vecCount,
|
||||||
|
&size, false);
|
||||||
|
if (status < B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
// TODO: this is a work-around for buggy device drivers!
|
||||||
|
// When our own drivers honour the length, we can:
|
||||||
|
// a) also use this direct I/O for writes (otherwise, it would
|
||||||
|
// overwrite precious data)
|
||||||
|
// b) panic if the term below is true (at least for writes)
|
||||||
|
if (size > fileVecs[0].length) {
|
||||||
|
//dprintf("warning: device driver %p doesn't respect total length in read_pages() call!\n", ref->device);
|
||||||
|
size = fileVecs[0].length;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(size <= fileVecs[0].length);
|
||||||
|
|
||||||
|
// If the file portion was contiguous, we're already done now
|
||||||
|
if (size == numBytes)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
// if we reached the end of the file, we can return as well
|
||||||
|
if (size != fileVecs[0].length) {
|
||||||
|
*_numBytes = size;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileVecIndex = 1;
|
||||||
|
|
||||||
|
// first, find out where we have to continue in our iovecs
|
||||||
|
for (; vecIndex < vecCount; vecIndex++) {
|
||||||
|
if (size < vecs[vecIndex].iov_len)
|
||||||
|
break;
|
||||||
|
|
||||||
|
size -= vecs[vecIndex].iov_len;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fileVecIndex = 0;
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Too bad, let's process the rest of the file_io_vecs
|
||||||
|
|
||||||
|
size_t totalSize = size;
|
||||||
|
size_t bytesLeft = numBytes - size;
|
||||||
|
|
||||||
|
for (; fileVecIndex < fileVecCount; fileVecIndex++) {
|
||||||
|
const file_io_vec &fileVec = fileVecs[fileVecIndex];
|
||||||
|
off_t fileOffset = fileVec.offset;
|
||||||
|
off_t fileLeft = min_c(fileVec.length, bytesLeft);
|
||||||
|
|
||||||
|
TRACE(("FILE VEC [%lu] length %Ld\n", fileVecIndex, fileLeft));
|
||||||
|
|
||||||
|
// process the complete fileVec
|
||||||
|
while (fileLeft > 0) {
|
||||||
|
iovec tempVecs[MAX_TEMP_IO_VECS];
|
||||||
|
uint32 tempCount = 0;
|
||||||
|
|
||||||
|
// size tracks how much of what is left of the current fileVec
|
||||||
|
// (fileLeft) has been assigned to tempVecs
|
||||||
|
size = 0;
|
||||||
|
|
||||||
|
// assign what is left of the current fileVec to the tempVecs
|
||||||
|
for (size = 0; size < fileLeft && vecIndex < vecCount
|
||||||
|
&& tempCount < MAX_TEMP_IO_VECS;) {
|
||||||
|
// try to satisfy one iovec per iteration (or as much as
|
||||||
|
// possible)
|
||||||
|
|
||||||
|
// bytes left of the current iovec
|
||||||
|
size_t vecLeft = vecs[vecIndex].iov_len - vecOffset;
|
||||||
|
if (vecLeft == 0) {
|
||||||
|
vecOffset = 0;
|
||||||
|
vecIndex++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE(("fill vec %ld, offset = %lu, size = %lu\n",
|
||||||
|
vecIndex, vecOffset, size));
|
||||||
|
|
||||||
|
// actually available bytes
|
||||||
|
size_t tempVecSize = min_c(vecLeft, fileLeft - size);
|
||||||
|
|
||||||
|
tempVecs[tempCount].iov_base
|
||||||
|
= (void *)((addr_t)vecs[vecIndex].iov_base + vecOffset);
|
||||||
|
tempVecs[tempCount].iov_len = tempVecSize;
|
||||||
|
tempCount++;
|
||||||
|
|
||||||
|
size += tempVecSize;
|
||||||
|
vecOffset += tempVecSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t bytes = size;
|
||||||
|
if (doWrite) {
|
||||||
|
status = FS_CALL(vnode, write_pages)(vnode->mount->cookie,
|
||||||
|
vnode->private_node, cookie, fileOffset, tempVecs,
|
||||||
|
tempCount, &bytes, false);
|
||||||
|
} else {
|
||||||
|
status = FS_CALL(vnode, read_pages)(vnode->mount->cookie,
|
||||||
|
vnode->private_node, cookie, fileOffset, tempVecs,
|
||||||
|
tempCount, &bytes, false);
|
||||||
|
}
|
||||||
|
if (status < B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
totalSize += bytes;
|
||||||
|
bytesLeft -= size;
|
||||||
|
fileOffset += size;
|
||||||
|
fileLeft -= size;
|
||||||
|
//dprintf("-> file left = %Lu\n", fileLeft);
|
||||||
|
|
||||||
|
if (size != bytes || vecIndex >= vecCount) {
|
||||||
|
// there are no more bytes or iovecs, let's bail out
|
||||||
|
*_numBytes = totalSize;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*_vecIndex = vecIndex;
|
||||||
|
*_vecOffset = vecOffset;
|
||||||
|
*_numBytes = totalSize;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - public API for file systems
|
// #pragma mark - public API for file systems
|
||||||
|
|
||||||
@@ -2736,6 +2893,88 @@ get_vnode_removed(dev_t mountID, ino_t vnodeID, bool* removed)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" status_t
|
||||||
|
read_pages(int fd, off_t pos, const iovec *vecs, size_t count,
|
||||||
|
size_t *_numBytes, bool fsReenter)
|
||||||
|
{
|
||||||
|
struct file_descriptor *descriptor;
|
||||||
|
struct vnode *vnode;
|
||||||
|
|
||||||
|
descriptor = get_fd_and_vnode(fd, &vnode, true);
|
||||||
|
if (descriptor == NULL)
|
||||||
|
return B_FILE_ERROR;
|
||||||
|
|
||||||
|
status_t status = FS_CALL(vnode, read_pages)(vnode->mount->cookie,
|
||||||
|
vnode->private_node, descriptor->cookie, pos, vecs, count, _numBytes,
|
||||||
|
fsReenter);
|
||||||
|
|
||||||
|
put_fd(descriptor);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" status_t
|
||||||
|
write_pages(int fd, off_t pos, const iovec *vecs, size_t count,
|
||||||
|
size_t *_numBytes, bool fsReenter)
|
||||||
|
{
|
||||||
|
struct file_descriptor *descriptor;
|
||||||
|
struct vnode *vnode;
|
||||||
|
|
||||||
|
descriptor = get_fd_and_vnode(fd, &vnode, true);
|
||||||
|
if (descriptor == NULL)
|
||||||
|
return B_FILE_ERROR;
|
||||||
|
|
||||||
|
status_t status = FS_CALL(vnode, write_pages)(vnode->mount->cookie,
|
||||||
|
vnode->private_node, descriptor->cookie, pos, vecs, count, _numBytes,
|
||||||
|
fsReenter);
|
||||||
|
|
||||||
|
put_fd(descriptor);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" status_t
|
||||||
|
read_file_io_vec_pages(int fd, const file_io_vec *fileVecs, size_t fileVecCount,
|
||||||
|
const iovec *vecs, size_t vecCount, uint32 *_vecIndex, size_t *_vecOffset,
|
||||||
|
size_t *_bytes)
|
||||||
|
{
|
||||||
|
struct file_descriptor *descriptor;
|
||||||
|
struct vnode *vnode;
|
||||||
|
|
||||||
|
descriptor = get_fd_and_vnode(fd, &vnode, true);
|
||||||
|
if (descriptor == NULL)
|
||||||
|
return B_FILE_ERROR;
|
||||||
|
|
||||||
|
status_t status = common_file_io_vec_pages(vnode, descriptor->cookie,
|
||||||
|
fileVecs, fileVecCount, vecs, vecCount, _vecIndex, _vecOffset, _bytes,
|
||||||
|
false);
|
||||||
|
|
||||||
|
put_fd(descriptor);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" status_t
|
||||||
|
write_file_io_vec_pages(int fd, const file_io_vec *fileVecs, size_t fileVecCount,
|
||||||
|
const iovec *vecs, size_t vecCount, uint32 *_vecIndex, size_t *_vecOffset,
|
||||||
|
size_t *_bytes)
|
||||||
|
{
|
||||||
|
struct file_descriptor *descriptor;
|
||||||
|
struct vnode *vnode;
|
||||||
|
|
||||||
|
descriptor = get_fd_and_vnode(fd, &vnode, true);
|
||||||
|
if (descriptor == NULL)
|
||||||
|
return B_FILE_ERROR;
|
||||||
|
|
||||||
|
status_t status = common_file_io_vec_pages(vnode, descriptor->cookie,
|
||||||
|
fileVecs, fileVecCount, vecs, vecCount, _vecIndex, _vecOffset, _bytes,
|
||||||
|
true);
|
||||||
|
|
||||||
|
put_fd(descriptor);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - private VFS API
|
// #pragma mark - private VFS API
|
||||||
// Functions the VFS exports for other parts of the kernel
|
// Functions the VFS exports for other parts of the kernel
|
||||||
|
|
||||||
@@ -3135,23 +3374,23 @@ vfs_can_page(struct vnode *vnode, void *cookie)
|
|||||||
|
|
||||||
extern "C" status_t
|
extern "C" status_t
|
||||||
vfs_read_pages(struct vnode *vnode, void *cookie, off_t pos, const iovec *vecs,
|
vfs_read_pages(struct vnode *vnode, void *cookie, off_t pos, const iovec *vecs,
|
||||||
size_t count, size_t *_numBytes, bool mayBlock, bool fsReenter)
|
size_t count, size_t *_numBytes, bool fsReenter)
|
||||||
{
|
{
|
||||||
FUNCTION(("vfs_read_pages: vnode %p, vecs %p, pos %Ld\n", vnode, vecs, pos));
|
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,
|
return FS_CALL(vnode, read_pages)(vnode->mount->cookie, vnode->private_node,
|
||||||
cookie, pos, vecs, count, _numBytes, mayBlock, fsReenter);
|
cookie, pos, vecs, count, _numBytes, fsReenter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extern "C" status_t
|
extern "C" status_t
|
||||||
vfs_write_pages(struct vnode *vnode, void *cookie, off_t pos, const iovec *vecs,
|
vfs_write_pages(struct vnode *vnode, void *cookie, off_t pos, const iovec *vecs,
|
||||||
size_t count, size_t *_numBytes, bool mayBlock, bool fsReenter)
|
size_t count, size_t *_numBytes, bool fsReenter)
|
||||||
{
|
{
|
||||||
FUNCTION(("vfs_write_pages: vnode %p, vecs %p, pos %Ld\n", vnode, vecs, pos));
|
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,
|
return FS_CALL(vnode, write_pages)(vnode->mount->cookie, vnode->private_node,
|
||||||
cookie, pos, vecs, count, _numBytes, mayBlock, fsReenter);
|
cookie, pos, vecs, count, _numBytes, fsReenter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3880,7 +3880,7 @@ fault_find_page(vm_translation_map *map, vm_cache *topCache,
|
|||||||
|
|
||||||
// read it in
|
// read it in
|
||||||
status_t status = store->ops->read(store, cacheOffset, &vec, 1,
|
status_t status = store->ops->read(store, cacheOffset, &vec, 1,
|
||||||
&bytesRead, true, false);
|
&bytesRead, false);
|
||||||
|
|
||||||
map->ops->put_physical_page((addr_t)vec.iov_base);
|
map->ops->put_physical_page((addr_t)vec.iov_base);
|
||||||
|
|
||||||
|
|||||||
@@ -803,7 +803,7 @@ page_scrubber(void *unused)
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
write_page(vm_page *page, bool mayBlock, bool fsReenter)
|
write_page(vm_page *page, bool fsReenter)
|
||||||
{
|
{
|
||||||
vm_store *store = page->cache->store;
|
vm_store *store = page->cache->store;
|
||||||
size_t length = B_PAGE_SIZE;
|
size_t length = B_PAGE_SIZE;
|
||||||
@@ -819,7 +819,7 @@ write_page(vm_page *page, bool mayBlock, bool fsReenter)
|
|||||||
vecs->iov_len = B_PAGE_SIZE;
|
vecs->iov_len = B_PAGE_SIZE;
|
||||||
|
|
||||||
status = store->ops->write(store, (off_t)page->cache_offset << PAGE_SHIFT,
|
status = store->ops->write(store, (off_t)page->cache_offset << PAGE_SHIFT,
|
||||||
vecs, 1, &length, mayBlock, fsReenter);
|
vecs, 1, &length, fsReenter);
|
||||||
|
|
||||||
vm_put_physical_page((addr_t)vecs[0].iov_base);
|
vm_put_physical_page((addr_t)vecs[0].iov_base);
|
||||||
#if 0
|
#if 0
|
||||||
@@ -973,7 +973,7 @@ page_writer(void* /*unused*/)
|
|||||||
// TODO: put this as requests into the I/O scheduler
|
// TODO: put this as requests into the I/O scheduler
|
||||||
status_t writeStatus[kNumPages];
|
status_t writeStatus[kNumPages];
|
||||||
for (uint32 i = 0; i < numPages; i++) {
|
for (uint32 i = 0; i < numPages; i++) {
|
||||||
writeStatus[i] = write_page(pages[i], false, false);
|
writeStatus[i] = write_page(pages[i], false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark pages depending on whether they could be written or not
|
// mark pages depending on whether they could be written or not
|
||||||
@@ -1258,7 +1258,7 @@ vm_page_write_modified_pages(vm_cache *cache, bool fsReenter)
|
|||||||
vm_clear_map_flags(page, PAGE_MODIFIED);
|
vm_clear_map_flags(page, PAGE_MODIFIED);
|
||||||
|
|
||||||
mutex_unlock(&cache->lock);
|
mutex_unlock(&cache->lock);
|
||||||
status_t status = write_page(page, true, fsReenter);
|
status_t status = write_page(page, fsReenter);
|
||||||
mutex_lock(&cache->lock);
|
mutex_lock(&cache->lock);
|
||||||
|
|
||||||
InterruptsSpinLocker locker(&sPageLock);
|
InterruptsSpinLocker locker(&sPageLock);
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ anonymous_has_page(struct vm_store *store, off_t offset)
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
anonymous_read(struct vm_store *store, off_t offset, const iovec *vecs,
|
anonymous_read(struct vm_store *store, off_t offset, const iovec *vecs,
|
||||||
size_t count, size_t *_numBytes, bool mayBlock, bool fsReenter)
|
size_t count, size_t *_numBytes, bool fsReenter)
|
||||||
{
|
{
|
||||||
panic("anonymous_store: read called. Invalid!\n");
|
panic("anonymous_store: read called. Invalid!\n");
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
@@ -99,7 +99,7 @@ anonymous_read(struct vm_store *store, off_t offset, const iovec *vecs,
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
anonymous_write(struct vm_store *store, off_t offset, const iovec *vecs,
|
anonymous_write(struct vm_store *store, off_t offset, const iovec *vecs,
|
||||||
size_t count, size_t *_numBytes, bool mayBlock, bool fsReenter)
|
size_t count, size_t *_numBytes, bool fsReenter)
|
||||||
{
|
{
|
||||||
// no place to write, this will cause the page daemon to skip this store
|
// no place to write, this will cause the page daemon to skip this store
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ device_has_page(struct vm_store *store, off_t offset)
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
device_read(struct vm_store *store, off_t offset, const iovec *vecs,
|
device_read(struct vm_store *store, off_t offset, const iovec *vecs,
|
||||||
size_t count, size_t *_numBytes, bool mayBlock, bool fsReenter)
|
size_t count, size_t *_numBytes, bool fsReenter)
|
||||||
{
|
{
|
||||||
panic("device_store: read called. Invalid!\n");
|
panic("device_store: read called. Invalid!\n");
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
@@ -55,7 +55,7 @@ device_read(struct vm_store *store, off_t offset, const iovec *vecs,
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
device_write(struct vm_store *store, off_t offset, const iovec *vecs,
|
device_write(struct vm_store *store, off_t offset, const iovec *vecs,
|
||||||
size_t count, size_t *_numBytes, bool mayBlock, bool fsReenter)
|
size_t count, size_t *_numBytes, bool fsReenter)
|
||||||
{
|
{
|
||||||
// no place to write, this will cause the page daemon to skip this store
|
// no place to write, this will cause the page daemon to skip this store
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ null_has_page(struct vm_store *store, off_t offset)
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
null_read(struct vm_store *store, off_t offset, const iovec *vecs,
|
null_read(struct vm_store *store, off_t offset, const iovec *vecs,
|
||||||
size_t count, size_t *_numBytes, bool mayBlock, bool fsReenter)
|
size_t count, size_t *_numBytes, bool fsReenter)
|
||||||
{
|
{
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
@@ -44,7 +44,7 @@ null_read(struct vm_store *store, off_t offset, const iovec *vecs,
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
null_write(struct vm_store *store, off_t offset, const iovec *vecs,
|
null_write(struct vm_store *store, off_t offset, const iovec *vecs,
|
||||||
size_t count, size_t *_numBytes, bool mayBlock, bool fsReenter)
|
size_t count, size_t *_numBytes, bool fsReenter)
|
||||||
{
|
{
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ BuildPlatformStaticLibrary <build>fs_shell.a :
|
|||||||
fcntl.cpp
|
fcntl.cpp
|
||||||
fd.cpp
|
fd.cpp
|
||||||
file_cache.cpp
|
file_cache.cpp
|
||||||
|
file_map.cpp
|
||||||
kernel_export.cpp
|
kernel_export.cpp
|
||||||
KPath.cpp
|
KPath.cpp
|
||||||
hash.cpp
|
hash.cpp
|
||||||
|
|||||||
+76
-1601
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,325 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "fssh_fs_cache.h"
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "fssh_kernel_export.h"
|
||||||
|
#include "vfs.h"
|
||||||
|
|
||||||
|
|
||||||
|
//#define TRACE_FILE_MAP
|
||||||
|
#ifdef TRACE_FILE_MAP
|
||||||
|
# define TRACE(x) fssh_dprintf x
|
||||||
|
#else
|
||||||
|
# define TRACE(x) ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CACHED_FILE_EXTENTS 2
|
||||||
|
// must be smaller than MAX_FILE_IO_VECS
|
||||||
|
// ToDo: find out how much of these are typically used
|
||||||
|
|
||||||
|
using namespace FSShell;
|
||||||
|
|
||||||
|
namespace FSShell {
|
||||||
|
|
||||||
|
struct file_extent {
|
||||||
|
fssh_off_t offset;
|
||||||
|
fssh_file_io_vec disk;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct file_map {
|
||||||
|
file_map();
|
||||||
|
~file_map();
|
||||||
|
|
||||||
|
file_extent *operator[](uint32_t index);
|
||||||
|
file_extent *ExtentAt(uint32_t index);
|
||||||
|
fssh_status_t Add(fssh_file_io_vec *vecs, fssh_size_t vecCount,
|
||||||
|
fssh_off_t &lastOffset);
|
||||||
|
void Free();
|
||||||
|
|
||||||
|
union {
|
||||||
|
file_extent direct[CACHED_FILE_EXTENTS];
|
||||||
|
file_extent *array;
|
||||||
|
};
|
||||||
|
fssh_size_t count;
|
||||||
|
void *vnode;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
file_map::file_map()
|
||||||
|
{
|
||||||
|
array = NULL;
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
file_map::~file_map()
|
||||||
|
{
|
||||||
|
Free();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
file_extent *
|
||||||
|
file_map::operator[](uint32_t index)
|
||||||
|
{
|
||||||
|
return ExtentAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
file_extent *
|
||||||
|
file_map::ExtentAt(uint32_t index)
|
||||||
|
{
|
||||||
|
if (index >= count)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (count > CACHED_FILE_EXTENTS)
|
||||||
|
return &array[index];
|
||||||
|
|
||||||
|
return &direct[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fssh_status_t
|
||||||
|
file_map::Add(fssh_file_io_vec *vecs, fssh_size_t vecCount,
|
||||||
|
fssh_off_t &lastOffset)
|
||||||
|
{
|
||||||
|
TRACE(("file_map::Add(vecCount = %ld)\n", vecCount));
|
||||||
|
|
||||||
|
fssh_off_t offset = 0;
|
||||||
|
|
||||||
|
if (vecCount <= CACHED_FILE_EXTENTS && count == 0) {
|
||||||
|
// just use the reserved area in the file_cache_ref structure
|
||||||
|
} else {
|
||||||
|
// TODO: once we can invalidate only parts of the file map,
|
||||||
|
// we might need to copy the previously cached file extends
|
||||||
|
// from the direct range
|
||||||
|
file_extent *newMap = (file_extent *)realloc(array,
|
||||||
|
(count + vecCount) * sizeof(file_extent));
|
||||||
|
if (newMap == NULL)
|
||||||
|
return FSSH_B_NO_MEMORY;
|
||||||
|
|
||||||
|
array = newMap;
|
||||||
|
|
||||||
|
if (count != 0) {
|
||||||
|
file_extent *extent = ExtentAt(count - 1);
|
||||||
|
offset = extent->offset + extent->disk.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t start = count;
|
||||||
|
count += vecCount;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < vecCount; i++) {
|
||||||
|
file_extent *extent = ExtentAt(start + i);
|
||||||
|
|
||||||
|
extent->offset = offset;
|
||||||
|
extent->disk = vecs[i];
|
||||||
|
|
||||||
|
offset += extent->disk.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TRACE_FILE_MAP
|
||||||
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
|
file_extent *extent = ExtentAt(i);
|
||||||
|
fssh_dprintf("[%ld] extend offset %Ld, disk offset %Ld, length %Ld\n",
|
||||||
|
i, extent->offset, extent->disk.offset, extent->disk.length);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
lastOffset = offset;
|
||||||
|
return FSSH_B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
file_map::Free()
|
||||||
|
{
|
||||||
|
if (count > CACHED_FILE_EXTENTS)
|
||||||
|
free(array);
|
||||||
|
|
||||||
|
array = NULL;
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
static file_extent *
|
||||||
|
find_file_extent(file_map &map, fssh_off_t offset, uint32_t *_index)
|
||||||
|
{
|
||||||
|
// TODO: do binary search
|
||||||
|
|
||||||
|
for (uint32_t index = 0; index < map.count; index++) {
|
||||||
|
file_extent *extent = map[index];
|
||||||
|
|
||||||
|
if (extent->offset <= offset
|
||||||
|
&& extent->offset + extent->disk.length > offset) {
|
||||||
|
if (_index)
|
||||||
|
*_index = index;
|
||||||
|
return extent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace FSShell
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - public FS API
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" void *
|
||||||
|
fssh_file_map_create(fssh_mount_id mountID, fssh_vnode_id vnodeID)
|
||||||
|
{
|
||||||
|
TRACE(("file_map_create(mountID = %ld, vnodeID = %Ld)\n", mountID, vnodeID));
|
||||||
|
|
||||||
|
file_map *map = new file_map;
|
||||||
|
if (map == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Get the vnode for the object
|
||||||
|
// (note, this does not grab a reference to the node)
|
||||||
|
if (vfs_lookup_vnode(mountID, vnodeID, &map->vnode) != FSSH_B_OK) {
|
||||||
|
delete map;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" void
|
||||||
|
fssh_file_map_delete(void *_map)
|
||||||
|
{
|
||||||
|
file_map *map = (file_map *)_map;
|
||||||
|
if (map == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TRACE(("file_map_delete(map = %p)\n", map));
|
||||||
|
delete map;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" void
|
||||||
|
fssh_file_map_set_size(void *_map, fssh_off_t size)
|
||||||
|
{
|
||||||
|
if (_map == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// TODO: honour offset/size parameters
|
||||||
|
file_map *map = (file_map *)_map;
|
||||||
|
map->Free();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" void
|
||||||
|
fssh_file_map_invalidate(void *_map, fssh_off_t offset, fssh_off_t size)
|
||||||
|
{
|
||||||
|
if (_map == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// TODO: honour offset/size parameters
|
||||||
|
file_map *map = (file_map *)_map;
|
||||||
|
map->Free();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" fssh_status_t
|
||||||
|
fssh_file_map_translate(void *_map, fssh_off_t offset, fssh_size_t size,
|
||||||
|
fssh_file_io_vec *vecs, fssh_size_t *_count)
|
||||||
|
{
|
||||||
|
if (_map == NULL)
|
||||||
|
return FSSH_B_BAD_VALUE;
|
||||||
|
|
||||||
|
file_map &map = *(file_map *)_map;
|
||||||
|
fssh_size_t maxVecs = *_count;
|
||||||
|
fssh_status_t status = FSSH_B_OK;
|
||||||
|
|
||||||
|
if (map.count == 0) {
|
||||||
|
// we don't yet have the map of this file, so let's grab it
|
||||||
|
// (ordered by offset, so that we can do a binary search on them)
|
||||||
|
fssh_size_t vecCount = maxVecs;
|
||||||
|
fssh_off_t mapOffset = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
status = vfs_get_file_map(map.vnode, mapOffset, ~0UL, vecs,
|
||||||
|
&vecCount);
|
||||||
|
if (status < FSSH_B_OK && status != FSSH_B_BUFFER_OVERFLOW)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
fssh_status_t addStatus = map.Add(vecs, vecCount, mapOffset);
|
||||||
|
if (addStatus != FSSH_B_OK) {
|
||||||
|
// only clobber the status in case of failure
|
||||||
|
status = addStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != FSSH_B_BUFFER_OVERFLOW)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// when we are here, the map has been stored in the array, and
|
||||||
|
// the array size was still too small to cover the whole file
|
||||||
|
vecCount = maxVecs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != FSSH_B_OK) {
|
||||||
|
// We must invalidate the (part of the) map we already
|
||||||
|
// have, as we cannot know if it's complete or not
|
||||||
|
map.Free();
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We now have cached the map of this file, we now need to
|
||||||
|
// translate it for the requested access.
|
||||||
|
|
||||||
|
uint32_t index;
|
||||||
|
file_extent *fileExtent = find_file_extent(map, offset, &index);
|
||||||
|
if (fileExtent == NULL) {
|
||||||
|
// access outside file bounds? But that's not our problem
|
||||||
|
*_count = 0;
|
||||||
|
return FSSH_B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset -= fileExtent->offset;
|
||||||
|
vecs[0].offset = fileExtent->disk.offset + offset;
|
||||||
|
vecs[0].length = fileExtent->disk.length - offset;
|
||||||
|
|
||||||
|
if (vecs[0].length >= size || index >= map.count - 1) {
|
||||||
|
*_count = 1;
|
||||||
|
return FSSH_B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy the rest of the vecs
|
||||||
|
|
||||||
|
size -= vecs[0].length;
|
||||||
|
|
||||||
|
for (index = 1; index < map.count;) {
|
||||||
|
fileExtent++;
|
||||||
|
|
||||||
|
vecs[index] = fileExtent->disk;
|
||||||
|
index++;
|
||||||
|
|
||||||
|
if (size <= fileExtent->disk.length)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (index >= maxVecs) {
|
||||||
|
*_count = index;
|
||||||
|
return FSSH_B_BUFFER_OVERFLOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
size -= fileExtent->disk.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
*_count = index;
|
||||||
|
return FSSH_B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
+289
-4
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de.
|
* Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include "vfs.h"
|
#include "vfs.h"
|
||||||
|
|
||||||
|
#include <new>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "fd.h"
|
#include "fd.h"
|
||||||
@@ -25,13 +26,13 @@
|
|||||||
#include "fssh_stat.h"
|
#include "fssh_stat.h"
|
||||||
#include "fssh_stdio.h"
|
#include "fssh_stdio.h"
|
||||||
#include "fssh_string.h"
|
#include "fssh_string.h"
|
||||||
|
#include "fssh_uio.h"
|
||||||
#include "fssh_unistd.h"
|
#include "fssh_unistd.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "KPath.h"
|
#include "KPath.h"
|
||||||
#include "posix_compatibility.h"
|
#include "posix_compatibility.h"
|
||||||
#include "syscalls.h"
|
#include "syscalls.h"
|
||||||
|
|
||||||
|
|
||||||
//#define TRACE_VFS
|
//#define TRACE_VFS
|
||||||
#ifdef TRACE_VFS
|
#ifdef TRACE_VFS
|
||||||
# define TRACE(x) fssh_dprintf x
|
# define TRACE(x) fssh_dprintf x
|
||||||
@@ -166,6 +167,8 @@ static struct vnode *sRoot;
|
|||||||
static hash_table *sMountsTable;
|
static hash_table *sMountsTable;
|
||||||
static fssh_mount_id sNextMountID = 1;
|
static fssh_mount_id sNextMountID = 1;
|
||||||
|
|
||||||
|
#define MAX_TEMP_IO_VECS 8
|
||||||
|
|
||||||
fssh_mode_t __fssh_gUmask = 022;
|
fssh_mode_t __fssh_gUmask = 022;
|
||||||
|
|
||||||
/* function declarations */
|
/* function declarations */
|
||||||
@@ -1724,6 +1727,158 @@ get_new_fd(int type, struct fs_mount *mount, struct vnode *vnode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Does the dirty work of combining the file_io_vecs with the iovecs
|
||||||
|
and calls the file system hooks to read/write the request to disk.
|
||||||
|
*/
|
||||||
|
static fssh_status_t
|
||||||
|
common_file_io_vec_pages(int fd, const fssh_file_io_vec *fileVecs,
|
||||||
|
fssh_size_t fileVecCount, const fssh_iovec *vecs, fssh_size_t vecCount,
|
||||||
|
uint32_t *_vecIndex, fssh_size_t *_vecOffset, fssh_size_t *_numBytes,
|
||||||
|
bool doWrite)
|
||||||
|
{
|
||||||
|
if (fileVecCount == 0) {
|
||||||
|
// There are no file vecs at this offset, so we're obviously trying
|
||||||
|
// to access the file outside of its bounds
|
||||||
|
return FSSH_B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
fssh_size_t numBytes = *_numBytes;
|
||||||
|
uint32_t fileVecIndex;
|
||||||
|
fssh_size_t vecOffset = *_vecOffset;
|
||||||
|
uint32_t vecIndex = *_vecIndex;
|
||||||
|
fssh_status_t status;
|
||||||
|
fssh_size_t size;
|
||||||
|
|
||||||
|
if (!doWrite) {
|
||||||
|
// now directly read the data from the device
|
||||||
|
// the first file_io_vec can be read directly
|
||||||
|
|
||||||
|
size = fileVecs[0].length;
|
||||||
|
if (size > numBytes)
|
||||||
|
size = numBytes;
|
||||||
|
|
||||||
|
status = fssh_read_pages(fd, fileVecs[0].offset, vecs, vecCount,
|
||||||
|
&size, false);
|
||||||
|
if (status < FSSH_B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
// TODO: this is a work-around for buggy device drivers!
|
||||||
|
// When our own drivers honour the length, we can:
|
||||||
|
// a) also use this direct I/O for writes (otherwise, it would
|
||||||
|
// overwrite precious data)
|
||||||
|
// b) panic if the term below is true (at least for writes)
|
||||||
|
if (size > fileVecs[0].length) {
|
||||||
|
//dprintf("warning: device driver %p doesn't respect total length in read_pages() call!\n", ref->device);
|
||||||
|
size = fileVecs[0].length;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(size <= fileVecs[0].length);
|
||||||
|
|
||||||
|
// If the file portion was contiguous, we're already done now
|
||||||
|
if (size == numBytes)
|
||||||
|
return FSSH_B_OK;
|
||||||
|
|
||||||
|
// if we reached the end of the file, we can return as well
|
||||||
|
if (size != fileVecs[0].length) {
|
||||||
|
*_numBytes = size;
|
||||||
|
return FSSH_B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileVecIndex = 1;
|
||||||
|
|
||||||
|
// first, find out where we have to continue in our iovecs
|
||||||
|
for (; vecIndex < vecCount; vecIndex++) {
|
||||||
|
if (size < vecs[vecIndex].iov_len)
|
||||||
|
break;
|
||||||
|
|
||||||
|
size -= vecs[vecIndex].iov_len;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fileVecIndex = 0;
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Too bad, let's process the rest of the file_io_vecs
|
||||||
|
|
||||||
|
fssh_size_t totalSize = size;
|
||||||
|
fssh_size_t bytesLeft = numBytes - size;
|
||||||
|
|
||||||
|
for (; fileVecIndex < fileVecCount; fileVecIndex++) {
|
||||||
|
const fssh_file_io_vec &fileVec = fileVecs[fileVecIndex];
|
||||||
|
fssh_off_t fileOffset = fileVec.offset;
|
||||||
|
fssh_off_t fileLeft = fssh_min_c(fileVec.length, bytesLeft);
|
||||||
|
|
||||||
|
TRACE(("FILE VEC [%lu] length %Ld\n", fileVecIndex, fileLeft));
|
||||||
|
|
||||||
|
// process the complete fileVec
|
||||||
|
while (fileLeft > 0) {
|
||||||
|
fssh_iovec tempVecs[MAX_TEMP_IO_VECS];
|
||||||
|
uint32_t tempCount = 0;
|
||||||
|
|
||||||
|
// size tracks how much of what is left of the current fileVec
|
||||||
|
// (fileLeft) has been assigned to tempVecs
|
||||||
|
size = 0;
|
||||||
|
|
||||||
|
// assign what is left of the current fileVec to the tempVecs
|
||||||
|
for (size = 0; size < fileLeft && vecIndex < vecCount
|
||||||
|
&& tempCount < MAX_TEMP_IO_VECS;) {
|
||||||
|
// try to satisfy one iovec per iteration (or as much as
|
||||||
|
// possible)
|
||||||
|
|
||||||
|
// bytes left of the current iovec
|
||||||
|
fssh_size_t vecLeft = vecs[vecIndex].iov_len - vecOffset;
|
||||||
|
if (vecLeft == 0) {
|
||||||
|
vecOffset = 0;
|
||||||
|
vecIndex++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE(("fill vec %ld, offset = %lu, size = %lu\n",
|
||||||
|
vecIndex, vecOffset, size));
|
||||||
|
|
||||||
|
// actually available bytes
|
||||||
|
fssh_size_t tempVecSize = fssh_min_c(vecLeft, fileLeft - size);
|
||||||
|
|
||||||
|
tempVecs[tempCount].iov_base
|
||||||
|
= (void *)((fssh_addr_t)vecs[vecIndex].iov_base + vecOffset);
|
||||||
|
tempVecs[tempCount].iov_len = tempVecSize;
|
||||||
|
tempCount++;
|
||||||
|
|
||||||
|
size += tempVecSize;
|
||||||
|
vecOffset += tempVecSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
fssh_size_t bytes = size;
|
||||||
|
if (doWrite) {
|
||||||
|
status = fssh_write_pages(fd, fileOffset, tempVecs,
|
||||||
|
tempCount, &bytes, false);
|
||||||
|
} else {
|
||||||
|
status = fssh_read_pages(fd, fileOffset, tempVecs,
|
||||||
|
tempCount, &bytes, false);
|
||||||
|
}
|
||||||
|
if (status < FSSH_B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
totalSize += bytes;
|
||||||
|
bytesLeft -= size;
|
||||||
|
fileOffset += size;
|
||||||
|
fileLeft -= size;
|
||||||
|
|
||||||
|
if (size != bytes || vecIndex >= vecCount) {
|
||||||
|
// there are no more bytes or iovecs, let's bail out
|
||||||
|
*_numBytes = totalSize;
|
||||||
|
return FSSH_B_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*_vecIndex = vecIndex;
|
||||||
|
*_vecOffset = vecOffset;
|
||||||
|
*_numBytes = totalSize;
|
||||||
|
return FSSH_B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - public VFS API
|
// #pragma mark - public VFS API
|
||||||
|
|
||||||
|
|
||||||
@@ -1895,6 +2050,110 @@ fssh_get_vnode_removed(fssh_mount_id mountID, fssh_vnode_id vnodeID,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! Works directly on the host's file system
|
||||||
|
extern "C" fssh_status_t
|
||||||
|
fssh_read_pages(int fd, fssh_off_t pos, const fssh_iovec *vecs,
|
||||||
|
fssh_size_t count, fssh_size_t *_numBytes, bool fsReenter)
|
||||||
|
{
|
||||||
|
// check how much the iovecs allow us to read
|
||||||
|
fssh_size_t toRead = 0;
|
||||||
|
for (fssh_size_t i = 0; i < count; i++)
|
||||||
|
toRead += vecs[i].iov_len;
|
||||||
|
|
||||||
|
fssh_iovec* newVecs = NULL;
|
||||||
|
if (*_numBytes < toRead) {
|
||||||
|
// We're supposed to read less than specified by the vecs. Since
|
||||||
|
// readv_pos() doesn't support this, we need to clone the vecs.
|
||||||
|
newVecs = new(nothrow) fssh_iovec[count];
|
||||||
|
if (!newVecs)
|
||||||
|
return FSSH_B_NO_MEMORY;
|
||||||
|
|
||||||
|
fssh_size_t newCount = 0;
|
||||||
|
for (fssh_size_t i = 0; i < count && toRead > 0; i++) {
|
||||||
|
fssh_size_t vecLen = fssh_min_c(vecs[i].iov_len, toRead);
|
||||||
|
newVecs[i].iov_base = vecs[i].iov_base;
|
||||||
|
newVecs[i].iov_len = vecLen;
|
||||||
|
toRead -= vecLen;
|
||||||
|
newCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
vecs = newVecs;
|
||||||
|
count = newCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
fssh_ssize_t bytesRead = fssh_readv_pos(fd, pos, vecs, count);
|
||||||
|
delete[] newVecs;
|
||||||
|
if (bytesRead < 0)
|
||||||
|
return fssh_get_errno();
|
||||||
|
|
||||||
|
*_numBytes = bytesRead;
|
||||||
|
return FSSH_B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! Works directly on the host's file system
|
||||||
|
extern "C" fssh_status_t
|
||||||
|
fssh_write_pages(int fd, fssh_off_t pos, const fssh_iovec *vecs,
|
||||||
|
fssh_size_t count, fssh_size_t *_numBytes, bool fsReenter)
|
||||||
|
{
|
||||||
|
// check how much the iovecs allow us to write
|
||||||
|
fssh_size_t toWrite = 0;
|
||||||
|
for (fssh_size_t i = 0; i < count; i++)
|
||||||
|
toWrite += vecs[i].iov_len;
|
||||||
|
|
||||||
|
fssh_iovec* newVecs = NULL;
|
||||||
|
if (*_numBytes < toWrite) {
|
||||||
|
// We're supposed to write less than specified by the vecs. Since
|
||||||
|
// writev_pos() doesn't support this, we need to clone the vecs.
|
||||||
|
newVecs = new(nothrow) fssh_iovec[count];
|
||||||
|
if (!newVecs)
|
||||||
|
return FSSH_B_NO_MEMORY;
|
||||||
|
|
||||||
|
fssh_size_t newCount = 0;
|
||||||
|
for (fssh_size_t i = 0; i < count && toWrite > 0; i++) {
|
||||||
|
fssh_size_t vecLen = fssh_min_c(vecs[i].iov_len, toWrite);
|
||||||
|
newVecs[i].iov_base = vecs[i].iov_base;
|
||||||
|
newVecs[i].iov_len = vecLen;
|
||||||
|
toWrite -= vecLen;
|
||||||
|
newCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
vecs = newVecs;
|
||||||
|
count = newCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
fssh_ssize_t bytesWritten = fssh_writev_pos(fd, pos, vecs, count);
|
||||||
|
delete[] newVecs;
|
||||||
|
if (bytesWritten < 0)
|
||||||
|
return fssh_get_errno();
|
||||||
|
|
||||||
|
*_numBytes = bytesWritten;
|
||||||
|
return FSSH_B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! Works directly on the host's file system
|
||||||
|
extern "C" fssh_status_t
|
||||||
|
fssh_read_file_io_vec_pages(int fd, const fssh_file_io_vec *fileVecs,
|
||||||
|
fssh_size_t fileVecCount, const fssh_iovec *vecs, fssh_size_t vecCount,
|
||||||
|
uint32_t *_vecIndex, fssh_size_t *_vecOffset, fssh_size_t *_bytes)
|
||||||
|
{
|
||||||
|
return common_file_io_vec_pages(fd, fileVecs, fileVecCount,
|
||||||
|
vecs, vecCount, _vecIndex, _vecOffset, _bytes, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! Works directly on the host's file system
|
||||||
|
extern "C" fssh_status_t
|
||||||
|
fssh_write_file_io_vec_pages(int fd, const fssh_file_io_vec *fileVecs,
|
||||||
|
fssh_size_t fileVecCount, const fssh_iovec *vecs, fssh_size_t vecCount,
|
||||||
|
uint32_t *_vecIndex, fssh_size_t *_vecOffset, fssh_size_t *_bytes)
|
||||||
|
{
|
||||||
|
return common_file_io_vec_pages(fd, fileVecs, fileVecCount,
|
||||||
|
vecs, vecCount, _vecIndex, _vecOffset, _bytes, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - private VFS API
|
// #pragma mark - private VFS API
|
||||||
// Functions the VFS exports for other parts of the kernel
|
// Functions the VFS exports for other parts of the kernel
|
||||||
|
|
||||||
@@ -1980,16 +2239,42 @@ vfs_get_vnode(fssh_mount_id mountID, fssh_vnode_id vnodeID, void **_vnode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fssh_status_t
|
||||||
|
vfs_read_pages(void *_vnode, void *cookie, fssh_off_t pos,
|
||||||
|
const fssh_iovec *vecs, fssh_size_t count, fssh_size_t *_numBytes,
|
||||||
|
bool fsReenter)
|
||||||
|
{
|
||||||
|
struct vnode *vnode = (struct vnode *)_vnode;
|
||||||
|
|
||||||
|
return FS_CALL(vnode, read_pages)(vnode->mount->cookie, vnode->private_node,
|
||||||
|
cookie, pos, vecs, count, _numBytes, fsReenter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fssh_status_t
|
||||||
|
vfs_write_pages(void *_vnode, void *cookie, fssh_off_t pos,
|
||||||
|
const fssh_iovec *vecs, fssh_size_t count, fssh_size_t *_numBytes,
|
||||||
|
bool fsReenter)
|
||||||
|
{
|
||||||
|
struct vnode *vnode = (struct vnode *)_vnode;
|
||||||
|
|
||||||
|
return FS_CALL(vnode, write_pages)(vnode->mount->cookie, vnode->private_node,
|
||||||
|
cookie, pos, vecs, count, _numBytes, fsReenter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fssh_status_t
|
fssh_status_t
|
||||||
vfs_entry_ref_to_vnode(fssh_mount_id mountID, fssh_vnode_id directoryID,
|
vfs_entry_ref_to_vnode(fssh_mount_id mountID, fssh_vnode_id directoryID,
|
||||||
const char *name, void **_vnode)
|
const char *name, void **_vnode)
|
||||||
{
|
{
|
||||||
return entry_ref_to_vnode(mountID, directoryID, name, (struct vnode **)_vnode);
|
return entry_ref_to_vnode(mountID, directoryID, name,
|
||||||
|
(struct vnode **)_vnode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
vfssh_fs_vnode_to_node_ref(void *_vnode, fssh_mount_id *_mountID, fssh_vnode_id *_vnodeID)
|
vfs_fs_vnode_to_node_ref(void *_vnode, fssh_mount_id *_mountID,
|
||||||
|
fssh_vnode_id *_vnodeID)
|
||||||
{
|
{
|
||||||
struct vnode *vnode = (struct vnode *)_vnode;
|
struct vnode *vnode = (struct vnode *)_vnode;
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,12 @@ fssh_status_t vfs_lookup_vnode(fssh_mount_id mountID, fssh_vnode_id vnodeID,
|
|||||||
void vfs_put_vnode(void *vnode);
|
void vfs_put_vnode(void *vnode);
|
||||||
void vfs_acquire_vnode(void *vnode);
|
void vfs_acquire_vnode(void *vnode);
|
||||||
fssh_status_t vfs_get_cookie_from_fd(int fd, void **_cookie);
|
fssh_status_t vfs_get_cookie_from_fd(int fd, void **_cookie);
|
||||||
|
fssh_status_t vfs_read_pages(void *vnode, void *cookie, fssh_off_t pos,
|
||||||
|
const fssh_iovec *vecs, fssh_size_t count,
|
||||||
|
fssh_size_t *_numBytes, bool fsReenter);
|
||||||
|
fssh_status_t vfs_write_pages(void *vnode, void *cookie,
|
||||||
|
fssh_off_t pos, const fssh_iovec *vecs, fssh_size_t count,
|
||||||
|
fssh_size_t *_numBytes, bool fsReenter);
|
||||||
fssh_status_t vfs_get_file_map(void *_vnode, fssh_off_t offset,
|
fssh_status_t vfs_get_file_map(void *_vnode, fssh_off_t offset,
|
||||||
fssh_size_t size, fssh_file_io_vec *vecs,
|
fssh_size_t size, fssh_file_io_vec *vecs,
|
||||||
fssh_size_t *_count);
|
fssh_size_t *_count);
|
||||||
|
|||||||
Reference in New Issue
Block a user