]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_symfile.c
xnu-1699.32.7.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>
1c79356b
A
54
55#include <mach-o/loader.h>
56#include <mach-o/nlist.h>
57
91447636 58#include <kern/kalloc.h>
1c79356b 59#include <vm/vm_kern.h>
91447636 60#include <pexpert/pexpert.h>
3a60a9f5 61#include <IOKit/IOHibernatePrivate.h>
1c79356b 62
2d21ac55
A
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.
1c79356b 66 */
2d21ac55 67int
7ddcb079
A
68get_kernel_symfile(__unused proc_t p, __unused char const **symfile);
69int
2d21ac55 70get_kernel_symfile(__unused proc_t p, __unused char const **symfile)
1c79356b 71{
2d21ac55 72 return KERN_FAILURE;
0b4e3aa0 73}
91447636 74
3a60a9f5
A
75struct kern_direct_file_io_ref_t
76{
6d2010ae
A
77 vfs_context_t ctx;
78 struct vnode * vp;
79 dev_t device;
7ddcb079
A
80 uint32_t blksize;
81 off_t filelength;
3a60a9f5
A
82};
83
84
6d2010ae 85static int file_ioctl(void * p1, void * p2, u_long theIoctl, caddr_t result)
3a60a9f5 86{
b0d623f7 87 dev_t device = *(dev_t*) p1;
3a60a9f5
A
88
89 return ((*bdevsw[major(device)].d_ioctl)
90 (device, theIoctl, result, S_IFBLK, p2));
91}
92
6d2010ae 93static int device_ioctl(void * p1, __unused void * p2, u_long theIoctl, caddr_t result)
3a60a9f5
A
94{
95 return (VNOP_IOCTL(p1, theIoctl, result, 0, p2));
96}
97
7ddcb079
A
98void
99kern_unmap_file(struct kern_direct_file_io_ref_t * ref, off_t f_offset, off_t end);
100int
101kern_write_file(struct kern_direct_file_io_ref_t * ref, off_t offset, caddr_t addr, vm_size_t len);
102
3a60a9f5
A
103struct kern_direct_file_io_ref_t *
104kern_open_file_for_direct_io(const char * name,
105 kern_get_file_extents_callback_t callback,
106 void * callback_ref,
6d2010ae
A
107 dev_t * partition_device_result,
108 dev_t * image_device_result,
3a60a9f5 109 uint64_t * partitionbase_result,
0b4c1975 110 uint64_t * maxiocount_result,
6d2010ae
A
111 uint32_t * oflags,
112 off_t offset,
113 caddr_t addr,
114 vm_size_t len)
3a60a9f5
A
115{
116 struct kern_direct_file_io_ref_t * ref;
117
2d21ac55 118 proc_t p;
3a60a9f5
A
119 struct vnode_attr va;
120 int error;
121 off_t f_offset;
6d2010ae
A
122 uint64_t fileblk;
123 size_t filechunk;
124 uint64_t physoffset;
3a60a9f5 125 dev_t device;
6d2010ae
A
126 dev_t target = 0;
127 int isssd = 0;
128 uint32_t flags = 0;
129 uint32_t blksize;
3a60a9f5 130 off_t maxiocount, count;
6d2010ae 131 boolean_t locked = FALSE;
3a60a9f5 132
6d2010ae
A
133 int (*do_ioctl)(void * p1, void * p2, u_long theIoctl, caddr_t result);
134 void * p1 = NULL;
135 void * p2 = NULL;
3a60a9f5
A
136
137 error = EFAULT;
138
139 ref = (struct kern_direct_file_io_ref_t *) kalloc(sizeof(struct kern_direct_file_io_ref_t));
140 if (!ref)
141 {
142 error = EFAULT;
143 goto out;
144 }
145
146 ref->vp = NULL;
6d2010ae 147 p = kernproc;
2d21ac55 148 ref->ctx = vfs_context_create(vfs_context_current());
3a60a9f5 149
2d21ac55 150 if ((error = vnode_open(name, (O_CREAT | FWRITE), (0), 0, &ref->vp, ref->ctx)))
3a60a9f5
A
151 goto out;
152
6d2010ae
A
153 if (addr && len)
154 {
155 if ((error = kern_write_file(ref, offset, addr, len)))
156 goto out;
157 }
158
3a60a9f5
A
159 VATTR_INIT(&va);
160 VATTR_WANTED(&va, va_rdev);
161 VATTR_WANTED(&va, va_fsid);
162 VATTR_WANTED(&va, va_data_size);
163 VATTR_WANTED(&va, va_nlink);
164 error = EFAULT;
2d21ac55 165 if (vnode_getattr(ref->vp, &va, ref->ctx))
3a60a9f5
A
166 goto out;
167
168 kprintf("vp va_rdev major %d minor %d\n", major(va.va_rdev), minor(va.va_rdev));
169 kprintf("vp va_fsid major %d minor %d\n", major(va.va_fsid), minor(va.va_fsid));
170 kprintf("vp size %qd\n", va.va_data_size);
171
172 if (ref->vp->v_type == VREG)
173 {
174 /* Don't dump files with links. */
175 if (va.va_nlink != 1)
176 goto out;
177
178 device = va.va_fsid;
b0d623f7 179 p1 = &device;
3a60a9f5
A
180 p2 = p;
181 do_ioctl = &file_ioctl;
182 }
183 else if ((ref->vp->v_type == VBLK) || (ref->vp->v_type == VCHR))
184 {
185 /* Partition. */
186 device = va.va_rdev;
187
188 p1 = ref->vp;
2d21ac55 189 p2 = ref->ctx;
3a60a9f5
A
190 do_ioctl = &device_ioctl;
191 }
192 else
193 {
194 /* Don't dump to non-regular files. */
195 error = EFAULT;
196 goto out;
197 }
6d2010ae
A
198 ref->device = device;
199
200 // generate the block list
201
202 error = do_ioctl(p1, p2, DKIOCLOCKPHYSICALEXTENTS, NULL);
203 if (error)
204 goto out;
205 locked = TRUE;
206
207 // get block size
208
7ddcb079 209 error = do_ioctl(p1, p2, DKIOCGETBLOCKSIZE, (caddr_t) &ref->blksize);
6d2010ae
A
210 if (error)
211 goto out;
212
213 if (ref->vp->v_type == VREG)
7ddcb079 214 ref->filelength = va.va_data_size;
6d2010ae
A
215 else
216 {
217 error = do_ioctl(p1, p2, DKIOCGETBLOCKCOUNT, (caddr_t) &fileblk);
218 if (error)
219 goto out;
7ddcb079 220 ref->filelength = fileblk * ref->blksize;
6d2010ae
A
221 }
222
223 f_offset = 0;
7ddcb079 224 while (f_offset < ref->filelength)
6d2010ae
A
225 {
226 if (ref->vp->v_type == VREG)
227 {
228 filechunk = 1*1024*1024*1024;
229 daddr64_t blkno;
230
231 error = VNOP_BLOCKMAP(ref->vp, f_offset, filechunk, &blkno, &filechunk, NULL, 0, NULL);
232 if (error)
233 goto out;
234
7ddcb079 235 fileblk = blkno * ref->blksize;
6d2010ae
A
236 }
237 else if ((ref->vp->v_type == VBLK) || (ref->vp->v_type == VCHR))
238 {
239 fileblk = f_offset;
7ddcb079 240 filechunk = f_offset ? 0 : ref->filelength;
6d2010ae
A
241 }
242
243 physoffset = 0;
244 while (physoffset < filechunk)
245 {
246 dk_physical_extent_t getphysreq;
247 bzero(&getphysreq, sizeof(getphysreq));
248
249 getphysreq.offset = fileblk + physoffset;
250 getphysreq.length = (filechunk - physoffset);
251 error = do_ioctl(p1, p2, DKIOCGETPHYSICALEXTENT, (caddr_t) &getphysreq);
252 if (error)
253 goto out;
254 if (!target)
255 {
256 target = getphysreq.dev;
257 }
258 else if (target != getphysreq.dev)
259 {
260 error = ENOTSUP;
261 goto out;
262 }
263 callback(callback_ref, getphysreq.offset, getphysreq.length);
264 physoffset += getphysreq.length;
265 }
266 f_offset += filechunk;
267 }
268 callback(callback_ref, 0ULL, 0ULL);
269
270 if (ref->vp->v_type == VREG)
271 p1 = &target;
3a60a9f5
A
272
273 // get partition base
274
275 error = do_ioctl(p1, p2, DKIOCGETBASE, (caddr_t) partitionbase_result);
276 if (error)
277 goto out;
278
279 // get block size & constraints
280
281 error = do_ioctl(p1, p2, DKIOCGETBLOCKSIZE, (caddr_t) &blksize);
282 if (error)
283 goto out;
284
285 maxiocount = 1*1024*1024*1024;
286
287 error = do_ioctl(p1, p2, DKIOCGETMAXBLOCKCOUNTREAD, (caddr_t) &count);
288 if (error)
289 count = 0;
290 count *= blksize;
291 if (count && (count < maxiocount))
292 maxiocount = count;
293
294 error = do_ioctl(p1, p2, DKIOCGETMAXBLOCKCOUNTWRITE, (caddr_t) &count);
295 if (error)
296 count = 0;
297 count *= blksize;
298 if (count && (count < maxiocount))
299 maxiocount = count;
300
301 error = do_ioctl(p1, p2, DKIOCGETMAXBYTECOUNTREAD, (caddr_t) &count);
302 if (error)
303 count = 0;
304 if (count && (count < maxiocount))
305 maxiocount = count;
306
307 error = do_ioctl(p1, p2, DKIOCGETMAXBYTECOUNTWRITE, (caddr_t) &count);
308 if (error)
309 count = 0;
310 if (count && (count < maxiocount))
311 maxiocount = count;
312
313 error = do_ioctl(p1, p2, DKIOCGETMAXSEGMENTBYTECOUNTREAD, (caddr_t) &count);
314 if (error)
315 count = 0;
316 if (count && (count < maxiocount))
317 maxiocount = count;
318
319 error = do_ioctl(p1, p2, DKIOCGETMAXSEGMENTBYTECOUNTWRITE, (caddr_t) &count);
320 if (error)
321 count = 0;
322 if (count && (count < maxiocount))
323 maxiocount = count;
324
325 kprintf("max io 0x%qx bytes\n", maxiocount);
326 if (maxiocount_result)
327 *maxiocount_result = maxiocount;
328
6d2010ae
A
329 error = do_ioctl(p1, p2, DKIOCISSOLIDSTATE, (caddr_t)&isssd);
330 if (!error && isssd)
331 flags |= kIOHibernateOptionSSD;
3a60a9f5 332
6d2010ae
A
333 if (partition_device_result)
334 *partition_device_result = device;
335 if (image_device_result)
336 *image_device_result = target;
337 if (flags)
338 *oflags = flags;
3a60a9f5
A
339
340out:
341 kprintf("kern_open_file_for_direct_io(%d)\n", error);
342
6d2010ae
A
343 if (error && locked)
344 {
345 p1 = &device;
346 (void) do_ioctl(p1, p2, DKIOCUNLOCKPHYSICALEXTENTS, NULL);
347 }
348
349 if (error && ref)
350 {
351 if (ref->vp)
352 {
2d21ac55
A
353 vnode_close(ref->vp, FWRITE, ref->ctx);
354 ref->vp = NULLVP;
355 }
2d21ac55
A
356 vfs_context_rele(ref->ctx);
357 kfree(ref, sizeof(struct kern_direct_file_io_ref_t));
358 ref = NULL;
3a60a9f5 359 }
3a60a9f5
A
360 return(ref);
361}
362
363int
364kern_write_file(struct kern_direct_file_io_ref_t * ref, off_t offset, caddr_t addr, vm_size_t len)
365{
366 return (vn_rdwr(UIO_WRITE, ref->vp,
367 addr, len, offset,
b0d623f7 368 UIO_SYSSPACE, IO_SYNC|IO_NODELOCKED|IO_UNIT,
2d21ac55
A
369 vfs_context_ucred(ref->ctx), (int *) 0,
370 vfs_context_proc(ref->ctx)));
3a60a9f5
A
371}
372
7ddcb079
A
373void
374kern_unmap_file(struct kern_direct_file_io_ref_t * ref, off_t offset, off_t end)
375{
376 int error;
377 int (*do_ioctl)(void * p1, void * p2, u_long theIoctl, caddr_t result);
378 void * p1;
379 void * p2;
380 dk_extent_t extent;
381 dk_unmap_t unmap;
382 uint64_t fileblk;
383 size_t filechunk;
384
385 bzero(&extent, sizeof(dk_extent_t));
386 bzero(&unmap, sizeof(dk_unmap_t));
387 if (ref->vp->v_type == VREG)
388 {
389 p1 = &ref->device;
390 p2 = kernproc;
391 do_ioctl = &file_ioctl;
392 }
393 else
394 {
395 /* Partition. */
396 p1 = ref->vp;
397 p2 = ref->ctx;
398 do_ioctl = &device_ioctl;
399 }
400 while (offset < end)
401 {
402 if (ref->vp->v_type == VREG)
403 {
404 daddr64_t blkno;
405 filechunk = 1*1024*1024*1024;
406 if (filechunk > (size_t)(end - offset))
407 filechunk = (size_t)(end - offset);
408 error = VNOP_BLOCKMAP(ref->vp, offset, filechunk, &blkno, &filechunk, NULL, 0, NULL);
409 if (error) break;
410 fileblk = blkno * ref->blksize;
411 }
412 else if ((ref->vp->v_type == VBLK) || (ref->vp->v_type == VCHR))
413 {
414 fileblk = offset;
415 filechunk = ref->filelength;
416 }
417 extent.offset = fileblk;
418 extent.length = filechunk;
419 unmap.extents = &extent;
420 unmap.extentsCount = 1;
421 error = do_ioctl(p1, p2, DKIOCUNMAP, (caddr_t)&unmap);
422// kprintf("DKIOCUNMAP(%d) 0x%qx, 0x%qx\n", error, extent.offset, extent.length);
423 if (error) break;
424 offset += filechunk;
425 }
426}
427
3a60a9f5 428void
6d2010ae 429kern_close_file_for_direct_io(struct kern_direct_file_io_ref_t * ref,
7ddcb079
A
430 off_t write_offset, caddr_t addr, vm_size_t write_length,
431 off_t discard_offset, off_t discard_end)
3a60a9f5 432{
6d2010ae 433 int error;
3a60a9f5
A
434 kprintf("kern_close_file_for_direct_io\n");
435
6d2010ae 436 if (!ref) return;
3a60a9f5 437
6d2010ae
A
438 if (ref->vp)
439 {
440 int (*do_ioctl)(void * p1, void * p2, u_long theIoctl, caddr_t result);
441 void * p1;
442 void * p2;
443
444 if (ref->vp->v_type == VREG)
445 {
446 p1 = &ref->device;
447 p2 = kernproc;
448 do_ioctl = &file_ioctl;
449 }
450 else
451 {
452 /* Partition. */
453 p1 = ref->vp;
454 p2 = ref->ctx;
455 do_ioctl = &device_ioctl;
456 }
457 (void) do_ioctl(p1, p2, DKIOCUNLOCKPHYSICALEXTENTS, NULL);
458
7ddcb079
A
459 if (addr && write_length)
460 {
461 (void) kern_write_file(ref, write_offset, addr, write_length);
462 }
463 if (discard_offset && discard_end)
6d2010ae 464 {
7ddcb079 465 (void) kern_unmap_file(ref, discard_offset, discard_end);
6d2010ae
A
466 }
467
468 error = vnode_close(ref->vp, FWRITE, ref->ctx);
469
470 ref->vp = NULLVP;
471 kprintf("vnode_close(%d)\n", error);
3a60a9f5 472 }
6d2010ae
A
473 vfs_context_rele(ref->ctx);
474 ref->ctx = NULL;
475 kfree(ref, sizeof(struct kern_direct_file_io_ref_t));
3a60a9f5 476}
2d21ac55 477