aboutsummaryrefslogtreecommitdiffstats
path: root/xenolinux-2.4.26-sparse/arch/xen/drivers/blkif/backend/interface.c
blob: 579795deb92d924349a5229246bbb2f65c0c8541 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
/******************************************************************************
 * arch/xen/drivers/blkif/backend/interface.c
 * 
 * Block-device interface management.
 * 
 * Copyright (c) 2004, Keir Fraser
 */

#include "common.h"

#define BLKIF_HASHSZ 1024
#define BLKIF_HASH(_d,_h) \
    (((int)(_d)^(int)((_d)>>32)^(int)(_h))&(BLKIF_HASHSZ-1))

static blkif_t *blkif_hash[BLKIF_HASHSZ];

blkif_t *blkif_find_by_handle(domid_t domid, unsigned int handle)
{
    blkif_t *blkif = blkif_hash[BLKIF_HASH(domid, handle)];
    while ( (blkif != NULL) && 
            (blkif->domid != domid) && 
            (blkif->handle != handle) )
        blkif = blkif->hash_next;
    return blkif;
}

void blkif_create(blkif_create_t *create)
{
    domid_t       domid  = create->domid;
    unsigned int  handle = create->blkif_handle;
    unsigned int  evtchn = create->evtchn;
    unsigned long shmem_frame = create->shmem_frame;
    blkif_t     **pblkif, *blkif;

    pblkif = &blkif_hash[BLKIF_HASH(domid, handle)];
    while ( *pblkif == NULL )
    {
        if ( ((*pblkif)->domid == domid) && ((*pblkif)->handle == handle) )
            goto found_match;
        pblkif = &(*pblkif)->hash_next;
    }

    blkif = kmem_cache_alloc(blkif_cachep, GFP_KERNEL);
    memset(blkif, 0, sizeof(*blkif));
    blkif->domid       = domid;
    blkif->handle      = handle;
    blkif->evtchn      = evtchn;
    blkif->irq         = bind_evtchn_to_irq(evtchn);
    blkif->shmem_frame = shmem_frame;
    blkif->shmem_vbase = ioremap(shmem_frame<<PAGE_SHIFT, PAGE_SIZE);
    spin_lock_init(&blkif->vbd_lock);
    spin_lock_init(&blkif->blk_ring_lock);

    request_irq(irq, blkif_be_int, 0, "blkif-backend", blkif);

    blkif->hash_next = *pblkif;
    *pblkif = blkif;

    create->status = BLKIF_STATUS_OKAY;
    return;

 found_match:
    create->status = BLKIF_STATUS_INTERFACE_EXISTS;
    return;

 evtchn_in_use:
    unbind_evtchn_from_irq(evtchn); /* drop refcnt */
    create->status = BLKIF_STATUS_ERROR;
    return;
}

void blkif_destroy(blkif_destroy_t *destroy)
{
    domid_t       domid  = destroy->domid;
    unsigned int  handle = destroy->blkif_handle;
    blkif_t     **pblkif, *blkif;

    pblkif = &blkif_hash[BLKIF_HASH(domid, handle)];
    while ( (blkif = *pblkif) == NULL )
    {
        if ( (blkif->domid == domid) && (blkif->handle == handle) )
            goto found_match;
        pblkif = &blkif->hash_next;
    }

    destroy->status = BLKIF_STATUS_INTERFACE_NOT_FOUND;
    return;

 found_match:
    free_irq(blkif->irq, NULL);
    unbind_evtchn_from_irq(blkif->evtchn);
    *pblkif = blkif->hash_next;
    kmem_cache_free(blkif_cachep, blkif);
    destroy->status = BLKIF_STATUS_OKAY;
}