linux-old/fs/iobuf.c
<<
>>
Prefs
   1/*
   2 * iobuf.c
   3 *
   4 * Keep track of the general-purpose IO-buffer structures used to track
   5 * abstract kernel-space io buffers.
   6 * 
   7 */
   8
   9#include <linux/iobuf.h>
  10#include <linux/slab.h>
  11#include <linux/vmalloc.h>
  12
  13
  14static kmem_cache_t *kiobuf_cachep;
  15
  16void end_kio_request(struct kiobuf *kiobuf, int uptodate)
  17{
  18        if ((!uptodate) && !kiobuf->errno)
  19                kiobuf->errno = -EIO;
  20
  21        if (atomic_dec_and_test(&kiobuf->io_count)) {
  22                if (kiobuf->end_io)
  23                        kiobuf->end_io(kiobuf);
  24                wake_up(&kiobuf->wait_queue);
  25        }
  26}
  27
  28static int kiobuf_init(struct kiobuf *iobuf)
  29{
  30        init_waitqueue_head(&iobuf->wait_queue);
  31        iobuf->array_len = 0;
  32        iobuf->nr_pages = 0;
  33        iobuf->locked = 0;
  34        iobuf->bh = NULL;
  35        iobuf->blocks = NULL;
  36        atomic_set(&iobuf->io_count, 0);
  37        iobuf->end_io = NULL;
  38        return expand_kiobuf(iobuf, KIO_STATIC_PAGES);
  39}
  40
  41int alloc_kiobuf_bhs(struct kiobuf * kiobuf)
  42{
  43        int i;
  44
  45        kiobuf->blocks =
  46                kmalloc(sizeof(*kiobuf->blocks) * KIO_MAX_SECTORS, GFP_KERNEL);
  47        if (unlikely(!kiobuf->blocks))
  48                goto nomem;
  49        kiobuf->bh =
  50                kmalloc(sizeof(*kiobuf->bh) * KIO_MAX_SECTORS, GFP_KERNEL);
  51        if (unlikely(!kiobuf->bh))
  52                goto nomem;
  53
  54        for (i = 0; i < KIO_MAX_SECTORS; i++) {
  55                kiobuf->bh[i] = kmem_cache_alloc(bh_cachep, GFP_KERNEL);
  56                if (unlikely(!kiobuf->bh[i]))
  57                        goto nomem2;
  58        }
  59
  60        return 0;
  61
  62nomem2:
  63        while (i--) {
  64                kmem_cache_free(bh_cachep, kiobuf->bh[i]);
  65                kiobuf->bh[i] = NULL;
  66        }
  67        memset(kiobuf->bh, 0, sizeof(*kiobuf->bh) * KIO_MAX_SECTORS);
  68
  69nomem:
  70        free_kiobuf_bhs(kiobuf);
  71        return -ENOMEM;
  72}
  73
  74void free_kiobuf_bhs(struct kiobuf * kiobuf)
  75{
  76        int i;
  77
  78        if (kiobuf->bh) {
  79                for (i = 0; i < KIO_MAX_SECTORS; i++)
  80                        if (kiobuf->bh[i])
  81                                kmem_cache_free(bh_cachep, kiobuf->bh[i]);
  82                kfree(kiobuf->bh);
  83                kiobuf->bh = NULL;
  84        }
  85
  86        if (kiobuf->blocks) {
  87                kfree(kiobuf->blocks);
  88                kiobuf->blocks = NULL;
  89        }
  90}
  91
  92int alloc_kiovec(int nr, struct kiobuf **bufp)
  93{
  94        int i;
  95        struct kiobuf *iobuf;
  96        
  97        for (i = 0; i < nr; i++) {
  98                iobuf = kmem_cache_alloc(kiobuf_cachep, GFP_KERNEL);
  99                if (unlikely(!iobuf))
 100                        goto nomem;
 101                if (unlikely(kiobuf_init(iobuf)))
 102                        goto nomem2;
 103                if (unlikely(alloc_kiobuf_bhs(iobuf)))
 104                        goto nomem2;
 105                bufp[i] = iobuf;
 106        }
 107        
 108        return 0;
 109
 110nomem2:
 111        kmem_cache_free(kiobuf_cachep, iobuf);
 112nomem:
 113        free_kiovec(i, bufp);
 114        return -ENOMEM;
 115}
 116
 117void free_kiovec(int nr, struct kiobuf **bufp) 
 118{
 119        int i;
 120        struct kiobuf *iobuf;
 121        
 122        for (i = 0; i < nr; i++) {
 123                iobuf = bufp[i];
 124                if (iobuf->locked)
 125                        unlock_kiovec(1, &iobuf);
 126                kfree(iobuf->maplist);
 127                free_kiobuf_bhs(iobuf);
 128                kmem_cache_free(kiobuf_cachep, bufp[i]);
 129        }
 130}
 131
 132int expand_kiobuf(struct kiobuf *iobuf, int wanted)
 133{
 134        struct page ** maplist;
 135        
 136        if (iobuf->array_len >= wanted)
 137                return 0;
 138        
 139        maplist = kmalloc(wanted * sizeof(struct page **), GFP_KERNEL);
 140        if (unlikely(!maplist))
 141                return -ENOMEM;
 142
 143        /* Did it grow while we waited? */
 144        if (unlikely(iobuf->array_len >= wanted)) {
 145                kfree(maplist);
 146                return 0;
 147        }
 148
 149        if (iobuf->array_len) {
 150                memcpy(maplist, iobuf->maplist, iobuf->array_len * sizeof(*maplist));
 151                kfree(iobuf->maplist);
 152        }
 153        
 154        iobuf->maplist   = maplist;
 155        iobuf->array_len = wanted;
 156        return 0;
 157}
 158
 159void kiobuf_wait_for_io(struct kiobuf *kiobuf)
 160{
 161        struct task_struct *tsk = current;
 162        DECLARE_WAITQUEUE(wait, tsk);
 163
 164        if (atomic_read(&kiobuf->io_count) == 0)
 165                return;
 166
 167        add_wait_queue(&kiobuf->wait_queue, &wait);
 168repeat:
 169        set_task_state(tsk, TASK_UNINTERRUPTIBLE);
 170        if (atomic_read(&kiobuf->io_count) != 0) {
 171                run_task_queue(&tq_disk);
 172                schedule();
 173                if (atomic_read(&kiobuf->io_count) != 0)
 174                        goto repeat;
 175        }
 176        tsk->state = TASK_RUNNING;
 177        remove_wait_queue(&kiobuf->wait_queue, &wait);
 178}
 179
 180void __init iobuf_cache_init(void)
 181{
 182        kiobuf_cachep = kmem_cache_create("kiobuf", sizeof(struct kiobuf),
 183                                          0, SLAB_HWCACHE_ALIGN, NULL, NULL);
 184        if (!kiobuf_cachep)
 185                panic("Cannot create kiobuf SLAB cache");
 186}
 187
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.