linux/drivers/staging/pohmelfs/mcache.c
<<
>>
Prefs
   1/*
   2 * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
   3 * All rights reserved.
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation; either version 2 of the License, or
   8 * (at your option) any later version.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 */
  15
  16#include <linux/module.h>
  17#include <linux/slab.h>
  18#include <linux/mempool.h>
  19
  20#include "netfs.h"
  21
  22static struct kmem_cache *pohmelfs_mcache_cache;
  23static mempool_t *pohmelfs_mcache_pool;
  24
  25static inline int pohmelfs_mcache_cmp(u64 gen, u64 new)
  26{
  27        if (gen < new)
  28                return 1;
  29        if (gen > new)
  30                return -1;
  31        return 0;
  32}
  33
  34struct pohmelfs_mcache *pohmelfs_mcache_search(struct pohmelfs_sb *psb, u64 gen)
  35{
  36        struct rb_root *root = &psb->mcache_root;
  37        struct rb_node *n = root->rb_node;
  38        struct pohmelfs_mcache *tmp, *ret = NULL;
  39        int cmp;
  40
  41        while (n) {
  42                tmp = rb_entry(n, struct pohmelfs_mcache, mcache_entry);
  43
  44                cmp = pohmelfs_mcache_cmp(tmp->gen, gen);
  45                if (cmp < 0)
  46                        n = n->rb_left;
  47                else if (cmp > 0)
  48                        n = n->rb_right;
  49                else {
  50                        ret = tmp;
  51                        pohmelfs_mcache_get(ret);
  52                        break;
  53                }
  54        }
  55
  56        return ret;
  57}
  58
  59static int pohmelfs_mcache_insert(struct pohmelfs_sb *psb, struct pohmelfs_mcache *m)
  60{
  61        struct rb_root *root = &psb->mcache_root;
  62        struct rb_node **n = &root->rb_node, *parent = NULL;
  63        struct pohmelfs_mcache *ret = NULL, *tmp;
  64        int cmp;
  65
  66        while (*n) {
  67                parent = *n;
  68
  69                tmp = rb_entry(parent, struct pohmelfs_mcache, mcache_entry);
  70
  71                cmp = pohmelfs_mcache_cmp(tmp->gen, m->gen);
  72                if (cmp < 0)
  73                        n = &parent->rb_left;
  74                else if (cmp > 0)
  75                        n = &parent->rb_right;
  76                else {
  77                        ret = tmp;
  78                        break;
  79                }
  80        }
  81
  82        if (ret)
  83                return -EEXIST;
  84
  85        rb_link_node(&m->mcache_entry, parent, n);
  86        rb_insert_color(&m->mcache_entry, root);
  87
  88        return 0;
  89}
  90
  91static int pohmelfs_mcache_remove(struct pohmelfs_sb *psb, struct pohmelfs_mcache *m)
  92{
  93        if (m && m->mcache_entry.rb_parent_color) {
  94                rb_erase(&m->mcache_entry, &psb->mcache_root);
  95                m->mcache_entry.rb_parent_color = 0;
  96                return 1;
  97        }
  98        return 0;
  99}
 100
 101void pohmelfs_mcache_remove_locked(struct pohmelfs_sb *psb, struct pohmelfs_mcache *m)
 102{
 103        mutex_lock(&psb->mcache_lock);
 104        pohmelfs_mcache_remove(psb, m);
 105        mutex_unlock(&psb->mcache_lock);
 106}
 107
 108struct pohmelfs_mcache *pohmelfs_mcache_alloc(struct pohmelfs_sb *psb, u64 start,
 109                unsigned int size, void *data)
 110{
 111        struct pohmelfs_mcache *m;
 112        int err = -ENOMEM;
 113
 114        m = mempool_alloc(pohmelfs_mcache_pool, GFP_KERNEL);
 115        if (!m)
 116                goto err_out_exit;
 117
 118        init_completion(&m->complete);
 119        m->err = 0;
 120        atomic_set(&m->refcnt, 1);
 121        m->data = data;
 122        m->start = start;
 123        m->size = size;
 124        m->gen = atomic_long_inc_return(&psb->mcache_gen);
 125
 126        mutex_lock(&psb->mcache_lock);
 127        err = pohmelfs_mcache_insert(psb, m);
 128        mutex_unlock(&psb->mcache_lock);
 129        if (err)
 130                goto err_out_free;
 131
 132        return m;
 133
 134err_out_free:
 135        mempool_free(m, pohmelfs_mcache_pool);
 136err_out_exit:
 137        return ERR_PTR(err);
 138}
 139
 140void pohmelfs_mcache_free(struct pohmelfs_sb *psb, struct pohmelfs_mcache *m)
 141{
 142        pohmelfs_mcache_remove_locked(psb, m);
 143
 144        mempool_free(m, pohmelfs_mcache_pool);
 145}
 146
 147int __init pohmelfs_mcache_init(void)
 148{
 149        pohmelfs_mcache_cache = kmem_cache_create("pohmelfs_mcache_cache",
 150                                sizeof(struct pohmelfs_mcache),
 151                                0, (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD), NULL);
 152        if (!pohmelfs_mcache_cache)
 153                goto err_out_exit;
 154
 155        pohmelfs_mcache_pool = mempool_create_slab_pool(256, pohmelfs_mcache_cache);
 156        if (!pohmelfs_mcache_pool)
 157                goto err_out_free;
 158
 159        return 0;
 160
 161err_out_free:
 162        kmem_cache_destroy(pohmelfs_mcache_cache);
 163err_out_exit:
 164        return -ENOMEM;
 165}
 166
 167void pohmelfs_mcache_exit(void)
 168{
 169        mempool_destroy(pohmelfs_mcache_pool);
 170        kmem_cache_destroy(pohmelfs_mcache_cache);
 171}
 172