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 20 status_t 21 VMVnodeCache::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 37 status_t 38 VMVnodeCache::Commit(off_t size, int priority) 39 { 40 // We don't need to commit memory. 41 return B_OK; 42 } 43 44 45 bool 46 VMVnodeCache::HasPage(off_t offset) 47 { 48 return ROUNDUP(offset, B_PAGE_SIZE) >= virtual_base 49 && offset < virtual_end; 50 } 51 52 53 status_t 54 VMVnodeCache::Read(off_t offset, const generic_io_vec* vecs, size_t count, 55 uint32 flags, generic_size_t* _numBytes) 56 { 57 generic_size_t bytesUntouched = *_numBytes; 58 59 status_t status = vfs_read_pages(fVnode, NULL, offset, vecs, count, 60 flags, _numBytes); 61 62 generic_size_t bytesEnd = *_numBytes; 63 64 if (offset + (off_t)bytesEnd > virtual_end) 65 bytesEnd = virtual_end - offset; 66 67 // If the request could be filled completely, or an error occured, 68 // we're done here 69 if (status != B_OK || bytesUntouched == bytesEnd) 70 return status; 71 72 bytesUntouched -= bytesEnd; 73 74 // Clear out any leftovers that were not touched by the above read - we're 75 // doing this here so that not every file system/device has to implement 76 // this 77 for (int32 i = count; i-- > 0 && bytesUntouched != 0;) { 78 generic_size_t length = min_c(bytesUntouched, vecs[i].length); 79 80 generic_addr_t address = vecs[i].base + vecs[i].length - length; 81 if ((flags & B_PHYSICAL_IO_REQUEST) != 0) 82 vm_memset_physical(address, 0, length); 83 else 84 memset((void*)(addr_t)address, 0, length); 85 86 bytesUntouched -= length; 87 } 88 89 return B_OK; 90 } 91 92 93 status_t 94 VMVnodeCache::Write(off_t offset, const generic_io_vec* vecs, size_t count, 95 uint32 flags, generic_size_t* _numBytes) 96 { 97 return vfs_write_pages(fVnode, NULL, offset, vecs, count, flags, _numBytes); 98 } 99 100 101 status_t 102 VMVnodeCache::WriteAsync(off_t offset, const generic_io_vec* vecs, size_t count, 103 generic_size_t numBytes, uint32 flags, AsyncIOCallback* callback) 104 { 105 return vfs_asynchronous_write_pages(fVnode, NULL, offset, vecs, count, 106 numBytes, flags, callback); 107 } 108 109 110 status_t 111 VMVnodeCache::Fault(struct VMAddressSpace* aspace, off_t offset) 112 { 113 if (!HasPage(offset)) 114 return B_BAD_ADDRESS; 115 116 // vm_soft_fault() reads the page in. 117 return B_BAD_HANDLER; 118 } 119 120 121 bool 122 VMVnodeCache::CanWritePage(off_t offset) 123 { 124 // all pages can be written 125 return true; 126 } 127 128 129 status_t 130 VMVnodeCache::AcquireUnreferencedStoreRef() 131 { 132 // Quick check whether getting a vnode reference is still allowed. Only 133 // after a successful vfs_get_vnode() the check is safe (since then we've 134 // either got the reference to our vnode, or have been notified that it is 135 // toast), but the check is cheap and saves quite a bit of work in case the 136 // condition holds. 137 if (fVnodeDeleted) 138 return B_BUSY; 139 140 struct vnode* vnode; 141 status_t status = vfs_get_vnode(fDevice, fInode, false, &vnode); 142 143 // If successful, update the store's vnode pointer, so that release_ref() 144 // won't use a stale pointer. 145 if (status == B_OK && fVnodeDeleted) { 146 vfs_put_vnode(vnode); 147 status = B_BUSY; 148 } 149 150 return status; 151 } 152 153 154 void 155 VMVnodeCache::AcquireStoreRef() 156 { 157 vfs_acquire_vnode(fVnode); 158 } 159 160 161 void 162 VMVnodeCache::ReleaseStoreRef() 163 { 164 vfs_put_vnode(fVnode); 165 } 166 167 168 void 169 VMVnodeCache::Dump(bool showPages) const 170 { 171 VMCache::Dump(showPages); 172 173 kprintf(" vnode: %p <%" B_PRIdDEV ", %" B_PRIdINO ">\n", fVnode, 174 fDevice, fInode); 175 } 176 177 178 void 179 VMVnodeCache::DeleteObject() 180 { 181 object_cache_delete(gVnodeCacheObjectCache, this); 182 } 183