]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_symfile.c
xnu-4903.221.2.tar.gz
[apple/xnu.git] / bsd / kern / kern_symfile.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/* Copyright (c) 1998 Apple Computer, Inc. All rights reserved.
29 *
30 * File: bsd/kern/kern_symfile.c
31 *
1c79356b 32 * HISTORY
1c79356b
A
33 */
34
35#include <mach/vm_param.h>
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/signalvar.h>
40#include <sys/resourcevar.h>
41#include <sys/namei.h>
91447636
A
42#include <sys/vnode_internal.h>
43#include <sys/proc_internal.h>
44#include <sys/kauth.h>
1c79356b
A
45#include <sys/timeb.h>
46#include <sys/times.h>
1c79356b 47#include <sys/acct.h>
91447636 48#include <sys/file_internal.h>
1c79356b
A
49#include <sys/uio.h>
50#include <sys/kernel.h>
51#include <sys/stat.h>
91447636
A
52#include <sys/disk.h>
53#include <sys/conf.h>
3e170ce0 54#include <sys/content_protection.h>
d9a64523 55#include <sys/fsctl.h>
1c79356b
A
56
57#include <mach-o/loader.h>
58#include <mach-o/nlist.h>
59
91447636 60#include <kern/kalloc.h>
1c79356b 61#include <vm/vm_kern.h>
91447636 62#include <pexpert/pexpert.h>
3e170ce0 63#include <IOKit/IOPolledInterface.h>
1c79356b 64
d9a64523
A
65#define HIBERNATE_MIN_PHYSICAL_LBA (34)
66#define HIBERNATE_MIN_FILE_SIZE (1024*1024)
67
2d21ac55
A
68/* This function is called from kern_sysctl in the current process context;
69 * it is exported with the System6.0.exports, but this appears to be a legacy
70 * export, as there are no internal consumers.
1c79356b 71 */
2d21ac55 72int
7ddcb079
A
73get_kernel_symfile(__unused proc_t p, __unused char const **symfile);
74int
2d21ac55 75get_kernel_symfile(__unused proc_t p, __unused char const **symfile)
1c79356b 76{
2d21ac55 77 return KERN_FAILURE;
0b4e3aa0 78}
91447636 79
3a60a9f5
A
80struct kern_direct_file_io_ref_t
81{
d9a64523
A
82 vfs_context_t ctx;
83 struct vnode * vp;
84 dev_t device;
85 uint32_t blksize;
86 off_t filelength;
87 char cf;
88 char pinned;
89 char frozen;
90 char wbcranged;
3a60a9f5
A
91};
92
93
6d2010ae 94static int file_ioctl(void * p1, void * p2, u_long theIoctl, caddr_t result)
3a60a9f5 95{
b0d623f7 96 dev_t device = *(dev_t*) p1;
3a60a9f5
A
97
98 return ((*bdevsw[major(device)].d_ioctl)
99 (device, theIoctl, result, S_IFBLK, p2));
100}
101
6d2010ae 102static int device_ioctl(void * p1, __unused void * p2, u_long theIoctl, caddr_t result)
3a60a9f5
A
103{
104 return (VNOP_IOCTL(p1, theIoctl, result, 0, p2));
105}
106
316670eb
A
107static int
108kern_ioctl_file_extents(struct kern_direct_file_io_ref_t * ref, u_long theIoctl, off_t offset, off_t end)
109{
3e170ce0 110 int error = 0;
316670eb
A
111 int (*do_ioctl)(void * p1, void * p2, u_long theIoctl, caddr_t result);
112 void * p1;
113 void * p2;
114 uint64_t fileblk;
115 size_t filechunk;
116 dk_extent_t extent;
117 dk_unmap_t unmap;
118 _dk_cs_pin_t pin;
119
120 bzero(&extent, sizeof(dk_extent_t));
121 bzero(&unmap, sizeof(dk_unmap_t));
122 bzero(&pin, sizeof(pin));
123 if (ref->vp->v_type == VREG)
124 {
125 p1 = &ref->device;
126 p2 = kernproc;
127 do_ioctl = &file_ioctl;
128 }
129 else
130 {
131 /* Partition. */
132 p1 = ref->vp;
133 p2 = ref->ctx;
134 do_ioctl = &device_ioctl;
135 }
3e170ce0
A
136
137 if (_DKIOCCSPINEXTENT == theIoctl) {
138 /* Tell CS the image size, so it knows whether to place the subsequent pins SSD/HDD */
139 pin.cp_extent.length = end;
140 pin.cp_flags = _DKIOCCSHIBERNATEIMGSIZE;
141 (void) do_ioctl(p1, p2, _DKIOCCSPINEXTENT, (caddr_t)&pin);
142 } else if (_DKIOCCSUNPINEXTENT == theIoctl) {
143 /* Tell CS hibernation is done, so it can stop blocking overlapping writes */
144 pin.cp_flags = _DKIOCCSPINDISCARDBLACKLIST;
145 (void) do_ioctl(p1, p2, _DKIOCCSUNPINEXTENT, (caddr_t)&pin);
146 }
147
39037602 148 for (; offset < end; offset += filechunk)
316670eb
A
149 {
150 if (ref->vp->v_type == VREG)
151 {
152 daddr64_t blkno;
153 filechunk = 1*1024*1024*1024;
154 if (filechunk > (size_t)(end - offset))
155 filechunk = (size_t)(end - offset);
fe8ab488 156 error = VNOP_BLOCKMAP(ref->vp, offset, filechunk, &blkno,
5ba3f43e 157 &filechunk, NULL, VNODE_WRITE | VNODE_BLOCKMAP_NO_TRACK, NULL);
39037602
A
158 if (error) break;
159 if (-1LL == blkno) continue;
316670eb
A
160 fileblk = blkno * ref->blksize;
161 }
162 else if ((ref->vp->v_type == VBLK) || (ref->vp->v_type == VCHR))
163 {
164 fileblk = offset;
165 filechunk = ref->filelength;
166 }
167
168 if (DKIOCUNMAP == theIoctl)
169 {
170 extent.offset = fileblk;
171 extent.length = filechunk;
172 unmap.extents = &extent;
173 unmap.extentsCount = 1;
174 error = do_ioctl(p1, p2, theIoctl, (caddr_t)&unmap);
175// printf("DKIOCUNMAP(%d) 0x%qx, 0x%qx\n", error, extent.offset, extent.length);
176 }
177 else if (_DKIOCCSPINEXTENT == theIoctl)
178 {
179 pin.cp_extent.offset = fileblk;
180 pin.cp_extent.length = filechunk;
fe8ab488 181 pin.cp_flags = _DKIOCCSPINFORHIBERNATION;
316670eb
A
182 error = do_ioctl(p1, p2, theIoctl, (caddr_t)&pin);
183 if (error && (ENOTTY != error))
184 {
3e170ce0
A
185 printf("_DKIOCCSPINEXTENT(%d) 0x%qx, 0x%qx\n", error, pin.cp_extent.offset, pin.cp_extent.length);
186 }
187 }
188 else if (_DKIOCCSUNPINEXTENT == theIoctl)
189 {
190 pin.cp_extent.offset = fileblk;
191 pin.cp_extent.length = filechunk;
192 pin.cp_flags = _DKIOCCSPINFORHIBERNATION;
193 error = do_ioctl(p1, p2, theIoctl, (caddr_t)&pin);
194 if (error && (ENOTTY != error))
195 {
196 printf("_DKIOCCSUNPINEXTENT(%d) 0x%qx, 0x%qx\n", error, pin.cp_extent.offset, pin.cp_extent.length);
316670eb
A
197 }
198 }
199 else error = EINVAL;
200
3e170ce0 201 if (error) break;
316670eb
A
202 }
203 return (error);
204}
205
3e170ce0 206extern uint32_t freespace_mb(vnode_t vp);
7ddcb079 207
3a60a9f5
A
208struct kern_direct_file_io_ref_t *
209kern_open_file_for_direct_io(const char * name,
d9a64523 210 uint32_t iflags,
3a60a9f5
A
211 kern_get_file_extents_callback_t callback,
212 void * callback_ref,
db609669 213 off_t set_file_size,
3e170ce0 214 off_t fs_free_size,
db609669 215 off_t write_file_offset,
3e170ce0
A
216 void * write_file_addr,
217 size_t write_file_len,
6d2010ae
A
218 dev_t * partition_device_result,
219 dev_t * image_device_result,
3a60a9f5 220 uint64_t * partitionbase_result,
0b4c1975 221 uint64_t * maxiocount_result,
db609669 222 uint32_t * oflags)
3a60a9f5
A
223{
224 struct kern_direct_file_io_ref_t * ref;
225
3e170ce0
A
226 proc_t p;
227 struct vnode_attr va;
d9a64523 228 dk_apfs_wbc_range_t wbc_range;
3e170ce0
A
229 int error;
230 off_t f_offset;
231 uint64_t fileblk;
232 size_t filechunk;
d9a64523 233 uint64_t physoffset, minoffset;
3e170ce0
A
234 dev_t device;
235 dev_t target = 0;
236 int isssd = 0;
237 uint32_t flags = 0;
238 uint32_t blksize;
d9a64523 239 off_t maxiocount, count, segcount, wbctotal;
3e170ce0
A
240 boolean_t locked = FALSE;
241 int fmode, cmode;
242 struct nameidata nd;
243 u_int32_t ndflags;
244 off_t mpFree;
3a60a9f5 245
6d2010ae
A
246 int (*do_ioctl)(void * p1, void * p2, u_long theIoctl, caddr_t result);
247 void * p1 = NULL;
248 void * p2 = NULL;
3a60a9f5
A
249
250 error = EFAULT;
251
252 ref = (struct kern_direct_file_io_ref_t *) kalloc(sizeof(struct kern_direct_file_io_ref_t));
253 if (!ref)
254 {
255 error = EFAULT;
256 goto out;
257 }
258
316670eb 259 bzero(ref, sizeof(*ref));
6d2010ae 260 p = kernproc;
00867663 261 ref->ctx = vfs_context_kernel();
3a60a9f5 262
d9a64523 263 fmode = (kIOPolledFileCreate & iflags) ? (O_CREAT | FWRITE) : FWRITE;
3e170ce0
A
264 cmode = S_IRUSR | S_IWUSR;
265 ndflags = NOFOLLOW;
266 NDINIT(&nd, LOOKUP, OP_OPEN, ndflags, UIO_SYSSPACE, CAST_USER_ADDR_T(name), ref->ctx);
267 VATTR_INIT(&va);
268 VATTR_SET(&va, va_mode, cmode);
269 VATTR_SET(&va, va_dataprotect_flags, VA_DP_RAWENCRYPTED);
270 VATTR_SET(&va, va_dataprotect_class, PROTECTION_CLASS_D);
00867663
A
271 if ((error = vn_open_auth(&nd, &fmode, &va))) {
272 kprintf("vn_open_auth(fmode: %d, cmode: %d) failed with error: %d\n", fmode, cmode, error);
273 goto out;
274 }
3a60a9f5 275
3e170ce0 276 ref->vp = nd.ni_vp;
39236c6e
A
277 if (ref->vp->v_type == VREG)
278 {
279 vnode_lock_spin(ref->vp);
280 SET(ref->vp->v_flag, VSWAP);
281 vnode_unlock(ref->vp);
282 }
283
db609669 284 if (write_file_addr && write_file_len)
6d2010ae 285 {
d9a64523
A
286 if ((error = kern_write_file(ref, write_file_offset, write_file_addr, write_file_len, IO_SKIP_ENCRYPTION))) {
287 kprintf("kern_write_file() failed with error: %d\n", error);
288 goto out;
289 }
6d2010ae
A
290 }
291
3a60a9f5
A
292 VATTR_INIT(&va);
293 VATTR_WANTED(&va, va_rdev);
294 VATTR_WANTED(&va, va_fsid);
39037602 295 VATTR_WANTED(&va, va_devid);
3a60a9f5 296 VATTR_WANTED(&va, va_data_size);
39236c6e 297 VATTR_WANTED(&va, va_data_alloc);
3a60a9f5
A
298 VATTR_WANTED(&va, va_nlink);
299 error = EFAULT;
3e170ce0 300 if (vnode_getattr(ref->vp, &va, ref->ctx)) goto out;
3a60a9f5 301
d9a64523 302 wbctotal = 0;
3e170ce0
A
303 mpFree = freespace_mb(ref->vp);
304 mpFree <<= 20;
305 kprintf("kern_direct_file(%s): vp size %qd, alloc %qd, mp free %qd, keep free %qd\n",
306 name, va.va_data_size, va.va_data_alloc, mpFree, fs_free_size);
3a60a9f5
A
307
308 if (ref->vp->v_type == VREG)
309 {
3e170ce0
A
310 /* Don't dump files with links. */
311 if (va.va_nlink != 1) goto out;
3a60a9f5 312
39037602 313 device = (VATTR_IS_SUPPORTED(&va, va_devid)) ? va.va_devid : va.va_fsid;
db609669
A
314 ref->filelength = va.va_data_size;
315
b0d623f7 316 p1 = &device;
3a60a9f5
A
317 p2 = p;
318 do_ioctl = &file_ioctl;
db609669 319
d9a64523
A
320 if (kIOPolledFileHibernate & iflags)
321 {
322 error = do_ioctl(p1, p2, DKIOCAPFSGETWBCRANGE, (caddr_t) &wbc_range);
323 ref->wbcranged = (error == 0);
324 }
325 if (ref->wbcranged)
326 {
327 uint32_t idx;
328 assert(wbc_range.count <= (sizeof(wbc_range.extents) / sizeof(wbc_range.extents[0])));
329 for (idx = 0; idx < wbc_range.count; idx++) wbctotal += wbc_range.extents[idx].length;
330 kprintf("kern_direct_file(%s): wbc %qd\n", name, wbctotal);
331 if (wbctotal) target = wbc_range.dev;
332 }
333
3e170ce0
A
334 if (set_file_size)
335 {
d9a64523
A
336 if (wbctotal)
337 {
338 if (wbctotal >= set_file_size) set_file_size = HIBERNATE_MIN_FILE_SIZE;
339 else
340 {
341 set_file_size -= wbctotal;
342 if (set_file_size < HIBERNATE_MIN_FILE_SIZE) set_file_size = HIBERNATE_MIN_FILE_SIZE;
343 }
344 }
3e170ce0
A
345 if (fs_free_size)
346 {
347 mpFree += va.va_data_alloc;
348 if ((mpFree < set_file_size) || ((mpFree - set_file_size) < fs_free_size))
349 {
350 error = ENOSPC;
351 goto out;
fe8ab488 352 }
3e170ce0
A
353 }
354 error = vnode_setsize(ref->vp, set_file_size, IO_NOZEROFILL | IO_NOAUTH, ref->ctx);
355 if (error) goto out;
356 ref->filelength = set_file_size;
357 }
3a60a9f5
A
358 }
359 else if ((ref->vp->v_type == VBLK) || (ref->vp->v_type == VCHR))
360 {
361 /* Partition. */
362 device = va.va_rdev;
363
364 p1 = ref->vp;
2d21ac55 365 p2 = ref->ctx;
3a60a9f5
A
366 do_ioctl = &device_ioctl;
367 }
368 else
369 {
370 /* Don't dump to non-regular files. */
3e170ce0 371 error = EFAULT;
3a60a9f5
A
372 goto out;
373 }
6d2010ae
A
374 ref->device = device;
375
3e170ce0
A
376 // probe for CF
377 dk_corestorage_info_t cs_info;
378 memset(&cs_info, 0, sizeof(dk_corestorage_info_t));
379 error = do_ioctl(p1, p2, DKIOCCORESTORAGE, (caddr_t)&cs_info);
380 ref->cf = (error == 0) && (cs_info.flags & DK_CORESTORAGE_ENABLE_HOTFILES);
381
6d2010ae
A
382 // get block size
383
7ddcb079 384 error = do_ioctl(p1, p2, DKIOCGETBLOCKSIZE, (caddr_t) &ref->blksize);
6d2010ae
A
385 if (error)
386 goto out;
387
d9a64523
A
388 minoffset = HIBERNATE_MIN_PHYSICAL_LBA * ref->blksize;
389
db609669 390 if (ref->vp->v_type != VREG)
6d2010ae
A
391 {
392 error = do_ioctl(p1, p2, DKIOCGETBLOCKCOUNT, (caddr_t) &fileblk);
3e170ce0 393 if (error) goto out;
7ddcb079 394 ref->filelength = fileblk * ref->blksize;
6d2010ae
A
395 }
396
d9a64523 397 // pin logical extents, CS version
316670eb
A
398
399 error = kern_ioctl_file_extents(ref, _DKIOCCSPINEXTENT, 0, ref->filelength);
400 if (error && (ENOTTY != error)) goto out;
401 ref->pinned = (error == 0);
402
d9a64523
A
403 // pin logical extents, apfs version
404
405 error = VNOP_IOCTL(ref->vp, FSCTL_FREEZE_EXTENTS, NULL, 0, ref->ctx);
406 if (error && (ENOTTY != error)) goto out;
407 ref->frozen = (error == 0);
408
316670eb
A
409 // generate the block list
410
411 error = do_ioctl(p1, p2, DKIOCLOCKPHYSICALEXTENTS, NULL);
3e170ce0 412 if (error) goto out;
316670eb
A
413 locked = TRUE;
414
6d2010ae 415 f_offset = 0;
39037602 416 for (; f_offset < ref->filelength; f_offset += filechunk)
6d2010ae
A
417 {
418 if (ref->vp->v_type == VREG)
419 {
420 filechunk = 1*1024*1024*1024;
421 daddr64_t blkno;
422
fe8ab488 423 error = VNOP_BLOCKMAP(ref->vp, f_offset, filechunk, &blkno,
5ba3f43e 424 &filechunk, NULL, VNODE_WRITE | VNODE_BLOCKMAP_NO_TRACK, NULL);
3e170ce0 425 if (error) goto out;
39037602 426 if (-1LL == blkno) continue;
7ddcb079 427 fileblk = blkno * ref->blksize;
6d2010ae
A
428 }
429 else if ((ref->vp->v_type == VBLK) || (ref->vp->v_type == VCHR))
430 {
431 fileblk = f_offset;
7ddcb079 432 filechunk = f_offset ? 0 : ref->filelength;
6d2010ae
A
433 }
434
435 physoffset = 0;
436 while (physoffset < filechunk)
437 {
438 dk_physical_extent_t getphysreq;
439 bzero(&getphysreq, sizeof(getphysreq));
440
441 getphysreq.offset = fileblk + physoffset;
442 getphysreq.length = (filechunk - physoffset);
443 error = do_ioctl(p1, p2, DKIOCGETPHYSICALEXTENT, (caddr_t) &getphysreq);
3e170ce0 444 if (error) goto out;
6d2010ae
A
445 if (!target)
446 {
447 target = getphysreq.dev;
448 }
449 else if (target != getphysreq.dev)
450 {
451 error = ENOTSUP;
452 goto out;
453 }
d9a64523
A
454
455 assert(getphysreq.offset >= minoffset);
456
39236c6e
A
457#if HIBFRAGMENT
458 uint64_t rev;
459 for (rev = 4096; rev <= getphysreq.length; rev += 4096)
460 {
461 callback(callback_ref, getphysreq.offset + getphysreq.length - rev, 4096);
462 }
463#else
6d2010ae 464 callback(callback_ref, getphysreq.offset, getphysreq.length);
39236c6e 465#endif
6d2010ae
A
466 physoffset += getphysreq.length;
467 }
6d2010ae 468 }
d9a64523
A
469 if (ref->wbcranged)
470 {
471 uint32_t idx;
472 for (idx = 0; idx < wbc_range.count; idx++)
473 {
474 assert(wbc_range.extents[idx].offset >= minoffset);
475 callback(callback_ref, wbc_range.extents[idx].offset, wbc_range.extents[idx].length);
476 }
477 }
6d2010ae
A
478 callback(callback_ref, 0ULL, 0ULL);
479
3e170ce0
A
480 if (ref->vp->v_type == VREG) p1 = &target;
481 else
482 {
483 p1 = &target;
484 p2 = p;
485 do_ioctl = &file_ioctl;
486 }
3a60a9f5
A
487
488 // get partition base
489
fe8ab488
A
490 if (partitionbase_result)
491 {
492 error = do_ioctl(p1, p2, DKIOCGETBASE, (caddr_t) partitionbase_result);
493 if (error)
494 goto out;
495 }
3a60a9f5
A
496
497 // get block size & constraints
498
499 error = do_ioctl(p1, p2, DKIOCGETBLOCKSIZE, (caddr_t) &blksize);
500 if (error)
501 goto out;
502
503 maxiocount = 1*1024*1024*1024;
504
505 error = do_ioctl(p1, p2, DKIOCGETMAXBLOCKCOUNTREAD, (caddr_t) &count);
506 if (error)
507 count = 0;
508 count *= blksize;
509 if (count && (count < maxiocount))
510 maxiocount = count;
511
512 error = do_ioctl(p1, p2, DKIOCGETMAXBLOCKCOUNTWRITE, (caddr_t) &count);
513 if (error)
514 count = 0;
515 count *= blksize;
516 if (count && (count < maxiocount))
517 maxiocount = count;
518
519 error = do_ioctl(p1, p2, DKIOCGETMAXBYTECOUNTREAD, (caddr_t) &count);
520 if (error)
521 count = 0;
522 if (count && (count < maxiocount))
523 maxiocount = count;
524
525 error = do_ioctl(p1, p2, DKIOCGETMAXBYTECOUNTWRITE, (caddr_t) &count);
526 if (error)
527 count = 0;
528 if (count && (count < maxiocount))
529 maxiocount = count;
530
531 error = do_ioctl(p1, p2, DKIOCGETMAXSEGMENTBYTECOUNTREAD, (caddr_t) &count);
bd504ef0
A
532 if (!error)
533 error = do_ioctl(p1, p2, DKIOCGETMAXSEGMENTCOUNTREAD, (caddr_t) &segcount);
3a60a9f5 534 if (error)
bd504ef0
A
535 count = segcount = 0;
536 count *= segcount;
3a60a9f5
A
537 if (count && (count < maxiocount))
538 maxiocount = count;
539
540 error = do_ioctl(p1, p2, DKIOCGETMAXSEGMENTBYTECOUNTWRITE, (caddr_t) &count);
bd504ef0
A
541 if (!error)
542 error = do_ioctl(p1, p2, DKIOCGETMAXSEGMENTCOUNTWRITE, (caddr_t) &segcount);
3a60a9f5 543 if (error)
bd504ef0
A
544 count = segcount = 0;
545 count *= segcount;
3a60a9f5
A
546 if (count && (count < maxiocount))
547 maxiocount = count;
548
549 kprintf("max io 0x%qx bytes\n", maxiocount);
550 if (maxiocount_result)
551 *maxiocount_result = maxiocount;
552
6d2010ae
A
553 error = do_ioctl(p1, p2, DKIOCISSOLIDSTATE, (caddr_t)&isssd);
554 if (!error && isssd)
3e170ce0 555 flags |= kIOPolledFileSSD;
3a60a9f5 556
6d2010ae
A
557 if (partition_device_result)
558 *partition_device_result = device;
559 if (image_device_result)
560 *image_device_result = target;
fe8ab488 561 if (oflags)
6d2010ae 562 *oflags = flags;
3a60a9f5 563
3e170ce0
A
564 if ((ref->vp->v_type == VBLK) || (ref->vp->v_type == VCHR))
565 {
566 vnode_close(ref->vp, FWRITE, ref->ctx);
567 ref->vp = NULLVP;
3e170ce0
A
568 ref->ctx = NULL;
569 }
570
3a60a9f5 571out:
813fb2f6 572 printf("kern_open_file_for_direct_io(%p, %d)\n", ref, error);
3a60a9f5 573
00867663 574
6d2010ae
A
575 if (error && locked)
576 {
577 p1 = &device;
578 (void) do_ioctl(p1, p2, DKIOCUNLOCKPHYSICALEXTENTS, NULL);
579 }
580
581 if (error && ref)
582 {
d9a64523
A
583 if (ref->vp)
584 {
585 (void) kern_ioctl_file_extents(ref, _DKIOCCSUNPINEXTENT, 0, (ref->pinned && ref->cf) ? ref->filelength : 0);
586
587 if (ref->frozen)
588 {
589 (void) VNOP_IOCTL(ref->vp, FSCTL_THAW_EXTENTS, NULL, 0, ref->ctx);
590 }
591 if (ref->wbcranged)
592 {
593 (void) do_ioctl(p1, p2, DKIOCAPFSRELEASEWBCRANGE, (caddr_t) NULL);
594 }
595 vnode_close(ref->vp, FWRITE, ref->ctx);
596 ref->vp = NULLVP;
597 }
598 ref->ctx = NULL;
599 kfree(ref, sizeof(struct kern_direct_file_io_ref_t));
600 ref = NULL;
3a60a9f5 601 }
db609669 602
3a60a9f5
A
603 return(ref);
604}
605
606int
3e170ce0 607kern_write_file(struct kern_direct_file_io_ref_t * ref, off_t offset, void * addr, size_t len, int ioflag)
3a60a9f5
A
608{
609 return (vn_rdwr(UIO_WRITE, ref->vp,
610 addr, len, offset,
fe8ab488 611 UIO_SYSSPACE, ioflag|IO_SYNC|IO_NODELOCKED|IO_UNIT,
2d21ac55
A
612 vfs_context_ucred(ref->ctx), (int *) 0,
613 vfs_context_proc(ref->ctx)));
3a60a9f5
A
614}
615
3e170ce0
A
616int
617kern_read_file(struct kern_direct_file_io_ref_t * ref, off_t offset, void * addr, size_t len, int ioflag)
618{
619 return (vn_rdwr(UIO_READ, ref->vp,
620 addr, len, offset,
621 UIO_SYSSPACE, ioflag|IO_SYNC|IO_NODELOCKED|IO_UNIT,
622 vfs_context_ucred(ref->ctx), (int *) 0,
623 vfs_context_proc(ref->ctx)));
624}
625
626
627struct mount *
628kern_file_mount(struct kern_direct_file_io_ref_t * ref)
629{
630 return (ref->vp->v_mount);
631}
7ddcb079 632
3a60a9f5 633void
6d2010ae 634kern_close_file_for_direct_io(struct kern_direct_file_io_ref_t * ref,
3e170ce0 635 off_t write_offset, void * addr, size_t write_length,
7ddcb079 636 off_t discard_offset, off_t discard_end)
3a60a9f5 637{
6d2010ae 638 int error;
813fb2f6 639 printf("kern_close_file_for_direct_io(%p)\n", ref);
3a60a9f5 640
6d2010ae 641 if (!ref) return;
3a60a9f5 642
6d2010ae
A
643 if (ref->vp)
644 {
645 int (*do_ioctl)(void * p1, void * p2, u_long theIoctl, caddr_t result);
646 void * p1;
647 void * p2;
648
d9a64523
A
649 discard_offset = ((discard_offset + ref->blksize - 1) & ~(((off_t) ref->blksize) - 1));
650 discard_end = ((discard_end) & ~(((off_t) ref->blksize) - 1));
651
6d2010ae
A
652 if (ref->vp->v_type == VREG)
653 {
654 p1 = &ref->device;
655 p2 = kernproc;
656 do_ioctl = &file_ioctl;
657 }
658 else
659 {
660 /* Partition. */
661 p1 = ref->vp;
662 p2 = ref->ctx;
663 do_ioctl = &device_ioctl;
664 }
665 (void) do_ioctl(p1, p2, DKIOCUNLOCKPHYSICALEXTENTS, NULL);
fe8ab488 666
3e170ce0
A
667 //XXX If unmapping extents then don't also need to unpin; except ...
668 //XXX if file unaligned (HFS 4k / Fusion 128k) then pin is superset and
669 //XXX unmap is subset, so save extra walk over file extents (and the risk
670 //XXX that CF drain starts) vs leaving partial units pinned to SSD
671 //XXX (until whatever was sharing also unmaps). Err on cleaning up fully.
672 boolean_t will_unmap = (!ref->pinned || ref->cf) && (discard_end > discard_offset);
673 boolean_t will_unpin = (ref->pinned && ref->cf /* && !will_unmap */);
fe8ab488 674
3e170ce0
A
675 (void) kern_ioctl_file_extents(ref, _DKIOCCSUNPINEXTENT, 0, (will_unpin) ? ref->filelength : 0);
676
677 if (will_unmap)
6d2010ae 678 {
3e170ce0 679 (void) kern_ioctl_file_extents(ref, DKIOCUNMAP, discard_offset, (ref->cf) ? ref->filelength : discard_end);
6d2010ae 680 }
3e170ce0 681
d9a64523
A
682 if (ref->frozen)
683 {
684 (void) VNOP_IOCTL(ref->vp, FSCTL_THAW_EXTENTS, NULL, 0, ref->ctx);
685 }
686 if (ref->wbcranged)
687 {
688 (void) do_ioctl(p1, p2, DKIOCAPFSRELEASEWBCRANGE, (caddr_t) NULL);
689 }
690
39236c6e
A
691 if (addr && write_length)
692 {
00867663 693 (void) kern_write_file(ref, write_offset, addr, write_length, IO_SKIP_ENCRYPTION);
39236c6e 694 }
6d2010ae
A
695
696 error = vnode_close(ref->vp, FWRITE, ref->ctx);
697
698 ref->vp = NULLVP;
699 kprintf("vnode_close(%d)\n", error);
00867663 700
3a60a9f5 701 }
00867663
A
702
703 ref->ctx = NULL;
704
6d2010ae 705 kfree(ref, sizeof(struct kern_direct_file_io_ref_t));
3a60a9f5 706}