#include <sys/disk.h>
#include <vm/vm_protos.h>
#include <vm/vm_pageout.h>
+#include <hfs/hfs.h>
void vm_swapfile_open(const char *path, vnode_t *vp);
void vm_swapfile_close(uint64_t path, vnode_t vp);
-int vm_swapfile_preallocate(vnode_t vp, uint64_t *size);
+int vm_swapfile_preallocate(vnode_t vp, uint64_t *size, boolean_t *pin);
uint64_t vm_swapfile_get_blksize(vnode_t vp);
uint64_t vm_swapfile_get_transfer_size(vnode_t vp);
int vm_swapfile_io(vnode_t vp, uint64_t offset, uint64_t start, int npages, int flags);
+int vm_record_file_write(struct vnode *vp, uint64_t offset, char *buf, int size);
+
void
vm_swapfile_open(const char *path, vnode_t *vp)
int error = 0;
vfs_context_t ctx = vfs_context_current();
- if ((error = vnode_open(path, (O_CREAT | FREAD | FWRITE), S_IRUSR | S_IWUSR, 0, vp, ctx))) {
+ if ((error = vnode_open(path, (O_CREAT | O_TRUNC | FREAD | FWRITE), S_IRUSR | S_IWUSR, 0, vp, ctx))) {
printf("Failed to open swap file %d\n", error);
*vp = NULL;
return;
return((uint64_t)vp->v_mount->mnt_vfsstat.f_iosize);
}
-int unlink1(vfs_context_t, struct nameidata *, int);
+int unlink1(vfs_context_t, vnode_t, user_addr_t, enum uio_seg, int);
void
vm_swapfile_close(uint64_t path_addr, vnode_t vp)
{
- struct nameidata nd;
vfs_context_t context = vfs_context_current();
- int error = 0;
+ int error;
vnode_getwithref(vp);
vnode_close(vp, 0, context);
- NDINIT(&nd, DELETE, OP_UNLINK, AUDITVNPATH1, UIO_SYSSPACE,
- path_addr, context);
+ error = unlink1(context, NULLVP, CAST_USER_ADDR_T(path_addr),
+ UIO_SYSSPACE, 0);
- error = unlink1(context, &nd, 0);
+#if DEVELOPMENT || DEBUG
+ if (error)
+ printf("%s : unlink of %s failed with error %d", __FUNCTION__,
+ (char *)path_addr, error);
+#endif
}
int
-vm_swapfile_preallocate(vnode_t vp, uint64_t *size)
+vm_swapfile_preallocate(vnode_t vp, uint64_t *size, boolean_t *pin)
{
int error = 0;
uint64_t file_size = 0;
}
}
#endif
+ error = vnode_setsize(vp, *size, IO_NOZEROFILL, ctx);
- /*
- * This check exists because dynamic_pager creates the 1st swapfile,
- * swapfile0, for us from user-space in a supported manner (with IO_NOZEROFILL etc).
- *
- * If dynamic_pager, in the future, discontinues creating that file,
- * then we need to change this check to a panic / assert or return an error.
- * That's because we can't be sure if the file has been created correctly.
- */
+ if (error) {
+ printf("vnode_setsize for swap files failed: %d\n", error);
+ goto done;
+ }
- if ((error = vnode_size(vp, (off_t*) &file_size, ctx)) != 0) {
+ error = vnode_size(vp, (off_t*) &file_size, ctx);
- printf("vnode_size (existing files) for swap files failed: %d\n", error);
+ if (error) {
+ printf("vnode_size (new file) for swap file failed: %d\n", error);
goto done;
- } else {
+ }
+ assert(file_size == *size);
- if (file_size == 0) {
+ if (pin != NULL && *pin != FALSE) {
- error = vnode_setsize(vp, *size, IO_NOZEROFILL, ctx);
-
- if (error) {
- printf("vnode_setsize for swap files failed: %d\n", error);
- goto done;
- }
- } else {
+ assert(vnode_tag(vp) == VT_HFS);
+
+ error = hfs_pin_vnode(VTOHFS(vp), vp, HFS_PIN_IT | HFS_DATALESS_PIN, NULL, ctx);
- *size = file_size;
+ if (error) {
+ printf("hfs_pin_vnode for swap files failed: %d\n", error);
+ /* this is not fatal, carry on with files wherever they landed */
+ *pin = FALSE;
+ error = 0;
}
}
return error;
}
+
+int
+vm_record_file_write(vnode_t vp, uint64_t offset, char *buf, int size)
+{
+ int error = 0;
+ vfs_context_t ctx;
+
+ ctx = vfs_context_kernel();
+
+ error = vn_rdwr(UIO_WRITE, vp, (caddr_t)buf, size, offset,
+ UIO_SYSSPACE, IO_NODELOCKED, vfs_context_ucred(ctx), (int *) 0, vfs_context_proc(ctx));
+
+ return (error);
+}
+
+
+
int
vm_swapfile_io(vnode_t vp, uint64_t offset, uint64_t start, int npages, int flags)
{
kern_return_t kr = KERN_SUCCESS;
upl_t upl = NULL;
unsigned int count = 0;
- int upl_create_flags = 0, upl_control_flags = 0;
+ upl_control_flags_t upl_create_flags = 0;
+ int upl_control_flags = 0;
upl_size_t upl_size = 0;
- upl_create_flags = UPL_SET_INTERNAL | UPL_SET_LITE;
- upl_control_flags = UPL_IOSYNC | UPL_PAGING_ENCRYPTED;
+ upl_create_flags = UPL_SET_INTERNAL | UPL_SET_LITE
+ | UPL_MEMORY_TAG_MAKE(VM_KERN_MEMORY_OSFMK);
+#if ENCRYPTED_SWAP
+ upl_control_flags = UPL_IOSYNC | UPL_PAGING_ENCRYPTED;
+#else
+ upl_control_flags = UPL_IOSYNC;
+#endif
if ((flags & SWAP_READ) == FALSE) {
upl_create_flags |= UPL_COPYOUT_FROM;
}
#define MAX_BATCH_TO_TRIM 256
-u_int32_t vnode_trim_list (vnode_t vp, struct trim_list *tl)
+#define ROUTE_ONLY 0x10 /* if corestorage is present, tell it to just pass */
+ /* the DKIOUNMAP command through w/o acting on it */
+ /* this is used by the compressed swap system to reclaim empty space */
+
+
+u_int32_t vnode_trim_list (vnode_t vp, struct trim_list *tl, boolean_t route_only)
{
int error = 0;
int trim_index = 0;
struct vnode *devvp;
dk_extent_t *extents;
dk_unmap_t unmap;
+ _dk_cs_unmap_t cs_unmap;
if ( !(vp->v_mount->mnt_ioflags & MNT_IOFLAGS_UNMAP_SUPPORTED))
return (ENOTSUP);
extents = kalloc(sizeof(dk_extent_t) * MAX_BATCH_TO_TRIM);
- memset (&unmap, 0, sizeof(dk_unmap_t));
- unmap.extents = extents;
+ if (vp->v_mount->mnt_ioflags & MNT_IOFLAGS_CSUNMAP_SUPPORTED) {
+ memset (&cs_unmap, 0, sizeof(_dk_cs_unmap_t));
+ cs_unmap.extents = extents;
+
+ if (route_only == TRUE)
+ cs_unmap.options = ROUTE_ONLY;
+ } else {
+ memset (&unmap, 0, sizeof(dk_unmap_t));
+ unmap.extents = extents;
+ }
while (tl) {
daddr64_t io_blockno; /* Block number corresponding to the start of the extent */
if (trim_index == MAX_BATCH_TO_TRIM) {
- unmap.extentsCount = trim_index;
- error = VNOP_IOCTL(devvp, DKIOCUNMAP, (caddr_t)&unmap, 0, vfs_context_kernel());
-
+ if (vp->v_mount->mnt_ioflags & MNT_IOFLAGS_CSUNMAP_SUPPORTED) {
+ cs_unmap.extentsCount = trim_index;
+ error = VNOP_IOCTL(devvp, _DKIOCCSUNMAP, (caddr_t)&cs_unmap, 0, vfs_context_kernel());
+ } else {
+ unmap.extentsCount = trim_index;
+ error = VNOP_IOCTL(devvp, DKIOCUNMAP, (caddr_t)&unmap, 0, vfs_context_kernel());
+ }
if (error) {
goto trim_exit;
}
tl = tl->tl_next;
}
if (trim_index) {
-
- unmap.extentsCount = trim_index;
- error = VNOP_IOCTL(devvp, DKIOCUNMAP, (caddr_t)&unmap, 0, vfs_context_kernel());
+ if (vp->v_mount->mnt_ioflags & MNT_IOFLAGS_CSUNMAP_SUPPORTED) {
+ cs_unmap.extentsCount = trim_index;
+ error = VNOP_IOCTL(devvp, _DKIOCCSUNMAP, (caddr_t)&cs_unmap, 0, vfs_context_kernel());
+ } else {
+ unmap.extentsCount = trim_index;
+ error = VNOP_IOCTL(devvp, DKIOCUNMAP, (caddr_t)&unmap, 0, vfs_context_kernel());
+ }
}
trim_exit:
kfree(extents, sizeof(dk_extent_t) * MAX_BATCH_TO_TRIM);