win-pvdrivers

view xencache/xencache.c @ 1057:2d5fbe07e866

More XenCache updates
author James Harper <james.harper@bendigoit.com.au>
date Sat Jun 08 10:42:55 2013 +1000 (2013-06-08)
parents a127b9bea695
children
line source
1 /*
2 PV Drivers for Windows Xen HVM Domains
3 Copyright (C) 2013 James Harper
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
20 #include "xencache.h"
22 #define TMEM_CONTROL 0
23 #define TMEM_NEW_POOL 1
24 #define TMEM_DESTROY_POOL 2
25 #define TMEM_NEW_PAGE 3
26 #define TMEM_PUT_PAGE 4
27 #define TMEM_GET_PAGE 5
28 #define TMEM_FLUSH_PAGE 6
29 #define TMEM_FLUSH_OBJECT 7
30 #define TMEM_READ 8
31 #define TMEM_WRITE 9
32 #define TMEM_XCHG 10
34 /* Bits for HYPERVISOR_tmem_op(TMEM_NEW_POOL) */
35 #define TMEM_POOL_PERSIST 1
36 #define TMEM_POOL_SHARED 2
37 #define TMEM_POOL_PAGESIZE_SHIFT 4
38 #define TMEM_VERSION_SHIFT 24
40 /* flags for tmem_ops.new_pool */
41 #define TMEM_POOL_PERSIST 1
42 #define TMEM_POOL_SHARED 2
44 PFLT_FILTER filter_handle;
45 global_context_t global_context;
47 DRIVER_INITIALIZE DriverEntry;
49 NTSTATUS XenCache_FilterUnload(FLT_FILTER_UNLOAD_FLAGS flags);
50 NTSTATUS XenCache_InstanceSetup(PCFLT_RELATED_OBJECTS flt_objects, FLT_INSTANCE_SETUP_FLAGS flags, DEVICE_TYPE volume_device_type, FLT_FILESYSTEM_TYPE volume_filesystem_type);
51 NTSTATUS XenCache_InstanceQueryTeardown(PCFLT_RELATED_OBJECTS flt_objects, FLT_INSTANCE_QUERY_TEARDOWN_FLAGS flags);
52 VOID XenCache_InstanceTeardownStart(PCFLT_RELATED_OBJECTS flt_objects, FLT_INSTANCE_QUERY_TEARDOWN_FLAGS reason);
53 VOID XenCache_InstanceTeardownComplete(PCFLT_RELATED_OBJECTS flt_objects, FLT_INSTANCE_QUERY_TEARDOWN_FLAGS reason);
55 FLT_PREOP_CALLBACK_STATUS XenCache_Pre_CLOSE(PFLT_CALLBACK_DATA data, PCFLT_RELATED_OBJECTS flt_objects, PVOID *completion_context);
56 FLT_POSTOP_CALLBACK_STATUS XenCache_Pst_CLOSE(PFLT_CALLBACK_DATA data, PCFLT_RELATED_OBJECTS flt_objects, PVOID completion_context, FLT_POST_OPERATION_FLAGS flags);
57 FLT_PREOP_CALLBACK_STATUS XenCache_Pre_CLEANUP(PFLT_CALLBACK_DATA data, PCFLT_RELATED_OBJECTS flt_objects, PVOID *completion_context);
58 FLT_POSTOP_CALLBACK_STATUS XenCache_Pst_CLEANUP(PFLT_CALLBACK_DATA data, PCFLT_RELATED_OBJECTS flt_objects, PVOID completion_context, FLT_POST_OPERATION_FLAGS flags);
59 FLT_PREOP_CALLBACK_STATUS XenCache_Pre_READ(PFLT_CALLBACK_DATA data, PCFLT_RELATED_OBJECTS flt_objects, PVOID *completion_context);
60 FLT_PREOP_CALLBACK_STATUS XenCache_Pre_WRITE(PFLT_CALLBACK_DATA data, PCFLT_RELATED_OBJECTS flt_objects, PVOID *completion_context);
62 FLT_OPERATION_REGISTRATION filter_callbacks[] = {
63 { IRP_MJ_CLOSE, 0, XenCache_Pre_CLOSE, XenCache_Pst_CLOSE },
64 { IRP_MJ_CLEANUP, 0, XenCache_Pre_CLEANUP, XenCache_Pst_CLEANUP },
65 { IRP_MJ_READ, 0, XenCache_Pre_READ, NULL },
66 { IRP_MJ_WRITE, 0, XenCache_Pre_WRITE, NULL },
67 { IRP_MJ_OPERATION_END }
68 };
70 FLT_REGISTRATION filter_registration = {
71 sizeof(FLT_REGISTRATION),
72 FLT_REGISTRATION_VERSION,
73 0, // flags
74 NULL, // context_callbacks,
75 filter_callbacks,
76 XenCache_FilterUnload,
77 XenCache_InstanceSetup,
78 XenCache_InstanceQueryTeardown,
79 XenCache_InstanceTeardownStart,
80 XenCache_InstanceTeardownComplete,
81 NULL, // XenCache_GenerateFileName,
82 NULL, // XenCache_NormalizeNameComponentn,
83 NULL, // XenCache_NormalizeContextCleanup,
84 #if FLT_MGR_LONGHORN
85 NULL, // XenCache_TransactionNotification,
86 NULL, // XenCache_NormalizeNameComponentEx,
87 #endif
88 };
90 NTSTATUS
91 DriverEntry(PDRIVER_OBJECT driver_object, PUNICODE_STRING registry_path) {
92 NTSTATUS status;
94 UNREFERENCED_PARAMETER(registry_path);
96 FUNCTION_ENTER();
98 RtlZeroMemory(&global_context, sizeof(global_context_t));
99 KeInitializeSpinLock(&global_context.lock);
101 status = FltRegisterFilter(driver_object, &filter_registration, &filter_handle);
102 FUNCTION_MSG("FltRegisterFilter = %08x\n", status);
104 if (!NT_SUCCESS(status)) {
105 FUNCTION_EXIT();
106 return status;
107 }
108 status = FltStartFiltering(filter_handle);
109 FUNCTION_MSG("FltStartFiltering = %08x\n", status);
110 if (!NT_SUCCESS(status)) {
111 FltUnregisterFilter(filter_handle);
112 }
114 FUNCTION_EXIT();
116 return status;
117 }
119 NTSTATUS
120 XenCache_FilterUnload(FLT_FILTER_UNLOAD_FLAGS flags) {
121 UNREFERENCED_PARAMETER(flags);
122 FUNCTION_ENTER();
123 FltUnregisterFilter(filter_handle);
124 RtlZeroMemory(&global_context, sizeof(global_context_t));
125 FUNCTION_EXIT();
126 return STATUS_SUCCESS;
127 }
129 NTSTATUS
130 XenCache_InstanceSetup(PCFLT_RELATED_OBJECTS flt_objects, FLT_INSTANCE_SETUP_FLAGS flags, DEVICE_TYPE volume_device_type, FLT_FILESYSTEM_TYPE volume_filesystem_type) {
131 FUNCTION_ENTER();
132 if (volume_device_type != FILE_DEVICE_DISK_FILE_SYSTEM) {
133 FUNCTION_MSG("is not disk\n");
134 FUNCTION_EXIT();
135 return STATUS_FLT_DO_NOT_ATTACH;
136 }
137 if (volume_filesystem_type != FLT_FSTYPE_NTFS) {
138 FUNCTION_MSG("is not NTFS\n");
139 FUNCTION_EXIT();
140 return STATUS_FLT_DO_NOT_ATTACH;
141 }
142 FUNCTION_MSG("flt_objects = %p\n", flt_objects);
143 FUNCTION_MSG("flags = %08x\n", flags);
144 FUNCTION_MSG("volume_device_type = %08x\n", volume_device_type);
145 FUNCTION_MSG("volume_filesystem_type = %08x\n", volume_filesystem_type);
146 FUNCTION_EXIT();
147 return STATUS_SUCCESS;
148 }
150 NTSTATUS
151 XenCache_InstanceQueryTeardown(PCFLT_RELATED_OBJECTS flt_objects, FLT_INSTANCE_QUERY_TEARDOWN_FLAGS flags) {
152 FUNCTION_ENTER();
153 FUNCTION_MSG("flt_objects = %p\n", flt_objects);
154 FUNCTION_MSG("flags = %08x\n", flags);
155 FUNCTION_EXIT();
156 return STATUS_SUCCESS;
157 }
159 VOID
160 XenCache_InstanceTeardownStart(PCFLT_RELATED_OBJECTS flt_objects, FLT_INSTANCE_QUERY_TEARDOWN_FLAGS reason) {
161 FUNCTION_ENTER();
162 FUNCTION_MSG("flt_objects = %p\n", flt_objects);
163 FUNCTION_MSG("reason = %08x\n", reason);
164 FUNCTION_EXIT();
165 }
167 VOID
168 XenCache_InstanceTeardownComplete(PCFLT_RELATED_OBJECTS flt_objects, FLT_INSTANCE_QUERY_TEARDOWN_FLAGS reason) {
169 FUNCTION_ENTER();
170 FUNCTION_MSG("flt_objects = %p\n", flt_objects);
171 FUNCTION_MSG("reason = %08x\n", reason);
172 FUNCTION_EXIT();
173 }
175 FLT_PREOP_CALLBACK_STATUS
176 XenCache_Pre_CLOSE(PFLT_CALLBACK_DATA data, PCFLT_RELATED_OBJECTS flt_objects, PVOID *completion_context) {
177 UNREFERENCED_PARAMETER(data);
178 UNREFERENCED_PARAMETER(flt_objects);
179 UNREFERENCED_PARAMETER(completion_context);
180 if (FsRtlIsPagingFile(flt_objects->FileObject)) {
181 FUNCTION_ENTER();
182 FUNCTION_MSG("IRQL = %d\n", KeGetCurrentIrql());
183 FUNCTION_MSG("FileObject = %p\n", flt_objects->FileObject);
184 FUNCTION_MSG("FileName = %S\n", flt_objects->FileObject->FileName.Buffer);
185 FUNCTION_MSG("IsPagingFile = %d\n", FsRtlIsPagingFile(flt_objects->FileObject));
186 FUNCTION_EXIT();
187 }
188 #if 0
189 FUNCTION_ENTER();
190 FUNCTION_MSG("IRQL = %d\n", KeGetCurrentIrql());
191 FUNCTION_MSG("FileObject = %p\n", flt_objects->FileObject);
192 FUNCTION_MSG("FileName = %S\n", flt_objects->FileObject->FileName.Buffer);
193 FUNCTION_MSG("IsPagingFile = %d\n", FsRtlIsPagingFile(flt_objects->FileObject));
194 FUNCTION_EXIT();
195 #endif
196 return FLT_PREOP_SUCCESS_WITH_CALLBACK;
197 }
199 FLT_POSTOP_CALLBACK_STATUS
200 XenCache_Pst_CLOSE(PFLT_CALLBACK_DATA data, PCFLT_RELATED_OBJECTS flt_objects, PVOID completion_context, FLT_POST_OPERATION_FLAGS flags) {
201 UNREFERENCED_PARAMETER(data);
202 UNREFERENCED_PARAMETER(flt_objects);
203 UNREFERENCED_PARAMETER(completion_context);
204 UNREFERENCED_PARAMETER(flags);
205 if (FsRtlIsPagingFile(flt_objects->FileObject)) {
206 FUNCTION_ENTER();
207 FUNCTION_MSG("IRQL = %d\n", KeGetCurrentIrql());
208 FUNCTION_MSG("FileObject = %p\n", flt_objects->FileObject);
209 FUNCTION_MSG("FileName = %S\n", flt_objects->FileObject->FileName.Buffer);
210 FUNCTION_MSG("IsPagingFile = %d\n", FsRtlIsPagingFile(flt_objects->FileObject));
211 FUNCTION_EXIT();
212 }
213 #if 0
214 FUNCTION_ENTER();
215 FUNCTION_MSG("IRQL = %d\n", KeGetCurrentIrql());
216 FUNCTION_MSG("FileObject = %p\n", flt_objects->FileObject);
217 FUNCTION_MSG("FileName = %S\n", flt_objects->FileObject->FileName.Buffer);
218 FUNCTION_MSG("IsPagingFile = %d\n", FsRtlIsPagingFile(flt_objects->FileObject));
219 FUNCTION_EXIT();
220 #endif
221 return FLT_POSTOP_FINISHED_PROCESSING;
222 }
224 FLT_PREOP_CALLBACK_STATUS
225 XenCache_Pre_CLEANUP(PFLT_CALLBACK_DATA data, PCFLT_RELATED_OBJECTS flt_objects, PVOID *completion_context) {
226 UNREFERENCED_PARAMETER(data);
227 UNREFERENCED_PARAMETER(flt_objects);
228 UNREFERENCED_PARAMETER(completion_context);
229 if (FsRtlIsPagingFile(flt_objects->FileObject)) {
230 FUNCTION_ENTER();
231 FUNCTION_MSG("IRQL = %d\n", KeGetCurrentIrql());
232 FUNCTION_MSG("FileObject = %p\n", flt_objects->FileObject);
233 FUNCTION_MSG("FileName = %S\n", flt_objects->FileObject->FileName.Buffer);
234 FUNCTION_MSG("IsPagingFile = %d\n", FsRtlIsPagingFile(flt_objects->FileObject));
235 FUNCTION_EXIT();
236 }
237 #if 0
238 FUNCTION_ENTER();
239 FUNCTION_MSG("IRQL = %d\n", KeGetCurrentIrql());
240 FUNCTION_MSG("FileObject = %p\n", flt_objects->FileObject);
241 FUNCTION_MSG("FileName = %S\n", flt_objects->FileObject->FileName.Buffer);
242 FUNCTION_MSG("IsPagingFile = %d\n", FsRtlIsPagingFile(flt_objects->FileObject));
243 FUNCTION_EXIT();
244 #endif
245 return FLT_PREOP_SUCCESS_WITH_CALLBACK;
246 }
248 FLT_POSTOP_CALLBACK_STATUS
249 XenCache_Pst_CLEANUP(PFLT_CALLBACK_DATA data, PCFLT_RELATED_OBJECTS flt_objects, PVOID completion_context, FLT_POST_OPERATION_FLAGS flags) {
250 UNREFERENCED_PARAMETER(data);
251 UNREFERENCED_PARAMETER(flt_objects);
252 UNREFERENCED_PARAMETER(completion_context);
253 UNREFERENCED_PARAMETER(flags);
254 if (FsRtlIsPagingFile(flt_objects->FileObject)) {
255 FUNCTION_ENTER();
256 FUNCTION_MSG("IRQL = %d\n", KeGetCurrentIrql());
257 FUNCTION_MSG("FileObject = %p\n", flt_objects->FileObject);
258 FUNCTION_MSG("FileName = %S\n", flt_objects->FileObject->FileName.Buffer);
259 FUNCTION_MSG("IsPagingFile = %d\n", FsRtlIsPagingFile(flt_objects->FileObject));
260 FUNCTION_EXIT();
261 }
262 return FLT_POSTOP_FINISHED_PROCESSING;
263 }
265 FLT_PREOP_CALLBACK_STATUS
266 XenCache_Pre_WRITE(PFLT_CALLBACK_DATA data, PCFLT_RELATED_OBJECTS flt_objects, PVOID *completion_context) {
267 pagefile_context_t *context;
268 int i;
269 KIRQL old_irql;
270 LONG rc;
271 struct tmem_op tmem_op;
273 UNREFERENCED_PARAMETER(data);
274 UNREFERENCED_PARAMETER(flt_objects);
275 UNREFERENCED_PARAMETER(completion_context);
277 if (global_context.error_count) {
278 return FLT_PREOP_SUCCESS_NO_CALLBACK;
279 }
280 if (!FsRtlIsPagingFile(flt_objects->FileObject)) {
281 return FLT_PREOP_SUCCESS_NO_CALLBACK;
282 }
284 if (!(data->Flags & FLTFL_CALLBACK_DATA_IRP_OPERATION)) {
285 return FLT_PREOP_SUCCESS_NO_CALLBACK;
286 }
288 KeAcquireSpinLock(&global_context.lock, &old_irql);
289 for (context = global_context.pagefile_head; context; context = context->next) {
290 if (context->file_object == flt_objects->FileObject)
291 break;
292 }
293 if (!context) {
294 context = ExAllocatePoolWithTag(NonPagedPool, sizeof(pagefile_context_t), XENCACHE_POOL_TAG);
295 if (!context) {
296 FUNCTION_MSG("Failed to allocate context\n");
297 /* should probably detach this instance here */
298 KeReleaseSpinLock(&global_context.lock, old_irql);
299 FUNCTION_EXIT();
300 return FLT_PREOP_SUCCESS_NO_CALLBACK;
301 }
302 RtlZeroMemory(context, sizeof(pagefile_context_t));
303 context->file_object = flt_objects->FileObject;
304 context->next = global_context.pagefile_head;
305 tmem_op.cmd = TMEM_NEW_POOL;
306 tmem_op.pool_id = 0; /* this doesn't actually get used for private */
307 tmem_op.u.new.flags = (TMEM_SPEC_VERSION << TMEM_VERSION_SHIFT); /* private, not shared */
308 context->pool_id = XnTmemOp(&tmem_op);
309 FUNCTION_MSG("pool_id = %d\n", context->pool_id);
310 if (context->pool_id < 0) {
311 ExFreePoolWithTag(context, XENCACHE_POOL_TAG);
312 global_context.error_count++;
313 KeReleaseSpinLock(&global_context.lock, old_irql);
314 /* should actually unload here */
315 return FLT_PREOP_SUCCESS_NO_CALLBACK;
316 }
317 global_context.pagefile_head = context;
318 }
320 for (i = 0; i < (int)data->Iopb->Parameters.Write.Length >> PAGE_SHIFT; i++) {
321 ULONG page = (ULONG)(data->Iopb->Parameters.Write.ByteOffset.QuadPart >> PAGE_SHIFT) + i;
323 tmem_op.cmd = TMEM_PUT_PAGE;
324 tmem_op.pool_id = context->pool_id;
325 tmem_op.u.gen.oid[0] = 0;
326 tmem_op.u.gen.oid[1] = 0;
327 tmem_op.u.gen.oid[2] = 0;
328 tmem_op.u.gen.index = page;
329 tmem_op.u.gen.tmem_offset = 0;
330 tmem_op.u.gen.pfn_offset = 0;
331 tmem_op.u.gen.len = 0;
332 set_xen_guest_handle(tmem_op.u.gen.gmfn, (void *)MmGetMdlPfnArray(data->Iopb->Parameters.Write.MdlAddress)[i]);
333 rc = XnTmemOp(&tmem_op);
334 if (rc == 1) {
335 context->put_success_count++;
336 } else if (rc == 0) {
337 context->put_fail_count++;
338 } else {
339 FUNCTION_MSG("TMEM_PUT_PAGE = %d\n", rc);
340 context->put_fail_count++;
341 context->error_count++;
342 }
343 }
344 KeReleaseSpinLock(&global_context.lock, old_irql);
345 if (((context->put_success_count + context->put_fail_count + context->get_success_count + context->get_fail_count) & 0xff) == 0) {
346 FUNCTION_MSG(" put_success_count = %I64d\n", context->put_success_count);
347 FUNCTION_MSG(" put_fail_count = %I64d\n", context->put_fail_count);
348 FUNCTION_MSG(" get_success_count = %I64d\n", context->get_success_count);
349 FUNCTION_MSG(" get_fail_count = %I64d\n", context->get_fail_count);
350 FUNCTION_MSG(" error_count = %I64d\n", context->error_count);
351 }
352 return FLT_PREOP_SUCCESS_NO_CALLBACK;
353 }
355 FLT_PREOP_CALLBACK_STATUS
356 XenCache_Pre_READ(PFLT_CALLBACK_DATA data, PCFLT_RELATED_OBJECTS flt_objects, PVOID *completion_context) {
357 NTSTATUS status;
358 pagefile_context_t *context;
359 KIRQL old_irql;
360 int i;
361 LONG rc;
362 struct tmem_op tmem_op;
364 UNREFERENCED_PARAMETER(data);
365 UNREFERENCED_PARAMETER(flt_objects);
366 UNREFERENCED_PARAMETER(completion_context);
368 if (!FsRtlIsPagingFile(flt_objects->FileObject)) {
369 return FLT_PREOP_SUCCESS_NO_CALLBACK;
370 }
371 KeAcquireSpinLock(&global_context.lock, &old_irql);
372 for (context = global_context.pagefile_head; context; context = context->next) {
373 if (context->file_object == flt_objects->FileObject)
374 break;
375 }
376 if (!context) {
377 /* no need to create context if op is a READ - either something is wrong or we were just loaded */
378 //FUNCTION_MSG("Failed to find context\n");
379 KeReleaseSpinLock(&global_context.lock, old_irql);
380 return FLT_PREOP_SUCCESS_NO_CALLBACK;
381 }
382 if (!(data->Flags & FLTFL_CALLBACK_DATA_IRP_OPERATION)) {
383 KeReleaseSpinLock(&global_context.lock, old_irql);
384 return FLT_PREOP_SUCCESS_NO_CALLBACK;
385 }
387 status = FLT_PREOP_COMPLETE;
388 for (i = 0; i < (int)data->Iopb->Parameters.Read.Length / 4096; i++) {
389 ULONG page = (ULONG)(data->Iopb->Parameters.Read.ByteOffset.QuadPart >> PAGE_SHIFT) + i;
391 tmem_op.cmd = TMEM_GET_PAGE;
392 tmem_op.pool_id = context->pool_id;
393 tmem_op.u.gen.oid[0] = 0;
394 tmem_op.u.gen.oid[1] = 0;
395 tmem_op.u.gen.oid[2] = 0;
396 tmem_op.u.gen.index = page;
397 tmem_op.u.gen.tmem_offset = 0;
398 tmem_op.u.gen.pfn_offset = 0;
399 tmem_op.u.gen.len = 0;
400 set_xen_guest_handle(tmem_op.u.gen.gmfn, (void *)MmGetMdlPfnArray(data->Iopb->Parameters.Read.MdlAddress)[i]);
401 rc = XnTmemOp(&tmem_op);
402 if (rc == 1) {
403 context->get_success_count++;
404 } else if (rc == 0) {
405 status = FLT_PREOP_SUCCESS_NO_CALLBACK;
406 context->get_fail_count++;
407 } else {
408 FUNCTION_MSG("TMEM_GET_PAGE = %d\n", rc);
409 status = FLT_PREOP_SUCCESS_NO_CALLBACK;
410 context->get_fail_count++;
411 context->error_count++;
412 }
413 }
415 if (((context->put_success_count + context->put_fail_count + context->get_success_count + context->get_fail_count) & 0xff) == 0) {
416 FUNCTION_MSG(" put_success_count = %I64d\n", context->put_success_count);
417 FUNCTION_MSG(" put_fail_count = %I64d\n", context->put_fail_count);
418 FUNCTION_MSG(" get_success_count = %I64d\n", context->get_success_count);
419 FUNCTION_MSG(" get_fail_count = %I64d\n", context->get_fail_count);
420 FUNCTION_MSG(" error_count = %I64d\n", context->error_count);
421 }
422 KeReleaseSpinLock(&global_context.lock, old_irql);
424 if (status == FLT_PREOP_COMPLETE) {
425 data->IoStatus.Status = STATUS_SUCCESS;
426 data->IoStatus.Information = data->Iopb->Parameters.Read.Length;
427 }
428 return status;
429 }