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_fileassoc.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 /* $NetBSD: kern_fileassoc.c,v 1.12 2006/11/20 21:50:51 elad Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *      This product includes software developed by Elad Efrat.
   18  * 4. The name of the author may not be used to endorse or promote products
   19  *    derived from this software without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __KERNEL_RCSID(0, "$NetBSD: kern_fileassoc.c,v 1.12 2006/11/20 21:50:51 elad Exp $");
   35 
   36 #include <sys/param.h>
   37 #include <sys/mount.h>
   38 #include <sys/queue.h>
   39 #include <sys/malloc.h>
   40 #include <sys/vnode.h>
   41 #include <sys/namei.h>
   42 #include <sys/exec.h>
   43 #include <sys/proc.h>
   44 #include <sys/inttypes.h>
   45 #include <sys/errno.h>
   46 #include <sys/fileassoc.h>
   47 #include <sys/hash.h>
   48 #include <sys/fstypes.h>
   49 
   50 static struct fileassoc_hash_entry *
   51 fileassoc_file_lookup(struct vnode *, fhandle_t *);
   52 static struct fileassoc_hash_entry *
   53 fileassoc_file_add(struct vnode *, fhandle_t *);
   54 
   55 /*
   56  * Hook entry.
   57  * Includes the hook name for identification and private hook clear callback.
   58  */
   59 struct fileassoc_hook {
   60         const char *hook_name;                  /* Hook name. */
   61         fileassoc_cleanup_cb_t hook_cleanup_cb; /* Hook clear callback. */
   62 };
   63 
   64 /* An entry in the per-device hash table. */
   65 struct fileassoc_hash_entry {
   66         fhandle_t *handle;                              /* File handle */
   67         void *hooks[FILEASSOC_NHOOKS];                  /* Hooks. */
   68         LIST_ENTRY(fileassoc_hash_entry) entries;       /* List pointer. */
   69 };
   70 
   71 LIST_HEAD(fileassoc_hashhead, fileassoc_hash_entry);
   72 
   73 struct fileassoc_table {
   74         struct fileassoc_hashhead *hash_tbl;
   75         size_t hash_size;                               /* Number of slots. */
   76         struct mount *tbl_mntpt;
   77         u_long hash_mask;
   78         void *tables[FILEASSOC_NHOOKS];
   79         LIST_ENTRY(fileassoc_table) hash_list;          /* List pointer. */
   80 };
   81 
   82 struct fileassoc_hook fileassoc_hooks[FILEASSOC_NHOOKS];
   83 int fileassoc_nhooks;
   84 
   85 /* Global list of hash tables, one per device. */
   86 LIST_HEAD(, fileassoc_table) fileassoc_tables;
   87 
   88 /*
   89  * Hashing function: Takes a number modulus the mask to give back an
   90  * index into the hash table.
   91  */
   92 #define FILEASSOC_HASH(tbl, handle)     \
   93         (hash32_buf((handle), FHANDLE_SIZE(handle), HASH32_BUF_INIT) \
   94          & ((tbl)->hash_mask))
   95 
   96 /*
   97  * Initialize the fileassoc subsystem.
   98  */
   99 void
  100 fileassoc_init(void)
  101 {
  102         memset(fileassoc_hooks, 0, sizeof(fileassoc_hooks));
  103         fileassoc_nhooks = 0;
  104 }
  105 
  106 /*
  107  * Register a new hook.
  108  */
  109 fileassoc_t
  110 fileassoc_register(const char *name, fileassoc_cleanup_cb_t cleanup_cb)
  111 {
  112         int i;
  113 
  114         if (fileassoc_nhooks >= FILEASSOC_NHOOKS)
  115                 return (-1);
  116 
  117         for (i = 0; i < FILEASSOC_NHOOKS; i++)
  118                 if (fileassoc_hooks[i].hook_name == NULL)
  119                         break;
  120 
  121         fileassoc_hooks[i].hook_name = name;
  122         fileassoc_hooks[i].hook_cleanup_cb = cleanup_cb;
  123 
  124         fileassoc_nhooks++;
  125 
  126         return (i);
  127 }
  128 
  129 /*
  130  * Deregister a hook.
  131  */
  132 int
  133 fileassoc_deregister(fileassoc_t id)
  134 {
  135         if (id < 0 || id >= FILEASSOC_NHOOKS)
  136                 return (EINVAL);
  137 
  138         fileassoc_hooks[id].hook_name = NULL;
  139         fileassoc_hooks[id].hook_cleanup_cb = NULL;
  140 
  141         fileassoc_nhooks--;
  142 
  143         return (0);
  144 }
  145 
  146 /*
  147  * Get the hash table for the specified device.
  148  */
  149 static struct fileassoc_table *
  150 fileassoc_table_lookup(struct mount *mp)
  151 {
  152         struct fileassoc_table *tbl;
  153 
  154         LIST_FOREACH(tbl, &fileassoc_tables, hash_list) {
  155                 if (tbl->tbl_mntpt == mp)
  156                         return (tbl);
  157         }
  158 
  159         return (NULL);
  160 }
  161 
  162 /*
  163  * Perform a lookup on a hash table.  If hint is non-zero then use the value
  164  * of the hint as the identifier instead of performing a lookup for the
  165  * fileid.
  166  */
  167 static struct fileassoc_hash_entry *
  168 fileassoc_file_lookup(struct vnode *vp, fhandle_t *hint)
  169 {
  170         struct fileassoc_table *tbl;
  171         struct fileassoc_hashhead *tble;
  172         struct fileassoc_hash_entry *e;
  173         size_t indx;
  174         fhandle_t *th;
  175         int error;
  176 
  177         if (hint == NULL) {
  178                 error = vfs_composefh_alloc(vp, &th);
  179                 if (error)
  180                         return (NULL);
  181         } else
  182                 th = hint;
  183 
  184         tbl = fileassoc_table_lookup(vp->v_mount);
  185         if (tbl == NULL) {
  186                 if (hint == NULL)
  187                         vfs_composefh_free(th);
  188 
  189                 return (NULL);
  190         }
  191 
  192         indx = FILEASSOC_HASH(tbl, th);
  193         tble = &(tbl->hash_tbl[indx]);
  194 
  195         LIST_FOREACH(e, tble, entries) {
  196                 if ((e != NULL) &&
  197                     ((FHANDLE_FILEID(e->handle)->fid_len ==
  198                      FHANDLE_FILEID(th)->fid_len)) &&
  199                     (memcmp(FHANDLE_FILEID(e->handle), FHANDLE_FILEID(th),
  200                            (FHANDLE_FILEID(th))->fid_len) == 0)) {
  201                         if (hint == NULL)
  202                                 vfs_composefh_free(th);
  203 
  204                         return (e);
  205                 }
  206         }
  207 
  208         if (hint == NULL)
  209                 vfs_composefh_free(th);
  210 
  211         return (NULL);
  212 }
  213 
  214 /*
  215  * Return hook data associated with a vnode.
  216  */
  217 void *
  218 fileassoc_lookup(struct vnode *vp, fileassoc_t id)
  219 {
  220         struct fileassoc_hash_entry *mhe;
  221 
  222         mhe = fileassoc_file_lookup(vp, NULL);
  223         if (mhe == NULL)
  224                 return (NULL);
  225 
  226         return (mhe->hooks[id]);
  227 }
  228 
  229 /*
  230  * Create a new fileassoc table.
  231  */
  232 int
  233 fileassoc_table_add(struct mount *mp, size_t size)
  234 {
  235         struct fileassoc_table *tbl;
  236 
  237         /* Check for existing table for device. */
  238         if (fileassoc_table_lookup(mp) != NULL)
  239                 return (EEXIST);
  240 
  241         /* Allocate and initialize a Veriexec hash table. */
  242         tbl = malloc(sizeof(*tbl), M_TEMP, M_WAITOK | M_ZERO);
  243         tbl->hash_size = size;
  244         tbl->tbl_mntpt = mp;
  245         tbl->hash_tbl = hashinit(size, HASH_LIST, M_TEMP,
  246                                  M_WAITOK | M_ZERO, &tbl->hash_mask);
  247 
  248         LIST_INSERT_HEAD(&fileassoc_tables, tbl, hash_list);
  249 
  250         return (0);
  251 }
  252 
  253 /*
  254  * Delete a table.
  255  */
  256 int
  257 fileassoc_table_delete(struct mount *mp)
  258 {
  259         struct fileassoc_table *tbl;
  260         struct fileassoc_hashhead *hh;
  261         u_long i;
  262         int j;
  263 
  264         tbl = fileassoc_table_lookup(mp);
  265         if (tbl == NULL)
  266                 return (EEXIST);
  267 
  268         /* Remove all entries from the table and lists */
  269         hh = tbl->hash_tbl;
  270         for (i = 0; i < tbl->hash_size; i++) {
  271                 struct fileassoc_hash_entry *mhe;
  272 
  273                 while (LIST_FIRST(&hh[i]) != NULL) {
  274                         mhe = LIST_FIRST(&hh[i]);
  275                         LIST_REMOVE(mhe, entries);
  276 
  277                         for (j = 0; j < fileassoc_nhooks; j++)
  278                                 if (fileassoc_hooks[j].hook_cleanup_cb != NULL)
  279                                         (fileassoc_hooks[j].hook_cleanup_cb)
  280                                             (mhe->hooks[j],
  281                                             FILEASSOC_CLEANUP_FILE);
  282 
  283                         vfs_composefh_free(mhe->handle);
  284                         free(mhe, M_TEMP);
  285                 }
  286         }
  287 
  288         for (j = 0; j < fileassoc_nhooks; j++)
  289                 if (fileassoc_hooks[j].hook_cleanup_cb != NULL)
  290                         (fileassoc_hooks[j].hook_cleanup_cb)(tbl->tables[j],
  291                             FILEASSOC_CLEANUP_TABLE);
  292 
  293         /* Remove hash table and sysctl node */
  294         hashdone(tbl->hash_tbl, M_TEMP);
  295         LIST_REMOVE(tbl, hash_list);
  296 
  297         return (0);
  298 }
  299 
  300 /*
  301  * Run a callback for each hook entry in a table.
  302  */
  303 int
  304 fileassoc_table_run(struct mount *mp, fileassoc_t id, fileassoc_cb_t cb)
  305 {
  306         struct fileassoc_table *tbl;
  307         struct fileassoc_hashhead *hh;
  308         u_long i;
  309 
  310         tbl = fileassoc_table_lookup(mp);
  311         if (tbl == NULL)
  312                 return (EEXIST);
  313 
  314         hh = tbl->hash_tbl;
  315         for (i = 0; i < tbl->hash_size; i++) {
  316                 struct fileassoc_hash_entry *mhe;
  317 
  318                 LIST_FOREACH(mhe, &hh[i], entries) {
  319                         if (mhe->hooks[id] != NULL)
  320                                 cb(mhe->hooks[id]);
  321                 }
  322         }
  323 
  324         return (0);
  325 }
  326 
  327 /*
  328  * Clear a table for a given hook.
  329  */
  330 int
  331 fileassoc_table_clear(struct mount *mp, fileassoc_t id)
  332 {
  333         struct fileassoc_table *tbl;
  334         struct fileassoc_hashhead *hh;
  335         fileassoc_cleanup_cb_t cleanup_cb;
  336         u_long i;
  337 
  338         tbl = fileassoc_table_lookup(mp);
  339         if (tbl == NULL)
  340                 return (EEXIST);
  341 
  342         cleanup_cb = fileassoc_hooks[id].hook_cleanup_cb;
  343 
  344         hh = tbl->hash_tbl;
  345         for (i = 0; i < tbl->hash_size; i++) {
  346                 struct fileassoc_hash_entry *mhe;
  347 
  348                 LIST_FOREACH(mhe, &hh[i], entries) {
  349                         if ((mhe->hooks[id] != NULL) && cleanup_cb != NULL)
  350                                 cleanup_cb(mhe->hooks[id],
  351                                     FILEASSOC_CLEANUP_FILE);
  352 
  353                         mhe->hooks[id] = NULL;
  354                 }
  355         }
  356 
  357         if ((tbl->tables[id] != NULL) && cleanup_cb != NULL)
  358                 cleanup_cb(tbl->tables[id], FILEASSOC_CLEANUP_TABLE);
  359 
  360         tbl->tables[id] = NULL;
  361 
  362         return (0);
  363 }
  364 
  365 /*
  366  * Add hook-specific data on a fileassoc table.
  367  */
  368 int
  369 fileassoc_tabledata_add(struct mount *mp, fileassoc_t id, void *data)
  370 {
  371         struct fileassoc_table *tbl;
  372 
  373         tbl = fileassoc_table_lookup(mp);
  374         if (tbl == NULL)
  375                 return (EFAULT);
  376 
  377         tbl->tables[id] = data;
  378 
  379         return (0);
  380 }
  381 
  382 /*
  383  * Clear hook-specific data on a fileassoc table.
  384  */
  385 int
  386 fileassoc_tabledata_clear(struct mount *mp, fileassoc_t id)
  387 {
  388         struct fileassoc_table *tbl;
  389 
  390         tbl = fileassoc_table_lookup(mp);
  391         if (tbl == NULL)
  392                 return (EFAULT);
  393 
  394         tbl->tables[id] = NULL;
  395 
  396         return (0);
  397 }
  398 
  399 /*
  400  * Retrieve hook-specific data from a fileassoc table.
  401  */
  402 void *
  403 fileassoc_tabledata_lookup(struct mount *mp, fileassoc_t id)
  404 {
  405         struct fileassoc_table *tbl;
  406 
  407         tbl = fileassoc_table_lookup(mp);
  408         if (tbl == NULL)
  409                 return (NULL);
  410 
  411         return (tbl->tables[id]);
  412 }
  413 
  414 /*
  415  * Add a file entry to a table.
  416  */
  417 static struct fileassoc_hash_entry *
  418 fileassoc_file_add(struct vnode *vp, fhandle_t *hint)
  419 {
  420         struct fileassoc_table *tbl;
  421         struct fileassoc_hashhead *vhh;
  422         struct fileassoc_hash_entry *e;
  423         size_t indx;
  424         fhandle_t *th;
  425         int error;
  426 
  427         if (hint == NULL) {
  428                 error = vfs_composefh_alloc(vp, &th);
  429                 if (error)
  430                         return (NULL);
  431         } else
  432                 th = hint;
  433 
  434         e = fileassoc_file_lookup(vp, th);
  435         if (e != NULL) {
  436                 if (hint == NULL)
  437                         vfs_composefh_free(th);
  438 
  439                 return (e);
  440         }
  441 
  442         tbl = fileassoc_table_lookup(vp->v_mount);
  443         if (tbl == NULL) {
  444                 if (hint == NULL)
  445                         vfs_composefh_free(th);
  446 
  447                 return (NULL);
  448         }
  449 
  450         indx = FILEASSOC_HASH(tbl, th);
  451         vhh = &(tbl->hash_tbl[indx]);
  452 
  453         e = malloc(sizeof(*e), M_TEMP, M_WAITOK | M_ZERO);
  454         e->handle = th;
  455         LIST_INSERT_HEAD(vhh, e, entries);
  456 
  457         return (e);
  458 }
  459 
  460 /*
  461  * Delete a file entry from a table.
  462  */
  463 int
  464 fileassoc_file_delete(struct vnode *vp)
  465 {
  466         struct fileassoc_hash_entry *mhe;
  467         int i;
  468 
  469         mhe = fileassoc_file_lookup(vp, NULL);
  470         if (mhe == NULL)
  471                 return (ENOENT);
  472 
  473         LIST_REMOVE(mhe, entries);
  474 
  475         for (i = 0; i < fileassoc_nhooks; i++)
  476                 if (fileassoc_hooks[i].hook_cleanup_cb != NULL)
  477                         (fileassoc_hooks[i].hook_cleanup_cb)(mhe->hooks[i],
  478                             FILEASSOC_CLEANUP_FILE);
  479 
  480         free(mhe, M_TEMP);
  481 
  482         return (0);
  483 }
  484 
  485 /*
  486  * Add a hook to a vnode.
  487  */
  488 int
  489 fileassoc_add(struct vnode *vp, fileassoc_t id, void *data)
  490 {
  491         struct fileassoc_hash_entry *e;
  492 
  493         e = fileassoc_file_lookup(vp, NULL);
  494         if (e == NULL) {
  495                 e = fileassoc_file_add(vp, NULL);
  496                 if (e == NULL)
  497                         return (ENOTDIR);
  498         }
  499 
  500         if (e->hooks[id] != NULL)
  501                 return (EEXIST);
  502 
  503         e->hooks[id] = data;
  504 
  505         return (0);
  506 }
  507 
  508 /*
  509  * Clear a hook from a vnode.
  510  */
  511 int
  512 fileassoc_clear(struct vnode *vp, fileassoc_t id)
  513 {
  514         struct fileassoc_hash_entry *mhe;
  515         fileassoc_cleanup_cb_t cleanup_cb;
  516 
  517         mhe = fileassoc_file_lookup(vp, NULL);
  518         if (mhe == NULL)
  519                 return (ENOENT);
  520 
  521         cleanup_cb = fileassoc_hooks[id].hook_cleanup_cb;
  522         if ((mhe->hooks[id] != NULL) && cleanup_cb != NULL)
  523                 cleanup_cb(mhe->hooks[id], FILEASSOC_CLEANUP_FILE);
  524 
  525         mhe->hooks[id] = NULL;
  526 
  527         return (0);
  528 }

Cache object: 438742f89fde923c1b28aa2605632333


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