]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/vm/vm_compressor_backing_file.c
xnu-3248.60.10.tar.gz
[apple/xnu.git] / bsd / vm / vm_compressor_backing_file.c
index fe74a47eae502ab70a763367bb49daad0006e09e..7ec5873dbc65a598ff8c745f2ce5da291f52b5fe 100644 (file)
 #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)
@@ -53,7 +56,7 @@ 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;
@@ -74,26 +77,29 @@ vm_swapfile_get_transfer_size(vnode_t vp)
        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;
@@ -123,33 +129,32 @@ vm_swapfile_preallocate(vnode_t vp, uint64_t *size)
                }
        }
 #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;
                }
        }
 
@@ -160,6 +165,23 @@ done:
        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)
 {
@@ -169,12 +191,18 @@ vm_swapfile_io(vnode_t vp, uint64_t offset, uint64_t start, int npages, int flag
        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;
        }
@@ -243,7 +271,12 @@ vm_swapfile_io(vnode_t vp, uint64_t offset, uint64_t start, int npages, int flag
 
 #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;
@@ -251,6 +284,7 @@ u_int32_t vnode_trim_list (vnode_t vp, struct trim_list *tl)
        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);
@@ -266,8 +300,16 @@ u_int32_t vnode_trim_list (vnode_t vp, struct trim_list *tl)
 
        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 */
@@ -306,9 +348,13 @@ u_int32_t vnode_trim_list (vnode_t vp, struct trim_list *tl)
 
                        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;
                                }
@@ -321,9 +367,13 @@ u_int32_t vnode_trim_list (vnode_t vp, struct trim_list *tl)
                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);