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/kern/kern_khelp.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) 2010,2013 Lawrence Stewart <lstewart@freebsd.org>
    3  * Copyright (c) 2010 The FreeBSD Foundation
    4  * All rights reserved.
    5  *
    6  * This software was developed by Lawrence Stewart while studying at the Centre
    7  * for Advanced Internet Architectures, Swinburne University of Technology,
    8  * made possible in part by grants from the FreeBSD Foundation and Cisco
    9  * University Research Program Fund at Community Foundation Silicon Valley.
   10  *
   11  * Portions of this software were developed at the Centre for Advanced
   12  * Internet Architectures, Swinburne University of Technology, Melbourne,
   13  * Australia by Lawrence Stewart under sponsorship from the FreeBSD Foundation.
   14  *
   15  * Redistribution and use in source and binary forms, with or without
   16  * modification, are permitted provided that the following conditions
   17  * are met:
   18  * 1. Redistributions of source code must retain the above copyright
   19  *    notice, this list of conditions and the following disclaimer.
   20  * 2. Redistributions in binary form must reproduce the above copyright
   21  *    notice, this list of conditions and the following disclaimer in the
   22  *    documentation and/or other materials provided with the distribution.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  */
   36 
   37 #include <sys/cdefs.h>
   38 __FBSDID("$FreeBSD: releng/11.0/sys/kern/kern_khelp.c 251778 2013-06-15 06:45:17Z lstewart $");
   39 
   40 #include <sys/param.h>
   41 #include <sys/kernel.h>
   42 #include <sys/hhook.h>
   43 #include <sys/khelp.h>
   44 #include <sys/lock.h>
   45 #include <sys/malloc.h>
   46 #include <sys/module.h>
   47 #include <sys/module_khelp.h>
   48 #include <sys/osd.h>
   49 #include <sys/queue.h>
   50 #include <sys/refcount.h>
   51 #include <sys/rwlock.h>
   52 #include <sys/systm.h>
   53 
   54 static struct rwlock khelp_list_lock;
   55 RW_SYSINIT(khelplistlock, &khelp_list_lock, "helper list lock");
   56 
   57 static TAILQ_HEAD(helper_head, helper) helpers = TAILQ_HEAD_INITIALIZER(helpers);
   58 
   59 /* Private function prototypes. */
   60 static inline void khelp_remove_osd(struct helper *h, struct osd *hosd);
   61 void khelp_new_hhook_registered(struct hhook_head *hhh, uint32_t flags);
   62 
   63 #define KHELP_LIST_WLOCK() rw_wlock(&khelp_list_lock)
   64 #define KHELP_LIST_WUNLOCK() rw_wunlock(&khelp_list_lock)
   65 #define KHELP_LIST_RLOCK() rw_rlock(&khelp_list_lock)
   66 #define KHELP_LIST_RUNLOCK() rw_runlock(&khelp_list_lock)
   67 #define KHELP_LIST_LOCK_ASSERT() rw_assert(&khelp_list_lock, RA_LOCKED)
   68 
   69 int
   70 khelp_register_helper(struct helper *h)
   71 {
   72         struct helper *tmph;
   73         int error, i, inserted;
   74 
   75         error = inserted = 0;
   76         refcount_init(&h->h_refcount, 0);
   77         h->h_id = osd_register(OSD_KHELP, NULL, NULL);
   78 
   79         /* It's only safe to add the hooks after osd_register(). */
   80         for (i = 0; i < h->h_nhooks && !error; i++) {
   81                 /* We don't require the module to assign hook_helper. */
   82                 h->h_hooks[i].hook_helper = h;
   83                 error = hhook_add_hook_lookup(&h->h_hooks[i], HHOOK_WAITOK);
   84                 if (error)
   85                         printf("%s: \"%s\" khelp module unable to "
   86                             "hook type %d id %d due to error %d\n", __func__,
   87                             h->h_name, h->h_hooks[i].hook_type,
   88                             h->h_hooks[i].hook_id, error);
   89         }
   90 
   91         if (error) {
   92                 for (i--; i >= 0; i--)
   93                         hhook_remove_hook_lookup(&h->h_hooks[i]);
   94                 osd_deregister(OSD_KHELP, h->h_id);
   95         } else {
   96                 KHELP_LIST_WLOCK();
   97                 /*
   98                  * Keep list of helpers sorted in descending h_id order. Due to
   99                  * the way osd_set() works, a sorted list ensures
  100                  * khelp_init_osd() will operate with improved efficiency.
  101                  */
  102                 TAILQ_FOREACH(tmph, &helpers, h_next) {
  103                         if (tmph->h_id < h->h_id) {
  104                                 TAILQ_INSERT_BEFORE(tmph, h, h_next);
  105                                 inserted = 1;
  106                                 break;
  107                         }
  108                 }
  109 
  110                 if (!inserted)
  111                         TAILQ_INSERT_TAIL(&helpers, h, h_next);
  112                 KHELP_LIST_WUNLOCK();
  113         }
  114 
  115         return (error);
  116 }
  117 
  118 int
  119 khelp_deregister_helper(struct helper *h)
  120 {
  121         struct helper *tmph;
  122         int error, i;
  123 
  124         KHELP_LIST_WLOCK();
  125         if (h->h_refcount > 0)
  126                 error = EBUSY;
  127         else {
  128                 error = ENOENT;
  129                 TAILQ_FOREACH(tmph, &helpers, h_next) {
  130                         if (tmph == h) {
  131                                 TAILQ_REMOVE(&helpers, h, h_next);
  132                                 error = 0;
  133                                 break;
  134                         }
  135                 }
  136         }
  137         KHELP_LIST_WUNLOCK();
  138 
  139         if (!error) {
  140                 for (i = 0; i < h->h_nhooks; i++)
  141                         hhook_remove_hook_lookup(&h->h_hooks[i]);
  142                 osd_deregister(OSD_KHELP, h->h_id);
  143         }
  144 
  145         return (error);
  146 }
  147 
  148 int
  149 khelp_init_osd(uint32_t classes, struct osd *hosd)
  150 {
  151         struct helper *h;
  152         void *hdata;
  153         int error;
  154 
  155         KASSERT(hosd != NULL, ("struct osd not initialised!"));
  156 
  157         error = 0;
  158 
  159         KHELP_LIST_RLOCK();
  160         TAILQ_FOREACH(h, &helpers, h_next) {
  161                 /* If helper is correct class and needs to store OSD... */
  162                 if (h->h_classes & classes && h->h_flags & HELPER_NEEDS_OSD) {
  163                         hdata = uma_zalloc(h->h_zone, M_NOWAIT);
  164                         if (hdata == NULL) {
  165                                 error = ENOMEM;
  166                                 break;
  167                         }
  168                         osd_set(OSD_KHELP, hosd, h->h_id, hdata);
  169                         refcount_acquire(&h->h_refcount);
  170                 }
  171         }
  172 
  173         if (error) {
  174                 /* Delete OSD that was assigned prior to the error. */
  175                 TAILQ_FOREACH(h, &helpers, h_next) {
  176                         if (h->h_classes & classes)
  177                                 khelp_remove_osd(h, hosd);
  178                 }
  179         }
  180         KHELP_LIST_RUNLOCK();
  181 
  182         return (error);
  183 }
  184 
  185 int
  186 khelp_destroy_osd(struct osd *hosd)
  187 {
  188         struct helper *h;
  189         int error;
  190 
  191         KASSERT(hosd != NULL, ("struct osd not initialised!"));
  192 
  193         error = 0;
  194 
  195         KHELP_LIST_RLOCK();
  196         /*
  197          * Clean up all khelp related OSD.
  198          *
  199          * XXXLAS: Would be nice to use something like osd_exit() here but it
  200          * doesn't have the right semantics for this purpose.
  201          */
  202         TAILQ_FOREACH(h, &helpers, h_next)
  203                 khelp_remove_osd(h, hosd);
  204         KHELP_LIST_RUNLOCK();
  205 
  206         return (error);
  207 }
  208 
  209 static inline void
  210 khelp_remove_osd(struct helper *h, struct osd *hosd)
  211 {
  212         void *hdata;
  213 
  214         if (h->h_flags & HELPER_NEEDS_OSD) {
  215                 /*
  216                  * If the current helper uses OSD and calling osd_get()
  217                  * on the helper's h_id returns non-NULL, the helper has
  218                  * OSD attached to 'hosd' which needs to be cleaned up.
  219                  */
  220                 hdata = osd_get(OSD_KHELP, hosd, h->h_id);
  221                 if (hdata != NULL) {
  222                         uma_zfree(h->h_zone, hdata);
  223                         osd_del(OSD_KHELP, hosd, h->h_id);
  224                         refcount_release(&h->h_refcount);
  225                 }
  226         }
  227 }
  228 
  229 void *
  230 khelp_get_osd(struct osd *hosd, int32_t id)
  231 {
  232 
  233         return (osd_get(OSD_KHELP, hosd, id));
  234 }
  235 
  236 int32_t
  237 khelp_get_id(char *hname)
  238 {
  239         struct helper *h;
  240         int32_t id;
  241 
  242         id = -1;
  243 
  244         KHELP_LIST_RLOCK();
  245         TAILQ_FOREACH(h, &helpers, h_next) {
  246                 if (strncmp(h->h_name, hname, HELPER_NAME_MAXLEN) == 0) {
  247                         id = h->h_id;
  248                         break;
  249                 }
  250         }
  251         KHELP_LIST_RUNLOCK();
  252 
  253         return (id);
  254 }
  255 
  256 int
  257 khelp_add_hhook(struct hookinfo *hki, uint32_t flags)
  258 {
  259         int error;
  260 
  261         /*
  262          * XXXLAS: Should probably include the functionality to update the
  263          * helper's h_hooks struct member.
  264          */
  265         error = hhook_add_hook_lookup(hki, flags);
  266 
  267         return (error);
  268 }
  269 
  270 int
  271 khelp_remove_hhook(struct hookinfo *hki)
  272 {
  273         int error;
  274 
  275         /*
  276          * XXXLAS: Should probably include the functionality to update the
  277          * helper's h_hooks struct member.
  278          */
  279         error = hhook_remove_hook_lookup(hki);
  280 
  281         return (error);
  282 }
  283 
  284 /*
  285  * Private KPI between hhook and khelp that allows khelp modules to insert hook
  286  * functions into hhook points which register after the modules were loaded.
  287  */
  288 void
  289 khelp_new_hhook_registered(struct hhook_head *hhh, uint32_t flags)
  290 {
  291         struct helper *h;
  292         int error, i;
  293 
  294         KHELP_LIST_RLOCK();
  295         TAILQ_FOREACH(h, &helpers, h_next) {
  296                 for (i = 0; i < h->h_nhooks; i++) {
  297                         if (hhh->hhh_type != h->h_hooks[i].hook_type ||
  298                             hhh->hhh_id != h->h_hooks[i].hook_id)
  299                                 continue;
  300                         error = hhook_add_hook(hhh, &h->h_hooks[i], flags);
  301                         if (error) {
  302                                 printf("%s: \"%s\" khelp module unable to "
  303                                     "hook type %d id %d due to error %d\n",
  304                                     __func__, h->h_name,
  305                                     h->h_hooks[i].hook_type,
  306                                     h->h_hooks[i].hook_id, error);
  307                                 error = 0;
  308                         }
  309                 }
  310         }
  311         KHELP_LIST_RUNLOCK();
  312 }
  313 
  314 int
  315 khelp_modevent(module_t mod, int event_type, void *data)
  316 {
  317         struct khelp_modevent_data *kmd;
  318         int error;
  319 
  320         kmd = (struct khelp_modevent_data *)data;
  321         error = 0;
  322 
  323         switch(event_type) {
  324         case MOD_LOAD:
  325                 if (kmd->helper->h_flags & HELPER_NEEDS_OSD) {
  326                         if (kmd->uma_zsize <= 0) {
  327                                 printf("Use KHELP_DECLARE_MOD_UMA() instead!\n");
  328                                 error = EDOOFUS;
  329                                 break;
  330                         }
  331                         kmd->helper->h_zone = uma_zcreate(kmd->name,
  332                             kmd->uma_zsize, kmd->umactor, kmd->umadtor, NULL,
  333                             NULL, 0, 0);
  334                         if (kmd->helper->h_zone == NULL) {
  335                                 error = ENOMEM;
  336                                 break;
  337                         }
  338                 }
  339                 strlcpy(kmd->helper->h_name, kmd->name, HELPER_NAME_MAXLEN);
  340                 kmd->helper->h_hooks = kmd->hooks;
  341                 kmd->helper->h_nhooks = kmd->nhooks;
  342                 if (kmd->helper->mod_init != NULL)
  343                         error = kmd->helper->mod_init();
  344                 if (!error)
  345                         error = khelp_register_helper(kmd->helper);
  346                 break;
  347 
  348         case MOD_QUIESCE:
  349         case MOD_SHUTDOWN:
  350         case MOD_UNLOAD:
  351                 error = khelp_deregister_helper(kmd->helper);
  352                 if (!error) {
  353                         if (kmd->helper->h_flags & HELPER_NEEDS_OSD)
  354                                 uma_zdestroy(kmd->helper->h_zone);
  355                         if (kmd->helper->mod_destroy != NULL)
  356                                 kmd->helper->mod_destroy();
  357                 } else if (error == ENOENT)
  358                         /* Do nothing and allow unload if helper not in list. */
  359                         error = 0;
  360                 else if (error == EBUSY)
  361                         printf("Khelp module \"%s\" can't unload until its "
  362                             "refcount drops from %d to 0.\n", kmd->name,
  363                             kmd->helper->h_refcount);
  364                 break;
  365 
  366         default:
  367                 error = EINVAL;
  368                 break;
  369         }
  370 
  371         return (error);
  372 }

Cache object: 9436a7680283c2611cefcecb85484238


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