1/* 2 * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2004-2007, Axel D��rfler, axeld@pinc-software.de. 4 * Distributed under the terms of the MIT License. 5 */ 6 7#include "vnode_store.h" 8 9#include <stdlib.h> 10#include <string.h> 11 12#include <file_cache.h> 13#include <slab/Slab.h> 14#include <vfs.h> 15#include <vm/vm.h> 16 17#include "IORequest.h" 18 19 20status_t 21VMVnodeCache::Init(struct vnode* vnode, uint32 allocationFlags) 22{ 23 status_t error = VMCache::Init(CACHE_TYPE_VNODE, allocationFlags); 24 if (error != B_OK) 25 return error; 26 27 fVnode = vnode; 28 fFileCacheRef = NULL; 29 fVnodeDeleted = false; 30 31 vfs_vnode_to_node_ref(fVnode, &fDevice, &fInode); 32 33 return B_OK; 34} 35 36 37bool 38VMVnodeCache::HasPage(off_t offset) 39{ 40 return ROUNDUP(offset, B_PAGE_SIZE) >= virtual_base 41 && offset < virtual_end; 42} 43 44 45status_t 46VMVnodeCache::Read(off_t offset, const generic_io_vec* vecs, size_t count, 47 uint32 flags, generic_size_t* _numBytes) 48{ 49 generic_size_t bytesUntouched = *_numBytes; 50 51 status_t status = vfs_read_pages(fVnode, NULL, offset, vecs, count, 52 flags, _numBytes); 53 54 generic_size_t bytesEnd = *_numBytes; 55 56 if (offset + (off_t)bytesEnd > virtual_end) 57 bytesEnd = virtual_end - offset; 58 59 // If the request could be filled completely, or an error occured, 60 // we're done here 61 if (status != B_OK || bytesUntouched == bytesEnd) 62 return status; 63 64 bytesUntouched -= bytesEnd; 65 66 // Clear out any leftovers that were not touched by the above read - we're 67 // doing this here so that not every file system/device has to implement 68 // this 69 for (int32 i = count; i-- > 0 && bytesUntouched != 0;) { 70 generic_size_t length = min_c(bytesUntouched, vecs[i].length); 71 72 generic_addr_t address = vecs[i].base + vecs[i].length - length; 73 if ((flags & B_PHYSICAL_IO_REQUEST) != 0) 74 vm_memset_physical(address, 0, length); 75 else 76 memset((void*)(addr_t)address, 0, length); 77 78 bytesUntouched -= length; 79 } 80 81 return B_OK; 82} 83 84 85status_t 86VMVnodeCache::Write(off_t offset, const generic_io_vec* vecs, size_t count, 87 uint32 flags, generic_size_t* _numBytes) 88{ 89 return vfs_write_pages(fVnode, NULL, offset, vecs, count, flags, _numBytes); 90} 91 92 93status_t 94VMVnodeCache::WriteAsync(off_t offset, const generic_io_vec* vecs, size_t count, 95 generic_size_t numBytes, uint32 flags, AsyncIOCallback* callback) 96{ 97 return vfs_asynchronous_write_pages(fVnode, NULL, offset, vecs, count, 98 numBytes, flags, callback); 99} 100 101 102status_t 103VMVnodeCache::Fault(struct VMAddressSpace* aspace, off_t offset) 104{ 105 if (!HasPage(offset)) 106 return B_BAD_ADDRESS; 107 108 // vm_soft_fault() reads the page in. 109 return B_BAD_HANDLER; 110} 111 112 113bool 114VMVnodeCache::CanWritePage(off_t offset) 115{ 116 // all pages can be written 117 return true; 118} 119 120 121status_t 122VMVnodeCache::AcquireUnreferencedStoreRef() 123{ 124 // Quick check whether getting a vnode reference is still allowed. Only 125 // after a successful vfs_get_vnode() the check is safe (since then we've 126 // either got the reference to our vnode, or have been notified that it is 127 // toast), but the check is cheap and saves quite a bit of work in case the 128 // condition holds. 129 if (fVnodeDeleted) 130 return B_BUSY; 131 132 struct vnode* vnode; 133 status_t status = vfs_get_vnode(fDevice, fInode, false, &vnode); 134 135 // If successful, update the store's vnode pointer, so that release_ref() 136 // won't use a stale pointer. 137 if (status == B_OK && fVnodeDeleted) { 138 vfs_put_vnode(vnode); 139 status = B_BUSY; 140 } 141 142 return status; 143} 144 145 146void 147VMVnodeCache::AcquireStoreRef() 148{ 149 vfs_acquire_vnode(fVnode); 150} 151 152 153void 154VMVnodeCache::ReleaseStoreRef() 155{ 156 vfs_put_vnode(fVnode); 157} 158 159 160void 161VMVnodeCache::Dump(bool showPages) const 162{ 163 VMCache::Dump(showPages); 164 165 kprintf(" vnode: %p <%" B_PRIdDEV ", %" B_PRIdINO ">\n", fVnode, 166 fDevice, fInode); 167} 168 169 170void 171VMVnodeCache::DeleteObject() 172{ 173 object_cache_delete(gVnodeCacheObjectCache, this); 174} 175