The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/bsd/vm/dp_backing_file.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2000-2010 Apple Inc. All rights reserved.
    3  *
    4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
    5  * 
    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.
   14  * 
   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
   20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   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.
   25  * 
   26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
   27  */
   28 /*
   29  * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
   30  * support for mandatory and extensible security protections.  This notice
   31  * is included in support of clause 2.2 (b) of the Apple Public License,
   32  * Version 2.0.
   33  */
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/lock.h>
   38 #include <sys/proc_internal.h>
   39 #include <sys/kauth.h>
   40 #include <sys/buf.h>
   41 #include <sys/uio.h>
   42 #include <sys/vnode_internal.h>
   43 #include <sys/namei.h>
   44 #include <sys/ubc_internal.h>
   45 #include <sys/malloc.h>
   46 #include <sys/user.h>
   47 #if CONFIG_PROTECT
   48 #include <sys/cprotect.h>
   49 #endif
   50 
   51 #include <default_pager/default_pager_types.h>
   52 #include <default_pager/default_pager_object.h>
   53 
   54 #include <security/audit/audit.h>
   55 #include <bsm/audit_kevents.h>
   56 
   57 #include <mach/mach_types.h>
   58 #include <mach/host_priv.h>
   59 #include <mach/mach_traps.h>
   60 #include <mach/boolean.h>
   61 
   62 #include <kern/kern_types.h>
   63 #include <kern/host.h>
   64 #include <kern/task.h>
   65 #include <kern/zalloc.h>
   66 #include <kern/kalloc.h>
   67 #include <kern/assert.h>
   68 
   69 #include <libkern/libkern.h>
   70 
   71 #include <vm/vm_pageout.h>
   72 #include <vm/vm_map.h>
   73 #include <vm/vm_kern.h>
   74 #include <vm/vnode_pager.h>
   75 #include <vm/vm_protos.h>
   76 #if CONFIG_MACF
   77 #include <security/mac_framework.h>
   78 #endif
   79 
   80 /*
   81  * temporary support for delayed instantiation
   82  * of default_pager
   83  */
   84 int default_pager_init_flag = 0;
   85 
   86 struct bs_map           bs_port_table[MAX_BACKING_STORE] = { 
   87         {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
   88         {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
   89         {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
   90         {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
   91         {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
   92         {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
   93         {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
   94         {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
   95         {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
   96         {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}};
   97 
   98 /* ###################################################### */
   99 
  100 
  101 /*
  102  *      Routine:        macx_backing_store_recovery
  103  *      Function:
  104  *              Syscall interface to set a tasks privilege
  105  *              level so that it is not subject to 
  106  *              macx_backing_store_suspend
  107  */
  108 int
  109 macx_backing_store_recovery(
  110         struct macx_backing_store_recovery_args *args)
  111 {
  112         int             pid = args->pid;
  113         int             error;
  114         struct proc     *p =  current_proc();
  115         boolean_t       funnel_state;
  116 
  117         funnel_state = thread_funnel_set(kernel_flock, TRUE);
  118         if ((error = suser(kauth_cred_get(), 0)))
  119                 goto backing_store_recovery_return;
  120 
  121         /* for now restrict backing_store_recovery */
  122         /* usage to only present task */
  123         if(pid != proc_selfpid()) {
  124                 error = EINVAL;
  125                 goto backing_store_recovery_return;
  126         }
  127 
  128         task_backing_store_privileged(p->task);
  129 
  130 backing_store_recovery_return:
  131         (void) thread_funnel_set(kernel_flock, FALSE);
  132         return(error);
  133 }
  134 
  135 /*
  136  *      Routine:        macx_backing_store_suspend
  137  *      Function:
  138  *              Syscall interface to stop new demand for 
  139  *              backing store when backing store is low
  140  */
  141 
  142 int
  143 macx_backing_store_suspend(
  144         struct macx_backing_store_suspend_args *args)
  145 {
  146         boolean_t       suspend = args->suspend;
  147         int             error;
  148         boolean_t       funnel_state;
  149 
  150         funnel_state = thread_funnel_set(kernel_flock, TRUE);
  151         if ((error = suser(kauth_cred_get(), 0)))
  152                 goto backing_store_suspend_return;
  153 
  154         vm_backing_store_disable(suspend);
  155 
  156 backing_store_suspend_return:
  157         (void) thread_funnel_set(kernel_flock, FALSE);
  158         return(error);
  159 }
  160 
  161 extern boolean_t backing_store_stop_compaction;
  162 
  163 /*
  164  *      Routine:        macx_backing_store_compaction
  165  *      Function:
  166  *              Turn compaction of swap space on or off.  This is
  167  *              used during shutdown/restart so that the kernel 
  168  *              doesn't waste time compacting swap files that are 
  169  *              about to be deleted anyway.  Compaction is always 
  170  *              on by default when the system comes up and is turned 
  171  *              off when a shutdown/restart is requested.  It is 
  172  *              re-enabled if the shutdown/restart is aborted for any reason.
  173  */
  174 
  175 int
  176 macx_backing_store_compaction(int flags)
  177 {
  178         int error;
  179 
  180         if ((error = suser(kauth_cred_get(), 0)))
  181                 return error;
  182 
  183         if (flags & SWAP_COMPACT_DISABLE) {
  184                 backing_store_stop_compaction = TRUE;
  185 
  186         } else if (flags & SWAP_COMPACT_ENABLE) {
  187                 backing_store_stop_compaction = FALSE;
  188         }
  189 
  190         return 0;
  191 }
  192 
  193 /*
  194  *      Routine:        macx_triggers
  195  *      Function:
  196  *              Syscall interface to set the call backs for low and
  197  *              high water marks.
  198  */
  199 int
  200 macx_triggers(
  201         struct macx_triggers_args *args)
  202 {
  203         int     error;
  204 
  205         error = suser(kauth_cred_get(), 0);
  206         if (error)
  207                 return error;
  208 
  209         return mach_macx_triggers(args);
  210 }
  211 
  212 
  213 extern boolean_t dp_isssd;
  214 
  215 /*
  216  *      Routine:        macx_swapon
  217  *      Function:
  218  *              Syscall interface to add a file to backing store
  219  */
  220 int
  221 macx_swapon(
  222         struct macx_swapon_args *args)
  223 {
  224         int                     size = args->size;
  225         vnode_t                 vp = (vnode_t)NULL; 
  226         struct nameidata        nd, *ndp;
  227         register int            error;
  228         kern_return_t           kr;
  229         mach_port_t             backing_store;
  230         memory_object_default_t default_pager;
  231         int                     i;
  232         boolean_t               funnel_state;
  233         off_t                   file_size;
  234         vfs_context_t           ctx = vfs_context_current();
  235         struct proc             *p =  current_proc();
  236         int                     dp_cluster_size;
  237 
  238 
  239         AUDIT_MACH_SYSCALL_ENTER(AUE_SWAPON);
  240         AUDIT_ARG(value32, args->priority);
  241 
  242         funnel_state = thread_funnel_set(kernel_flock, TRUE);
  243         ndp = &nd;
  244 
  245         if ((error = suser(kauth_cred_get(), 0)))
  246                 goto swapon_bailout;
  247 
  248         /*
  249          * Get a vnode for the paging area.
  250          */
  251         NDINIT(ndp, LOOKUP, OP_LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1,
  252                ((IS_64BIT_PROCESS(p)) ? UIO_USERSPACE64 : UIO_USERSPACE32),
  253                (user_addr_t) args->filename, ctx);
  254 
  255         if ((error = namei(ndp)))
  256                 goto swapon_bailout;
  257         nameidone(ndp);
  258         vp = ndp->ni_vp;
  259 
  260         if (vp->v_type != VREG) {
  261                 error = EINVAL;
  262                 goto swapon_bailout;
  263         }
  264 
  265         /* get file size */
  266         if ((error = vnode_size(vp, &file_size, ctx)) != 0)
  267                 goto swapon_bailout;
  268 #if CONFIG_MACF
  269         vnode_lock(vp);
  270         error = mac_system_check_swapon(vfs_context_ucred(ctx), vp);
  271         vnode_unlock(vp);
  272         if (error)
  273                 goto swapon_bailout;
  274 #endif
  275 
  276         /* resize to desired size if it's too small */
  277         if ((file_size < (off_t)size) && ((error = vnode_setsize(vp, (off_t)size, 0, ctx)) != 0))
  278                 goto swapon_bailout;
  279 
  280 #if CONFIG_PROTECT
  281         {
  282                 /* initialize content protection keys manually */
  283                 if ((error = cp_handle_vnop(vp, CP_WRITE_ACCESS, 0)) != 0) {
  284                         goto swapon_bailout;
  285                 }
  286         }
  287 #endif
  288 
  289 
  290         if (default_pager_init_flag == 0) {
  291                 start_def_pager(NULL);
  292                 default_pager_init_flag = 1;
  293         }
  294 
  295         /* add new backing store to list */
  296         i = 0;
  297         while(bs_port_table[i].vp != 0) {
  298                 if(i == MAX_BACKING_STORE)
  299                         break;
  300                 i++;
  301         }
  302         if(i == MAX_BACKING_STORE) {
  303                 error = ENOMEM;
  304                 goto swapon_bailout;
  305         }
  306 
  307         /* remember the vnode. This vnode has namei() reference */
  308         bs_port_table[i].vp = vp;
  309         
  310         /*
  311          * Look to see if we are already paging to this file.
  312          */
  313         /* make certain the copy send of kernel call will work */
  314         default_pager = MEMORY_OBJECT_DEFAULT_NULL;
  315         kr = host_default_memory_manager(host_priv_self(), &default_pager, 0);
  316         if(kr != KERN_SUCCESS) {
  317            error = EAGAIN;
  318            bs_port_table[i].vp = 0;
  319            goto swapon_bailout;
  320         }
  321 
  322 #if CONFIG_EMBEDDED
  323         dp_cluster_size = 1 * PAGE_SIZE;
  324 #else
  325         if ((dp_isssd = vnode_pager_isSSD(vp)) == TRUE) {
  326                 /*
  327                  * keep the cluster size small since the
  328                  * seek cost is effectively 0 which means
  329                  * we don't care much about fragmentation
  330                  */
  331                 dp_cluster_size = 2 * PAGE_SIZE;
  332         } else {
  333                 /*
  334                  * use the default cluster size
  335                  */
  336                 dp_cluster_size = 0;
  337         }
  338 #endif
  339         kr = default_pager_backing_store_create(default_pager, 
  340                                         -1, /* default priority */
  341                                         dp_cluster_size,
  342                                         &backing_store);
  343         memory_object_default_deallocate(default_pager);
  344 
  345         if(kr != KERN_SUCCESS) {
  346            error = ENOMEM;
  347            bs_port_table[i].vp = 0;
  348            goto swapon_bailout;
  349         }
  350 
  351         /* Mark this vnode as being used for swapfile */
  352         vnode_lock_spin(vp);
  353         SET(vp->v_flag, VSWAP);
  354         vnode_unlock(vp);
  355 
  356         /*
  357          * NOTE: we are able to supply PAGE_SIZE here instead of
  358          *      an actual record size or block number because:
  359          *      a: we do not support offsets from the beginning of the
  360          *              file (allowing for non page size/record modulo offsets.
  361          *      b: because allow paging will be done modulo page size
  362          */
  363 
  364         kr = default_pager_add_file(backing_store, (vnode_ptr_t) vp,
  365                                 PAGE_SIZE, (int)(file_size/PAGE_SIZE));
  366         if(kr != KERN_SUCCESS) {
  367            bs_port_table[i].vp = 0;
  368            if(kr == KERN_INVALID_ARGUMENT)
  369                 error = EINVAL;
  370            else 
  371                 error = ENOMEM;
  372 
  373            /* This vnode is not to be used for swapfile */
  374            vnode_lock_spin(vp);
  375            CLR(vp->v_flag, VSWAP);
  376            vnode_unlock(vp);
  377 
  378            goto swapon_bailout;
  379         }
  380         bs_port_table[i].bs = (void *)backing_store;
  381         error = 0;
  382 
  383         ubc_setthreadcred(vp, p, current_thread());
  384 
  385         /*
  386          * take a long term reference on the vnode to keep
  387          * vnreclaim() away from this vnode.
  388          */
  389         vnode_ref(vp);
  390 
  391 swapon_bailout:
  392         if (vp) {
  393                 vnode_put(vp);
  394         }
  395         (void) thread_funnel_set(kernel_flock, FALSE);
  396         AUDIT_MACH_SYSCALL_EXIT(error);
  397 
  398         if (error)
  399                 printf("macx_swapon FAILED - %d\n", error);
  400         else
  401                 printf("macx_swapon SUCCESS\n");
  402 
  403         return(error);
  404 }
  405 
  406 /*
  407  *      Routine:        macx_swapoff
  408  *      Function:
  409  *              Syscall interface to remove a file from backing store
  410  */
  411 int
  412 macx_swapoff(
  413         struct macx_swapoff_args *args)
  414 {
  415         __unused int    flags = args->flags;
  416         kern_return_t   kr;
  417         mach_port_t     backing_store;
  418 
  419         struct vnode            *vp = 0; 
  420         struct nameidata        nd, *ndp;
  421         struct proc             *p =  current_proc();
  422         int                     i;
  423         int                     error;
  424         boolean_t               funnel_state;
  425         vfs_context_t ctx = vfs_context_current();
  426         struct uthread  *ut;
  427         int                     orig_iopol_disk;
  428 
  429         AUDIT_MACH_SYSCALL_ENTER(AUE_SWAPOFF);
  430 
  431         funnel_state = thread_funnel_set(kernel_flock, TRUE);
  432         backing_store = NULL;
  433         ndp = &nd;
  434 
  435         if ((error = suser(kauth_cred_get(), 0)))
  436                 goto swapoff_bailout;
  437 
  438         /*
  439          * Get the vnode for the paging area.
  440          */
  441         NDINIT(ndp, LOOKUP, OP_LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1,
  442                ((IS_64BIT_PROCESS(p)) ? UIO_USERSPACE64 : UIO_USERSPACE32),
  443                (user_addr_t) args->filename, ctx);
  444 
  445         if ((error = namei(ndp)))
  446                 goto swapoff_bailout;
  447         nameidone(ndp);
  448         vp = ndp->ni_vp;
  449 
  450         if (vp->v_type != VREG) {
  451                 error = EINVAL;
  452                 goto swapoff_bailout;
  453         }
  454 #if CONFIG_MACF
  455         vnode_lock(vp);
  456         error = mac_system_check_swapoff(vfs_context_ucred(ctx), vp);
  457         vnode_unlock(vp);
  458         if (error)
  459                 goto swapoff_bailout;
  460 #endif
  461 
  462         for(i = 0; i < MAX_BACKING_STORE; i++) {
  463                 if(bs_port_table[i].vp == vp) {
  464                         break;
  465                 }
  466         }
  467         if (i == MAX_BACKING_STORE) {
  468                 error = EINVAL;
  469                 goto swapoff_bailout;
  470         }
  471         backing_store = (mach_port_t)bs_port_table[i].bs;
  472 
  473         ut = get_bsdthread_info(current_thread());
  474 
  475         orig_iopol_disk = proc_get_thread_selfdiskacc();
  476         proc_apply_thread_selfdiskacc(IOPOL_THROTTLE);
  477 
  478         kr = default_pager_backing_store_delete(backing_store);
  479 
  480         proc_apply_thread_selfdiskacc(orig_iopol_disk);
  481 
  482         switch (kr) {
  483                 case KERN_SUCCESS:
  484                         error = 0;
  485                         bs_port_table[i].vp = 0;
  486                         /* This vnode is no longer used for swapfile */
  487                         vnode_lock_spin(vp);
  488                         CLR(vp->v_flag, VSWAP);
  489                         vnode_unlock(vp);
  490 
  491                         /* get rid of macx_swapon() "long term" reference */
  492                         vnode_rele(vp);
  493 
  494                         break;
  495                 case KERN_FAILURE:
  496                         error = EAGAIN;
  497                         break;
  498                 default:
  499                         error = EAGAIN;
  500                         break;
  501         }
  502 
  503 swapoff_bailout:
  504         /* get rid of macx_swapoff() namei() reference */
  505         if (vp)
  506                 vnode_put(vp);
  507 
  508         (void) thread_funnel_set(kernel_flock, FALSE);
  509         AUDIT_MACH_SYSCALL_EXIT(error);
  510 
  511         if (error)
  512                 printf("macx_swapoff FAILED - %d\n", error);
  513         else
  514                 printf("macx_swapoff SUCCESS\n");
  515 
  516         return(error);
  517 }
  518 
  519 /*
  520  *      Routine:        macx_swapinfo
  521  *      Function:
  522  *              Syscall interface to get general swap statistics
  523  */
  524 int
  525 macx_swapinfo(
  526         memory_object_size_t    *total_p,
  527         memory_object_size_t    *avail_p,
  528         vm_size_t               *pagesize_p,
  529         boolean_t               *encrypted_p)
  530 {
  531         int                     error;
  532         memory_object_default_t default_pager;
  533         default_pager_info_64_t dpi64;
  534         kern_return_t           kr;
  535 
  536         error = 0;
  537 
  538         /*
  539          * Get a handle on the default pager.
  540          */
  541         default_pager = MEMORY_OBJECT_DEFAULT_NULL;
  542         kr = host_default_memory_manager(host_priv_self(), &default_pager, 0);
  543         if (kr != KERN_SUCCESS) {
  544                 error = EAGAIN; /* XXX why EAGAIN ? */
  545                 goto done;
  546         }
  547         if (default_pager == MEMORY_OBJECT_DEFAULT_NULL) {
  548                 /*
  549                  * The default pager has not initialized yet,
  550                  * so it can't be using any swap space at all.
  551                  */
  552                 *total_p = 0;
  553                 *avail_p = 0;
  554                 *pagesize_p = 0;
  555                 *encrypted_p = FALSE;
  556                 goto done;
  557         }
  558         
  559         /*
  560          * Get swap usage data from default pager.
  561          */
  562         kr = default_pager_info_64(default_pager, &dpi64);
  563         if (kr != KERN_SUCCESS) {
  564                 error = ENOTSUP;
  565                 goto done;
  566         }
  567 
  568         /*
  569          * Provide default pager info to caller.
  570          */
  571         *total_p = dpi64.dpi_total_space;
  572         *avail_p = dpi64.dpi_free_space;
  573         *pagesize_p = dpi64.dpi_page_size;
  574         if (dpi64.dpi_flags & DPI_ENCRYPTED) {
  575                 *encrypted_p = TRUE;
  576         } else {
  577                 *encrypted_p = FALSE;
  578         }
  579 
  580 done:
  581         if (default_pager != MEMORY_OBJECT_DEFAULT_NULL) {
  582                 /* release our handle on default pager */
  583                 memory_object_default_deallocate(default_pager);
  584         }
  585         return error;
  586 }

Cache object: 18b5ce5421787c1d23b8147a4db29aa0


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.