X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/7ddcb079202367355dddccdfa4318e57d50318be..bb59bff194111743b33cc36712410b5656329d3c:/bsd/kern/kern_symfile.c diff --git a/bsd/kern/kern_symfile.c b/bsd/kern/kern_symfile.c index b1db73f0c..0e9d6c9c6 100644 --- a/bsd/kern/kern_symfile.c +++ b/bsd/kern/kern_symfile.c @@ -78,7 +78,8 @@ struct kern_direct_file_io_ref_t struct vnode * vp; dev_t device; uint32_t blksize; - off_t filelength; + off_t filelength; + char pinned; }; @@ -95,23 +96,98 @@ static int device_ioctl(void * p1, __unused void * p2, u_long theIoctl, caddr_t return (VNOP_IOCTL(p1, theIoctl, result, 0, p2)); } -void -kern_unmap_file(struct kern_direct_file_io_ref_t * ref, off_t f_offset, off_t end); -int -kern_write_file(struct kern_direct_file_io_ref_t * ref, off_t offset, caddr_t addr, vm_size_t len); +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; + 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; + } + while (offset < end) + { + 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, NULL); + if (error) break; + fileblk = blkno * ref->blksize; + } + else if ((ref->vp->v_type == VBLK) || (ref->vp->v_type == VCHR)) + { + fileblk = offset; + filechunk = 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 error = EINVAL; + + if (error) break; + offset += filechunk; + } + return (error); +} + struct kern_direct_file_io_ref_t * kern_open_file_for_direct_io(const char * name, + boolean_t create_file, kern_get_file_extents_callback_t callback, void * callback_ref, + off_t set_file_size, + off_t write_file_offset, + caddr_t write_file_addr, + vm_size_t write_file_len, dev_t * partition_device_result, dev_t * image_device_result, uint64_t * partitionbase_result, uint64_t * maxiocount_result, - uint32_t * oflags, - off_t offset, - caddr_t addr, - vm_size_t len) + uint32_t * oflags) { struct kern_direct_file_io_ref_t * ref; @@ -127,7 +203,7 @@ kern_open_file_for_direct_io(const char * name, int isssd = 0; uint32_t flags = 0; uint32_t blksize; - off_t maxiocount, count; + off_t maxiocount, count, segcount; boolean_t locked = FALSE; int (*do_ioctl)(void * p1, void * p2, u_long theIoctl, caddr_t result); @@ -143,16 +219,24 @@ kern_open_file_for_direct_io(const char * name, goto out; } - ref->vp = NULL; + bzero(ref, sizeof(*ref)); p = kernproc; ref->ctx = vfs_context_create(vfs_context_current()); - if ((error = vnode_open(name, (O_CREAT | FWRITE), (0), 0, &ref->vp, ref->ctx))) + if ((error = vnode_open(name, (create_file) ? (O_CREAT | FWRITE) : FWRITE, + (0), 0, &ref->vp, ref->ctx))) goto out; - if (addr && len) + if (ref->vp->v_type == VREG) + { + vnode_lock_spin(ref->vp); + SET(ref->vp->v_flag, VSWAP); + vnode_unlock(ref->vp); + } + + if (write_file_addr && write_file_len) { - if ((error = kern_write_file(ref, offset, addr, len))) + if ((error = kern_write_file(ref, write_file_offset, write_file_addr, write_file_len, 0))) goto out; } @@ -160,6 +244,7 @@ kern_open_file_for_direct_io(const char * name, VATTR_WANTED(&va, va_rdev); VATTR_WANTED(&va, va_fsid); VATTR_WANTED(&va, va_data_size); + VATTR_WANTED(&va, va_data_alloc); VATTR_WANTED(&va, va_nlink); error = EFAULT; if (vnode_getattr(ref->vp, &va, ref->ctx)) @@ -167,18 +252,29 @@ kern_open_file_for_direct_io(const char * name, kprintf("vp va_rdev major %d minor %d\n", major(va.va_rdev), minor(va.va_rdev)); kprintf("vp va_fsid major %d minor %d\n", major(va.va_fsid), minor(va.va_fsid)); - kprintf("vp size %qd\n", va.va_data_size); + kprintf("vp size %qd alloc %qd\n", va.va_data_size, va.va_data_alloc); if (ref->vp->v_type == VREG) { - /* Don't dump files with links. */ - if (va.va_nlink != 1) - goto out; + /* Don't dump files with links. */ + if (va.va_nlink != 1) + goto out; device = va.va_fsid; + ref->filelength = va.va_data_size; + p1 = &device; p2 = p; do_ioctl = &file_ioctl; + + if (set_file_size) + { + error = vnode_setsize(ref->vp, set_file_size, + IO_NOZEROFILL | IO_NOAUTH, ref->ctx); + if (error) + goto out; + ref->filelength = set_file_size; + } } else if ((ref->vp->v_type == VBLK) || (ref->vp->v_type == VCHR)) { @@ -197,22 +293,13 @@ kern_open_file_for_direct_io(const char * name, } ref->device = device; - // generate the block list - - error = do_ioctl(p1, p2, DKIOCLOCKPHYSICALEXTENTS, NULL); - if (error) - goto out; - locked = TRUE; - // get block size error = do_ioctl(p1, p2, DKIOCGETBLOCKSIZE, (caddr_t) &ref->blksize); if (error) goto out; - if (ref->vp->v_type == VREG) - ref->filelength = va.va_data_size; - else + if (ref->vp->v_type != VREG) { error = do_ioctl(p1, p2, DKIOCGETBLOCKCOUNT, (caddr_t) &fileblk); if (error) @@ -220,6 +307,19 @@ kern_open_file_for_direct_io(const char * name, ref->filelength = fileblk * ref->blksize; } + // pin logical extents + + error = kern_ioctl_file_extents(ref, _DKIOCCSPINEXTENT, 0, ref->filelength); + if (error && (ENOTTY != error)) goto out; + ref->pinned = (error == 0); + + // generate the block list + + error = do_ioctl(p1, p2, DKIOCLOCKPHYSICALEXTENTS, NULL); + if (error) + goto out; + locked = TRUE; + f_offset = 0; while (f_offset < ref->filelength) { @@ -228,7 +328,8 @@ kern_open_file_for_direct_io(const char * name, filechunk = 1*1024*1024*1024; daddr64_t blkno; - error = VNOP_BLOCKMAP(ref->vp, f_offset, filechunk, &blkno, &filechunk, NULL, 0, NULL); + error = VNOP_BLOCKMAP(ref->vp, f_offset, filechunk, &blkno, + &filechunk, NULL, VNODE_WRITE, NULL); if (error) goto out; @@ -260,7 +361,15 @@ kern_open_file_for_direct_io(const char * name, error = ENOTSUP; goto out; } +#if HIBFRAGMENT + uint64_t rev; + for (rev = 4096; rev <= getphysreq.length; rev += 4096) + { + callback(callback_ref, getphysreq.offset + getphysreq.length - rev, 4096); + } +#else callback(callback_ref, getphysreq.offset, getphysreq.length); +#endif physoffset += getphysreq.length; } f_offset += filechunk; @@ -272,9 +381,12 @@ kern_open_file_for_direct_io(const char * name, // get partition base - error = do_ioctl(p1, p2, DKIOCGETBASE, (caddr_t) partitionbase_result); - if (error) - goto out; + if (partitionbase_result) + { + error = do_ioctl(p1, p2, DKIOCGETBASE, (caddr_t) partitionbase_result); + if (error) + goto out; + } // get block size & constraints @@ -311,14 +423,20 @@ kern_open_file_for_direct_io(const char * name, maxiocount = count; error = do_ioctl(p1, p2, DKIOCGETMAXSEGMENTBYTECOUNTREAD, (caddr_t) &count); + if (!error) + error = do_ioctl(p1, p2, DKIOCGETMAXSEGMENTCOUNTREAD, (caddr_t) &segcount); if (error) - count = 0; + count = segcount = 0; + count *= segcount; if (count && (count < maxiocount)) maxiocount = count; error = do_ioctl(p1, p2, DKIOCGETMAXSEGMENTBYTECOUNTWRITE, (caddr_t) &count); + if (!error) + error = do_ioctl(p1, p2, DKIOCGETMAXSEGMENTCOUNTWRITE, (caddr_t) &segcount); if (error) - count = 0; + count = segcount = 0; + count *= segcount; if (count && (count < maxiocount)) maxiocount = count; @@ -334,7 +452,7 @@ kern_open_file_for_direct_io(const char * name, *partition_device_result = device; if (image_device_result) *image_device_result = target; - if (flags) + if (oflags) *oflags = flags; out: @@ -348,6 +466,15 @@ out: if (error && ref) { + if (ref->pinned) + { + _dk_cs_pin_t pin; + bzero(&pin, sizeof(pin)); + + pin.cp_flags = _DKIOCCSPINDISCARDBLACKLIST; + p1 = &device; + (void) do_ioctl(p1, p2, _DKIOCCSUNPINEXTENT, (caddr_t)&pin); + } if (ref->vp) { vnode_close(ref->vp, FWRITE, ref->ctx); @@ -357,73 +484,20 @@ out: kfree(ref, sizeof(struct kern_direct_file_io_ref_t)); ref = NULL; } + return(ref); } int -kern_write_file(struct kern_direct_file_io_ref_t * ref, off_t offset, caddr_t addr, vm_size_t len) +kern_write_file(struct kern_direct_file_io_ref_t * ref, off_t offset, caddr_t addr, vm_size_t len, int ioflag) { return (vn_rdwr(UIO_WRITE, ref->vp, addr, len, offset, - UIO_SYSSPACE, IO_SYNC|IO_NODELOCKED|IO_UNIT, + UIO_SYSSPACE, ioflag|IO_SYNC|IO_NODELOCKED|IO_UNIT, vfs_context_ucred(ref->ctx), (int *) 0, vfs_context_proc(ref->ctx))); } -void -kern_unmap_file(struct kern_direct_file_io_ref_t * ref, off_t offset, off_t end) -{ - int error; - int (*do_ioctl)(void * p1, void * p2, u_long theIoctl, caddr_t result); - void * p1; - void * p2; - dk_extent_t extent; - dk_unmap_t unmap; - uint64_t fileblk; - size_t filechunk; - - bzero(&extent, sizeof(dk_extent_t)); - bzero(&unmap, sizeof(dk_unmap_t)); - 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; - } - while (offset < end) - { - 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, 0, NULL); - if (error) break; - fileblk = blkno * ref->blksize; - } - else if ((ref->vp->v_type == VBLK) || (ref->vp->v_type == VCHR)) - { - fileblk = offset; - filechunk = ref->filelength; - } - extent.offset = fileblk; - extent.length = filechunk; - unmap.extents = &extent; - unmap.extentsCount = 1; - error = do_ioctl(p1, p2, DKIOCUNMAP, (caddr_t)&unmap); -// kprintf("DKIOCUNMAP(%d) 0x%qx, 0x%qx\n", error, extent.offset, extent.length); - if (error) break; - offset += filechunk; - } -} void kern_close_file_for_direct_io(struct kern_direct_file_io_ref_t * ref, @@ -431,6 +505,7 @@ kern_close_file_for_direct_io(struct kern_direct_file_io_ref_t * ref, off_t discard_offset, off_t discard_end) { int error; + _dk_cs_pin_t pin; kprintf("kern_close_file_for_direct_io\n"); if (!ref) return; @@ -455,14 +530,22 @@ kern_close_file_for_direct_io(struct kern_direct_file_io_ref_t * ref, do_ioctl = &device_ioctl; } (void) do_ioctl(p1, p2, DKIOCUNLOCKPHYSICALEXTENTS, NULL); + + if (ref->pinned) + { + bzero(&pin, sizeof(pin)); + pin.cp_flags = _DKIOCCSPINDISCARDBLACKLIST; + (void) do_ioctl(p1, p2, _DKIOCCSUNPINEXTENT, (caddr_t)&pin); + } + - if (addr && write_length) + if (discard_offset && discard_end && !ref->pinned) { - (void) kern_write_file(ref, write_offset, addr, write_length); + (void) kern_ioctl_file_extents(ref, DKIOCUNMAP, discard_offset, discard_end); } - if (discard_offset && discard_end) + if (addr && write_length) { - (void) kern_unmap_file(ref, discard_offset, discard_end); + (void) kern_write_file(ref, write_offset, addr, write_length, 0); } error = vnode_close(ref->vp, FWRITE, ref->ctx); @@ -474,4 +557,3 @@ kern_close_file_for_direct_io(struct kern_direct_file_io_ref_t * ref, ref->ctx = NULL; kfree(ref, sizeof(struct kern_direct_file_io_ref_t)); } -