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

Cache object: 45174d2a0a4d3587b02f206f319bb6f2


[ 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.