xref: /haiku/src/system/kernel/cache/vnode_store.cpp (revision fc7456e9b1ec38c941134ed6d01c438cf289381e)
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