+ return VNOP_IOCTL(p1, theIoctl, result, 0, p2);
+}
+
+static int
+kern_ioctl_file_extents(struct kern_direct_file_io_ref_t * ref, u_long theIoctl, off_t offset, off_t end)
+{
+ int error = 0;
+ int (*do_ioctl)(void * p1, void * p2, u_long theIoctl, caddr_t result);
+ void * p1;
+ void * p2;
+ uint64_t fileblk;
+ size_t filechunk;
+ dk_extent_t extent;
+ dk_unmap_t unmap;
+ _dk_cs_pin_t pin;
+
+ bzero(&extent, sizeof(dk_extent_t));
+ bzero(&unmap, sizeof(dk_unmap_t));
+ bzero(&pin, sizeof(pin));
+ if (ref->vp->v_type == VREG) {
+ p1 = &ref->device;
+ p2 = kernproc;
+ do_ioctl = &file_ioctl;
+ } else {
+ /* Partition. */
+ p1 = ref->vp;
+ p2 = ref->ctx;
+ do_ioctl = &device_ioctl;
+ }
+
+ if (_DKIOCCSPINEXTENT == theIoctl) {
+ /* Tell CS the image size, so it knows whether to place the subsequent pins SSD/HDD */
+ pin.cp_extent.length = end;
+ pin.cp_flags = _DKIOCCSHIBERNATEIMGSIZE;
+ (void) do_ioctl(p1, p2, _DKIOCCSPINEXTENT, (caddr_t)&pin);
+ } else if (_DKIOCCSUNPINEXTENT == theIoctl) {
+ /* Tell CS hibernation is done, so it can stop blocking overlapping writes */
+ pin.cp_flags = _DKIOCCSPINDISCARDBLACKLIST;
+ (void) do_ioctl(p1, p2, _DKIOCCSUNPINEXTENT, (caddr_t)&pin);
+ }
+
+ for (; offset < end; offset += filechunk) {
+ if (ref->vp->v_type == VREG) {
+ daddr64_t blkno;
+ filechunk = 1 * 1024 * 1024 * 1024;
+ if (filechunk > (size_t)(end - offset)) {
+ filechunk = (size_t)(end - offset);
+ }
+ error = VNOP_BLOCKMAP(ref->vp, offset, filechunk, &blkno,
+ &filechunk, NULL, VNODE_WRITE | VNODE_BLOCKMAP_NO_TRACK, NULL);
+ if (error) {
+ break;
+ }
+ if (-1LL == blkno) {
+ continue;
+ }
+ fileblk = blkno * ref->blksize;
+ } else if ((ref->vp->v_type == VBLK) || (ref->vp->v_type == VCHR)) {
+ fileblk = offset;
+ filechunk = (unsigned long)((ref->filelength > ULONG_MAX) ? ULONG_MAX: ref->filelength);
+ }
+
+ if (DKIOCUNMAP == theIoctl) {
+ extent.offset = fileblk;
+ extent.length = filechunk;
+ unmap.extents = &extent;
+ unmap.extentsCount = 1;
+ error = do_ioctl(p1, p2, theIoctl, (caddr_t)&unmap);
+// printf("DKIOCUNMAP(%d) 0x%qx, 0x%qx\n", error, extent.offset, extent.length);
+ } else if (_DKIOCCSPINEXTENT == theIoctl) {
+ pin.cp_extent.offset = fileblk;
+ pin.cp_extent.length = filechunk;
+ pin.cp_flags = _DKIOCCSPINFORHIBERNATION;
+ error = do_ioctl(p1, p2, theIoctl, (caddr_t)&pin);
+ if (error && (ENOTTY != error)) {
+ printf("_DKIOCCSPINEXTENT(%d) 0x%qx, 0x%qx\n", error, pin.cp_extent.offset, pin.cp_extent.length);
+ }
+ } else if (_DKIOCCSUNPINEXTENT == theIoctl) {
+ pin.cp_extent.offset = fileblk;
+ pin.cp_extent.length = filechunk;
+ pin.cp_flags = _DKIOCCSPINFORHIBERNATION;
+ error = do_ioctl(p1, p2, theIoctl, (caddr_t)&pin);
+ if (error && (ENOTTY != error)) {
+ printf("_DKIOCCSUNPINEXTENT(%d) 0x%qx, 0x%qx\n", error, pin.cp_extent.offset, pin.cp_extent.length);
+ }
+ } else {
+ error = EINVAL;
+ }
+
+ if (error) {
+ break;
+ }
+ }
+ return error;