LCOV - code coverage report
Current view: top level - drivers/base - map.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 60 87 69.0 %
Date: 2021-04-22 12:43:58 Functions: 3 4 75.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  *  linux/drivers/base/map.c
       4             :  *
       5             :  * (C) Copyright Al Viro 2002,2003
       6             :  *
       7             :  * NOTE: data structure needs to be changed.  It works, but for large dev_t
       8             :  * it will be too slow.  It is isolated, though, so these changes will be
       9             :  * local to that file.
      10             :  */
      11             : 
      12             : #include <linux/module.h>
      13             : #include <linux/slab.h>
      14             : #include <linux/mutex.h>
      15             : #include <linux/kdev_t.h>
      16             : #include <linux/kobject.h>
      17             : #include <linux/kobj_map.h>
      18             : 
      19             : struct kobj_map {
      20             :         struct probe {
      21             :                 struct probe *next;
      22             :                 dev_t dev;
      23             :                 unsigned long range;
      24             :                 struct module *owner;
      25             :                 kobj_probe_t *get;
      26             :                 int (*lock)(dev_t, void *);
      27             :                 void *data;
      28             :         } *probes[255];
      29             :         struct mutex *lock;
      30             : };
      31             : 
      32          76 : int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
      33             :              struct module *module, kobj_probe_t *probe,
      34             :              int (*lock)(dev_t, void *), void *data)
      35             : {
      36          76 :         unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1;
      37          76 :         unsigned index = MAJOR(dev);
      38          76 :         unsigned i;
      39          76 :         struct probe *p;
      40             : 
      41          76 :         if (n > 255)
      42             :                 n = 255;
      43             : 
      44          76 :         p = kmalloc_array(n, sizeof(struct probe), GFP_KERNEL);
      45          76 :         if (p == NULL)
      46             :                 return -ENOMEM;
      47             : 
      48         152 :         for (i = 0; i < n; i++, p++) {
      49          76 :                 p->owner = module;
      50          76 :                 p->get = probe;
      51          76 :                 p->lock = lock;
      52          76 :                 p->dev = dev;
      53          76 :                 p->range = range;
      54          76 :                 p->data = data;
      55             :         }
      56          76 :         mutex_lock(domain->lock);
      57         152 :         for (i = 0, p -= n; i < n; i++, p++, index++) {
      58          76 :                 struct probe **s = &domain->probes[index % 255];
      59          76 :                 while (*s && (*s)->range < range)
      60           0 :                         s = &(*s)->next;
      61          76 :                 p->next = *s;
      62          76 :                 *s = p;
      63             :         }
      64          76 :         mutex_unlock(domain->lock);
      65          76 :         return 0;
      66             : }
      67             : 
      68           0 : void kobj_unmap(struct kobj_map *domain, dev_t dev, unsigned long range)
      69             : {
      70           0 :         unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1;
      71           0 :         unsigned index = MAJOR(dev);
      72           0 :         unsigned i;
      73           0 :         struct probe *found = NULL;
      74             : 
      75           0 :         if (n > 255)
      76             :                 n = 255;
      77             : 
      78           0 :         mutex_lock(domain->lock);
      79           0 :         for (i = 0; i < n; i++, index++) {
      80           0 :                 struct probe **s;
      81           0 :                 for (s = &domain->probes[index % 255]; *s; s = &(*s)->next) {
      82           0 :                         struct probe *p = *s;
      83           0 :                         if (p->dev == dev && p->range == range) {
      84           0 :                                 *s = p->next;
      85           0 :                                 if (!found)
      86           0 :                                         found = p;
      87             :                                 break;
      88             :                         }
      89             :                 }
      90             :         }
      91           0 :         mutex_unlock(domain->lock);
      92           0 :         kfree(found);
      93           0 : }
      94             : 
      95          14 : struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev, int *index)
      96             : {
      97          14 :         struct kobject *kobj;
      98          14 :         struct probe *p;
      99          14 :         unsigned long best = ~0UL;
     100             : 
     101          14 : retry:
     102          14 :         mutex_lock(domain->lock);
     103         469 :         for (p = domain->probes[MAJOR(dev) % 255]; p; p = p->next) {
     104         469 :                 struct kobject *(*probe)(dev_t, int *, void *);
     105         469 :                 struct module *owner;
     106         469 :                 void *data;
     107             : 
     108         469 :                 if (p->dev > dev || p->dev + p->range - 1 < dev)
     109         455 :                         continue;
     110          14 :                 if (p->range - 1 >= best)
     111             :                         break;
     112          14 :                 if (!try_module_get(p->owner))
     113             :                         continue;
     114          14 :                 owner = p->owner;
     115          14 :                 data = p->data;
     116          14 :                 probe = p->get;
     117          14 :                 best = p->range - 1;
     118          14 :                 *index = dev - p->dev;
     119          14 :                 if (p->lock && p->lock(dev, data) < 0) {
     120           0 :                         module_put(owner);
     121           0 :                         continue;
     122             :                 }
     123          14 :                 mutex_unlock(domain->lock);
     124          14 :                 kobj = probe(dev, index, data);
     125             :                 /* Currently ->owner protects _only_ ->probe() itself. */
     126          14 :                 module_put(owner);
     127          14 :                 if (kobj)
     128          14 :                         return kobj;
     129           0 :                 goto retry;
     130             :         }
     131           0 :         mutex_unlock(domain->lock);
     132           0 :         return NULL;
     133             : }
     134             : 
     135           1 : struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct mutex *lock)
     136             : {
     137           1 :         struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL);
     138           1 :         struct probe *base = kzalloc(sizeof(*base), GFP_KERNEL);
     139           1 :         int i;
     140             : 
     141           1 :         if ((p == NULL) || (base == NULL)) {
     142           0 :                 kfree(p);
     143           0 :                 kfree(base);
     144           0 :                 return NULL;
     145             :         }
     146             : 
     147           1 :         base->dev = 1;
     148           1 :         base->range = ~0;
     149           1 :         base->get = base_probe;
     150         256 :         for (i = 0; i < 255; i++)
     151         255 :                 p->probes[i] = base;
     152           1 :         p->lock = lock;
     153           1 :         return p;
     154             : }

Generated by: LCOV version 1.14