Linux 内核2.6.35 skb_copy_bits 函数和map.c文件

downtown 2011-05-04

int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
{
    int start = skb_headlen(skb);
    struct sk_buff *frag_iter;
    int i, copy;

    if (offset > (int)skb->len - len)
        goto fault;

    /* Copy header. */
    if ((copy = start - offset) > 0) {
        if (copy > len)
            copy = len;
        skb_copy_from_linear_data_offset(skb, offset, to, copy);
        if ((len -= copy) == 0)
            return 0;
        offset += copy;
        to     += copy;
    }

    for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
        int end;

        WARN_ON(start > offset + len);

        end = start + skb_shinfo(skb)->frags[i].size;
        if ((copy = end - offset) > 0) {
            u8 *vaddr;

            if (copy > len)
                copy = len;

            vaddr = kmap_skb_frag(&skb_shinfo(skb)->frags[i]);
            memcpy(to,
                   vaddr + skb_shinfo(skb)->frags[i].page_offset+
                   offset - start, copy);
            kunmap_skb_frag(vaddr);

            if ((len -= copy) == 0)
                return 0;
            offset += copy;
            to     += copy;
        }
        start = end;
    }

    skb_walk_frags(skb, frag_iter) {
        int end;

        WARN_ON(start > offset + len);

        end = start + frag_iter->len;
        if ((copy = end - offset) > 0) {
            if (copy > len)
                copy = len;
            if (skb_copy_bits(frag_iter, offset - start, to, copy))
                goto fault;
            if ((len -= copy) == 0)
                return 0;
            offset += copy;
            to     += copy;
        }
        start = end;
    }
    if (!len)
        return 0;

fault:
    return -EFAULT;
}
EXPORT_SYMBOL(skb_copy_bits);

/*
 *  linux/drivers/base/map.c
 *
 * (C) Copyright Al Viro 2002,2003
 * Released under GPL v2.
 *
 * NOTE: data structure needs to be changed.  It works, but for large dev_t
 * it will be too slow.  It is isolated, though, so these changes will be
 * local to that file.
 */

#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/kdev_t.h>
#include <linux/kobject.h>
#include <linux/kobj_map.h>

struct kobj_map {
 struct probe {
  struct probe *next;
  dev_t dev;
  unsigned long range;
  struct module *owner;
  kobj_probe_t *get;
  int (*lock)(dev_t, void *);
  void *data;
 } *probes[255];
 struct mutex *lock;
};

int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
      struct module *module, kobj_probe_t *probe,
      int (*lock)(dev_t, void *), void *data)
{
 unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1;
 unsigned index = MAJOR(dev);
 unsigned i;
 struct probe *p;

 if (n > 255)
  n = 255;

 p = kmalloc(sizeof(struct probe) * n, GFP_KERNEL);

 if (p == NULL)
  return -ENOMEM;

 for (i = 0; i < n; i++, p++) {
  p->owner = module;
  p->get = probe;
  p->lock = lock;
  p->dev = dev;
  p->range = range;
  p->data = data;
 }
 mutex_lock(domain->lock);
 for (i = 0, p -= n; i < n; i++, p++, index++) {
  struct probe **s = &domain->probes[index % 255];
  while (*s && (*s)->range < range)
   s = &(*s)->next;
  p->next = *s;
  *s = p;
 }
 mutex_unlock(domain->lock);
 return 0;
}

void kobj_unmap(struct kobj_map *domain, dev_t dev, unsigned long range)
{
 unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1;
 unsigned index = MAJOR(dev);
 unsigned i;
 struct probe *found = NULL;

 if (n > 255)
  n = 255;

 mutex_lock(domain->lock);
 for (i = 0; i < n; i++, index++) {
  struct probe **s;
  for (s = &domain->probes[index % 255]; *s; s = &(*s)->next) {
   struct probe *p = *s;
   if (p->dev == dev && p->range == range) {
    *s = p->next;
    if (!found)
     found = p;
    break;
   }
  }
 }
 mutex_unlock(domain->lock);
 kfree(found);
}

struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev, int *index)
{
 struct kobject *kobj;
 struct probe *p;
 unsigned long best = ~0UL;

retry:
 mutex_lock(domain->lock);
 for (p = domain->probes[MAJOR(dev) % 255]; p; p = p->next) {
  struct kobject *(*probe)(dev_t, int *, void *);
  struct module *owner;
  void *data;

  if (p->dev > dev || p->dev + p->range - 1 < dev)
   continue;
  if (p->range - 1 >= best)
   break;
  if (!try_module_get(p->owner))
   continue;
  owner = p->owner;
  data = p->data;
  probe = p->get;
  best = p->range - 1;
  *index = dev - p->dev;
  if (p->lock && p->lock(dev, data) < 0) {
   module_put(owner);
   continue;
  }
  mutex_unlock(domain->lock);
  kobj = probe(dev, index, data);
  /* Currently ->owner protects _only_ ->probe() itself. */
  module_put(owner);
  if (kobj)
   return kobj;
  goto retry;
 }
 mutex_unlock(domain->lock);
 return NULL;
}

struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct mutex *lock)
{
 struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL);
 struct probe *base = kzalloc(sizeof(*base), GFP_KERNEL);
 int i;

 if ((p == NULL) || (base == NULL)) {
  kfree(p);
  kfree(base);
  return NULL;
 }

 base->dev = 1;
 base->range = ~0;
 base->get = base_probe;
 for (i = 0; i < 255; i++)
  p->probes[i] = base;
 p->lock = lock;
 return p;
}

相关推荐

phpchandler / 0评论 2010-11-18