2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 /* Copyright (c) 1998 Apple Computer, Inc. All rights reserved.
30 * File: bsd/kern/kern_symfile.c
35 #include <mach/vm_param.h>
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>
42 #include <sys/vnode_internal.h>
43 #include <sys/proc_internal.h>
44 #include <sys/kauth.h>
45 #include <sys/timeb.h>
46 #include <sys/times.h>
48 #include <sys/file_internal.h>
50 #include <sys/kernel.h>
55 #include <mach-o/loader.h>
56 #include <mach-o/nlist.h>
58 #include <kern/kalloc.h>
59 #include <vm/vm_kern.h>
60 #include <pexpert/pexpert.h>
61 #include <IOKit/IOHibernatePrivate.h>
63 /* This function is called from kern_sysctl in the current process context;
64 * it is exported with the System6.0.exports, but this appears to be a legacy
65 * export, as there are no internal consumers.
68 get_kernel_symfile(__unused proc_t p
, __unused
char const **symfile
);
70 get_kernel_symfile(__unused proc_t p
, __unused
char const **symfile
)
75 struct kern_direct_file_io_ref_t
86 static int file_ioctl(void * p1
, void * p2
, u_long theIoctl
, caddr_t result
)
88 dev_t device
= *(dev_t
*) p1
;
90 return ((*bdevsw
[major(device
)].d_ioctl
)
91 (device
, theIoctl
, result
, S_IFBLK
, p2
));
94 static int device_ioctl(void * p1
, __unused
void * p2
, u_long theIoctl
, caddr_t result
)
96 return (VNOP_IOCTL(p1
, theIoctl
, result
, 0, p2
));
100 kern_ioctl_file_extents(struct kern_direct_file_io_ref_t
* ref
, u_long theIoctl
, off_t offset
, off_t end
)
103 int (*do_ioctl
)(void * p1
, void * p2
, u_long theIoctl
, caddr_t result
);
112 bzero(&extent
, sizeof(dk_extent_t
));
113 bzero(&unmap
, sizeof(dk_unmap_t
));
114 bzero(&pin
, sizeof(pin
));
115 if (ref
->vp
->v_type
== VREG
)
119 do_ioctl
= &file_ioctl
;
126 do_ioctl
= &device_ioctl
;
130 if (ref
->vp
->v_type
== VREG
)
133 filechunk
= 1*1024*1024*1024;
134 if (filechunk
> (size_t)(end
- offset
))
135 filechunk
= (size_t)(end
- offset
);
136 error
= VNOP_BLOCKMAP(ref
->vp
, offset
, filechunk
, &blkno
,
137 &filechunk
, NULL
, VNODE_WRITE
, NULL
);
139 fileblk
= blkno
* ref
->blksize
;
141 else if ((ref
->vp
->v_type
== VBLK
) || (ref
->vp
->v_type
== VCHR
))
144 filechunk
= ref
->filelength
;
147 if (DKIOCUNMAP
== theIoctl
)
149 extent
.offset
= fileblk
;
150 extent
.length
= filechunk
;
151 unmap
.extents
= &extent
;
152 unmap
.extentsCount
= 1;
153 error
= do_ioctl(p1
, p2
, theIoctl
, (caddr_t
)&unmap
);
154 // printf("DKIOCUNMAP(%d) 0x%qx, 0x%qx\n", error, extent.offset, extent.length);
156 else if (_DKIOCCSPINEXTENT
== theIoctl
)
158 pin
.cp_extent
.offset
= fileblk
;
159 pin
.cp_extent
.length
= filechunk
;
160 pin
.cp_flags
= _DKIOCCSPINFORHIBERNATION
;
161 error
= do_ioctl(p1
, p2
, theIoctl
, (caddr_t
)&pin
);
162 if (error
&& (ENOTTY
!= error
))
164 printf("_DKIOCCSPINEXTENT(%d) 0x%qx, 0x%qx\n",
165 error
, pin
.cp_extent
.offset
, pin
.cp_extent
.length
);
177 struct kern_direct_file_io_ref_t
*
178 kern_open_file_for_direct_io(const char * name
,
179 boolean_t create_file
,
180 kern_get_file_extents_callback_t callback
,
183 off_t write_file_offset
,
184 caddr_t write_file_addr
,
185 vm_size_t write_file_len
,
186 dev_t
* partition_device_result
,
187 dev_t
* image_device_result
,
188 uint64_t * partitionbase_result
,
189 uint64_t * maxiocount_result
,
192 struct kern_direct_file_io_ref_t
* ref
;
195 struct vnode_attr va
;
206 off_t maxiocount
, count
, segcount
;
207 boolean_t locked
= FALSE
;
209 int (*do_ioctl
)(void * p1
, void * p2
, u_long theIoctl
, caddr_t result
);
215 ref
= (struct kern_direct_file_io_ref_t
*) kalloc(sizeof(struct kern_direct_file_io_ref_t
));
222 bzero(ref
, sizeof(*ref
));
224 ref
->ctx
= vfs_context_create(vfs_context_current());
226 if ((error
= vnode_open(name
, (create_file
) ? (O_CREAT
| FWRITE
) : FWRITE
,
227 (0), 0, &ref
->vp
, ref
->ctx
)))
230 if (ref
->vp
->v_type
== VREG
)
232 vnode_lock_spin(ref
->vp
);
233 SET(ref
->vp
->v_flag
, VSWAP
);
234 vnode_unlock(ref
->vp
);
237 if (write_file_addr
&& write_file_len
)
239 if ((error
= kern_write_file(ref
, write_file_offset
, write_file_addr
, write_file_len
, 0)))
244 VATTR_WANTED(&va
, va_rdev
);
245 VATTR_WANTED(&va
, va_fsid
);
246 VATTR_WANTED(&va
, va_data_size
);
247 VATTR_WANTED(&va
, va_data_alloc
);
248 VATTR_WANTED(&va
, va_nlink
);
250 if (vnode_getattr(ref
->vp
, &va
, ref
->ctx
))
253 kprintf("vp va_rdev major %d minor %d\n", major(va
.va_rdev
), minor(va
.va_rdev
));
254 kprintf("vp va_fsid major %d minor %d\n", major(va
.va_fsid
), minor(va
.va_fsid
));
255 kprintf("vp size %qd alloc %qd\n", va
.va_data_size
, va
.va_data_alloc
);
257 if (ref
->vp
->v_type
== VREG
)
259 /* Don't dump files with links. */
260 if (va
.va_nlink
!= 1)
264 ref
->filelength
= va
.va_data_size
;
268 do_ioctl
= &file_ioctl
;
272 error
= vnode_setsize(ref
->vp
, set_file_size
,
273 IO_NOZEROFILL
| IO_NOAUTH
, ref
->ctx
);
276 ref
->filelength
= set_file_size
;
279 else if ((ref
->vp
->v_type
== VBLK
) || (ref
->vp
->v_type
== VCHR
))
286 do_ioctl
= &device_ioctl
;
290 /* Don't dump to non-regular files. */
294 ref
->device
= device
;
298 error
= do_ioctl(p1
, p2
, DKIOCGETBLOCKSIZE
, (caddr_t
) &ref
->blksize
);
302 if (ref
->vp
->v_type
!= VREG
)
304 error
= do_ioctl(p1
, p2
, DKIOCGETBLOCKCOUNT
, (caddr_t
) &fileblk
);
307 ref
->filelength
= fileblk
* ref
->blksize
;
310 // pin logical extents
312 error
= kern_ioctl_file_extents(ref
, _DKIOCCSPINEXTENT
, 0, ref
->filelength
);
313 if (error
&& (ENOTTY
!= error
)) goto out
;
314 ref
->pinned
= (error
== 0);
316 // generate the block list
318 error
= do_ioctl(p1
, p2
, DKIOCLOCKPHYSICALEXTENTS
, NULL
);
324 while (f_offset
< ref
->filelength
)
326 if (ref
->vp
->v_type
== VREG
)
328 filechunk
= 1*1024*1024*1024;
331 error
= VNOP_BLOCKMAP(ref
->vp
, f_offset
, filechunk
, &blkno
,
332 &filechunk
, NULL
, VNODE_WRITE
, NULL
);
336 fileblk
= blkno
* ref
->blksize
;
338 else if ((ref
->vp
->v_type
== VBLK
) || (ref
->vp
->v_type
== VCHR
))
341 filechunk
= f_offset
? 0 : ref
->filelength
;
345 while (physoffset
< filechunk
)
347 dk_physical_extent_t getphysreq
;
348 bzero(&getphysreq
, sizeof(getphysreq
));
350 getphysreq
.offset
= fileblk
+ physoffset
;
351 getphysreq
.length
= (filechunk
- physoffset
);
352 error
= do_ioctl(p1
, p2
, DKIOCGETPHYSICALEXTENT
, (caddr_t
) &getphysreq
);
357 target
= getphysreq
.dev
;
359 else if (target
!= getphysreq
.dev
)
366 for (rev
= 4096; rev
<= getphysreq
.length
; rev
+= 4096)
368 callback(callback_ref
, getphysreq
.offset
+ getphysreq
.length
- rev
, 4096);
371 callback(callback_ref
, getphysreq
.offset
, getphysreq
.length
);
373 physoffset
+= getphysreq
.length
;
375 f_offset
+= filechunk
;
377 callback(callback_ref
, 0ULL, 0ULL);
379 if (ref
->vp
->v_type
== VREG
)
382 // get partition base
384 if (partitionbase_result
)
386 error
= do_ioctl(p1
, p2
, DKIOCGETBASE
, (caddr_t
) partitionbase_result
);
391 // get block size & constraints
393 error
= do_ioctl(p1
, p2
, DKIOCGETBLOCKSIZE
, (caddr_t
) &blksize
);
397 maxiocount
= 1*1024*1024*1024;
399 error
= do_ioctl(p1
, p2
, DKIOCGETMAXBLOCKCOUNTREAD
, (caddr_t
) &count
);
403 if (count
&& (count
< maxiocount
))
406 error
= do_ioctl(p1
, p2
, DKIOCGETMAXBLOCKCOUNTWRITE
, (caddr_t
) &count
);
410 if (count
&& (count
< maxiocount
))
413 error
= do_ioctl(p1
, p2
, DKIOCGETMAXBYTECOUNTREAD
, (caddr_t
) &count
);
416 if (count
&& (count
< maxiocount
))
419 error
= do_ioctl(p1
, p2
, DKIOCGETMAXBYTECOUNTWRITE
, (caddr_t
) &count
);
422 if (count
&& (count
< maxiocount
))
425 error
= do_ioctl(p1
, p2
, DKIOCGETMAXSEGMENTBYTECOUNTREAD
, (caddr_t
) &count
);
427 error
= do_ioctl(p1
, p2
, DKIOCGETMAXSEGMENTCOUNTREAD
, (caddr_t
) &segcount
);
429 count
= segcount
= 0;
431 if (count
&& (count
< maxiocount
))
434 error
= do_ioctl(p1
, p2
, DKIOCGETMAXSEGMENTBYTECOUNTWRITE
, (caddr_t
) &count
);
436 error
= do_ioctl(p1
, p2
, DKIOCGETMAXSEGMENTCOUNTWRITE
, (caddr_t
) &segcount
);
438 count
= segcount
= 0;
440 if (count
&& (count
< maxiocount
))
443 kprintf("max io 0x%qx bytes\n", maxiocount
);
444 if (maxiocount_result
)
445 *maxiocount_result
= maxiocount
;
447 error
= do_ioctl(p1
, p2
, DKIOCISSOLIDSTATE
, (caddr_t
)&isssd
);
449 flags
|= kIOHibernateOptionSSD
;
451 if (partition_device_result
)
452 *partition_device_result
= device
;
453 if (image_device_result
)
454 *image_device_result
= target
;
459 kprintf("kern_open_file_for_direct_io(%d)\n", error
);
464 (void) do_ioctl(p1
, p2
, DKIOCUNLOCKPHYSICALEXTENTS
, NULL
);
472 bzero(&pin
, sizeof(pin
));
474 pin
.cp_flags
= _DKIOCCSPINDISCARDBLACKLIST
;
476 (void) do_ioctl(p1
, p2
, _DKIOCCSUNPINEXTENT
, (caddr_t
)&pin
);
480 vnode_close(ref
->vp
, FWRITE
, ref
->ctx
);
483 vfs_context_rele(ref
->ctx
);
484 kfree(ref
, sizeof(struct kern_direct_file_io_ref_t
));
492 kern_write_file(struct kern_direct_file_io_ref_t
* ref
, off_t offset
, caddr_t addr
, vm_size_t len
, int ioflag
)
494 return (vn_rdwr(UIO_WRITE
, ref
->vp
,
496 UIO_SYSSPACE
, ioflag
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
,
497 vfs_context_ucred(ref
->ctx
), (int *) 0,
498 vfs_context_proc(ref
->ctx
)));
503 kern_close_file_for_direct_io(struct kern_direct_file_io_ref_t
* ref
,
504 off_t write_offset
, caddr_t addr
, vm_size_t write_length
,
505 off_t discard_offset
, off_t discard_end
)
509 kprintf("kern_close_file_for_direct_io\n");
515 int (*do_ioctl
)(void * p1
, void * p2
, u_long theIoctl
, caddr_t result
);
519 if (ref
->vp
->v_type
== VREG
)
523 do_ioctl
= &file_ioctl
;
530 do_ioctl
= &device_ioctl
;
532 (void) do_ioctl(p1
, p2
, DKIOCUNLOCKPHYSICALEXTENTS
, NULL
);
536 bzero(&pin
, sizeof(pin
));
537 pin
.cp_flags
= _DKIOCCSPINDISCARDBLACKLIST
;
538 (void) do_ioctl(p1
, p2
, _DKIOCCSUNPINEXTENT
, (caddr_t
)&pin
);
542 if (discard_offset
&& discard_end
&& !ref
->pinned
)
544 (void) kern_ioctl_file_extents(ref
, DKIOCUNMAP
, discard_offset
, discard_end
);
546 if (addr
&& write_length
)
548 (void) kern_write_file(ref
, write_offset
, addr
, write_length
, 0);
551 error
= vnode_close(ref
->vp
, FWRITE
, ref
->ctx
);
554 kprintf("vnode_close(%d)\n", error
);
556 vfs_context_rele(ref
->ctx
);
558 kfree(ref
, sizeof(struct kern_direct_file_io_ref_t
));