Chinaunix首页 | 论坛 | 博客
  • 博客访问: 129797
  • 博文数量: 17
  • 博客积分: 2000
  • 博客等级: 大尉
  • 技术积分: 490
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-13 14:07
文章分类

全部博文(17)

文章存档

2011年(1)

2009年(5)

2008年(11)

我的朋友

分类: LINUX

2009-01-04 18:28:54

1. idr机制

Linux的dm中对minor number采用idr机制进行管理。idr即"ID Radix",内核中通过radix树对ID进行组织和管理,是一种将整数ID和指针关联在一起的一种机制。radix树基于以二进制表示的键值的查找树,尤其适合于处理非常长的、可变长度的键值。查找时每个节点都存储有进行下一次的bit测试之前需要跳过的bit数目,查找效率比较高。

以下代码中的注释说明了idr的基本作用(lib/idr.c)
/*
 * 2002-10-18  written by Jim Houston jim.houston@ccur.com
 *  Copyright (C) 2002 by Concurrent Computer Corporation
 *  Distributed under the GNU GPL license version 2.
 *
 * Modified by George Anzinger to reuse immediately and to use
 * find bit instructions.  Also removed _irq on spinlocks.
 *
 * Small id to pointer translation service. 
 *
 * It uses a radix tree like structure as a sparse array indexed
 * by the id to obtain the pointer.  The bitmap makes allocating
 * a new id quick. 
 *
 * You call it to allocate an id (an int) an associate with that id a
 * pointer or what ever, we treat it as a (void *).  You can pass this
 * id to a user for him to pass back at a later time.  You then pass
 * that id to this code and it returns your pointer.
   
 * You can release ids at any time. When all ids are released, most of
 * the memory is returned (we keep IDR_FREE_MAX) in a local pool so we
 * don't need to go to the memory "store" during an id allocate, just
 * so you don't need to be too concerned about locking and conflicts
 * with the slab allocator.
 */

API函数主要是以下几个:

void *idr_find(struct idr *idp, int id);
int idr_pre_get(struct idr *idp, unsigned gfp_mask);
int idr_get_new(struct idr *idp, void *ptr, int *id);
int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id);
void idr_remove(struct idr *idp, int id);
void idr_init(struct idr *idp);


/**
 * idr_get_new - allocate new idr entry
 * @idp: idr handle
 * @ptr: pointer you want associated with the ide
 * @id: pointer to the allocated handle
 *
 * This is the allocate id function.  It should be called with any
 * required locks.
 * 
 * If memory is required, it will return -EAGAIN, you should unlock
 * and go back to the idr_pre_get() call.  If the idr is full, it will
 * return -ENOSPC.
 *
 * @id returns a value in the range 0 ... 0x7fffffff
 */
int idr_get_new(struct idr *idp, void *ptr, int *id)
{  
    int rv;
    rv = idr_get_new_above_int(idp, ptr, 0);
    /*
     * This is a cheap hack until the IDR code can be fixed to
     * return proper error values.
     */
    if (rv < 0) {
        if (rv == -1)
            return -EAGAIN;
        else /* Will be -3 */
            return -ENOSPC;
    }
    *id = rv;
    return 0;
}      


2. dm中minor的管理

/* 
 * Allocate and initialise a blank device with a given minor.
 */
static struct mapped_device *alloc_dev(unsigned int minor, int persistent)
{
    int r;
    struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL);

    if (!md) {
        DMWARN("unable to allocate device, out of memory.");
        return NULL;
    }

    /* get a minor number for the dev */
    r = persistent ? specific_minor(minor) : next_free_minor(&minor);

    blk_queue_make_request(md->queue, dm_request);

    md->disk = alloc_disk(1);

    md->disk->major = _major;
    md->disk->first_minor = minor;
    md->disk->queue = md->queue;

    sprintf(md->disk->disk_name, "dm-%d", minor);
    add_disk(md->disk);

    init_waitqueue_head(&md->wait);
    init_waitqueue_head(&md->eventq);
}

1)对于指定minor

/*
 * See if the device with a specific minor # is free.
 */
static int specific_minor(unsigned int minor)
{
    int r, m;

    if (minor >= (1 << MINORBITS))
        return -EINVAL;

    down(&_minor_lock);

    if (idr_find(&_minor_idr, minor)) {
        r = -EBUSY;
        goto out;
    }

    r = idr_pre_get(&_minor_idr, GFP_KERNEL);
    if (!r) {
        r = -ENOMEM;
        goto out;
    }

    r = idr_get_new_above(&_minor_idr, specific_minor, minor, &m);
    if (r) {
        goto out;
    }

    if (m != minor) {
        idr_remove(&_minor_idr, m);
        r = -EBUSY;
        goto out;
    }

out:
    up(&_minor_lock);
    return r;
}

2)动态分配minor

static int next_free_minor(unsigned int *minor)
{
    int r;
    unsigned int m;

    down(&_minor_lock);

    r = idr_pre_get(&_minor_idr, GFP_KERNEL);
    if (!r) {
        r = -ENOMEM;
        goto out;
    }

    r = idr_get_new(&_minor_idr, next_free_minor, &m);
    if (r) {
        goto out;
    }

    if (m >= (1 << MINORBITS)) {
        idr_remove(&_minor_idr, m);
        r = -ENOSPC;
        goto out;
    }

    *minor = m;

out:
    up(&_minor_lock);
    return r;
}


3)ioctl
static int dev_create(struct dm_ioctl *param, size_t param_size)
{      
    int r;
    struct mapped_device *md;

    r = check_name(param->name);
    if (r)   
        return r;
   
    if (param->flags & DM_PERSISTENT_DEV_FLAG)
        r = dm_create_with_minor(MINOR(huge_decode_dev(param->dev)), &md);
    else
        r = dm_create(&md);
}
阅读(1860) | 评论(0) | 转发(0) |
0

上一篇:进程结构

下一篇:关于alignment问题

给主人留下些什么吧!~~