From ac7036c13113ed58bc9851d2808467dfeda8daed Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov Date: Mon, 9 Feb 2009 17:02:39 +0300 Subject: Staging: pohmelfs: distributed locking and cache coherency protocol. POHMELFS utilizes writeback cache, which is built on top of MO(E)SI-like coherency protocol. This patch includes its implementation and cache object processing helpers (like allocation and completion callbacks). POHMELFS uses scalable cached read/write locking. No additional requests are performed if lock is granted to the filesystem. The same protocol is used by the server to on-demand flushing of the client's cache (for example when server wants to update local data). Signed-off-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman --- drivers/staging/pohmelfs/mcache.c | 171 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 drivers/staging/pohmelfs/mcache.c (limited to 'drivers/staging/pohmelfs/mcache.c') diff --git a/drivers/staging/pohmelfs/mcache.c b/drivers/staging/pohmelfs/mcache.c new file mode 100644 index 00000000000..e22665cdd16 --- /dev/null +++ b/drivers/staging/pohmelfs/mcache.c @@ -0,0 +1,171 @@ +/* + * 2007+ Copyright (c) Evgeniy Polyakov + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include + +#include "netfs.h" + +static struct kmem_cache *pohmelfs_mcache_cache; +static mempool_t *pohmelfs_mcache_pool; + +static inline int pohmelfs_mcache_cmp(u64 gen, u64 new) +{ + if (gen < new) + return 1; + if (gen > new) + return -1; + return 0; +} + +struct pohmelfs_mcache *pohmelfs_mcache_search(struct pohmelfs_sb *psb, u64 gen) +{ + struct rb_root *root = &psb->mcache_root; + struct rb_node *n = root->rb_node; + struct pohmelfs_mcache *tmp, *ret = NULL; + int cmp; + + while (n) { + tmp = rb_entry(n, struct pohmelfs_mcache, mcache_entry); + + cmp = pohmelfs_mcache_cmp(tmp->gen, gen); + if (cmp < 0) + n = n->rb_left; + else if (cmp > 0) + n = n->rb_right; + else { + ret = tmp; + pohmelfs_mcache_get(ret); + break; + } + } + + return ret; +} + +static int pohmelfs_mcache_insert(struct pohmelfs_sb *psb, struct pohmelfs_mcache *m) +{ + struct rb_root *root = &psb->mcache_root; + struct rb_node **n = &root->rb_node, *parent = NULL; + struct pohmelfs_mcache *ret = NULL, *tmp; + int cmp; + + while (*n) { + parent = *n; + + tmp = rb_entry(parent, struct pohmelfs_mcache, mcache_entry); + + cmp = pohmelfs_mcache_cmp(tmp->gen, m->gen); + if (cmp < 0) + n = &parent->rb_left; + else if (cmp > 0) + n = &parent->rb_right; + else { + ret = tmp; + break; + } + } + + if (ret) + return -EEXIST; + + rb_link_node(&m->mcache_entry, parent, n); + rb_insert_color(&m->mcache_entry, root); + + return 0; +} + +static int pohmelfs_mcache_remove(struct pohmelfs_sb *psb, struct pohmelfs_mcache *m) +{ + if (m && m->mcache_entry.rb_parent_color) { + rb_erase(&m->mcache_entry, &psb->mcache_root); + m->mcache_entry.rb_parent_color = 0; + return 1; + } + return 0; +} + +void pohmelfs_mcache_remove_locked(struct pohmelfs_sb *psb, struct pohmelfs_mcache *m) +{ + mutex_lock(&psb->mcache_lock); + pohmelfs_mcache_remove(psb, m); + mutex_unlock(&psb->mcache_lock); +} + +struct pohmelfs_mcache *pohmelfs_mcache_alloc(struct pohmelfs_sb *psb, u64 start, + unsigned int size, void *data) +{ + struct pohmelfs_mcache *m; + int err = -ENOMEM; + + m = mempool_alloc(pohmelfs_mcache_pool, GFP_KERNEL); + if (!m) + goto err_out_exit; + + init_completion(&m->complete); + m->err = 0; + atomic_set(&m->refcnt, 1); + m->data = data; + m->start = start; + m->size = size; + m->gen = atomic_long_inc_return(&psb->mcache_gen); + + mutex_lock(&psb->mcache_lock); + err = pohmelfs_mcache_insert(psb, m); + mutex_unlock(&psb->mcache_lock); + if (err) + goto err_out_free; + + return m; + +err_out_free: + mempool_free(m, pohmelfs_mcache_pool); +err_out_exit: + return ERR_PTR(err); +} + +void pohmelfs_mcache_free(struct pohmelfs_sb *psb, struct pohmelfs_mcache *m) +{ + pohmelfs_mcache_remove_locked(psb, m); + + mempool_free(m, pohmelfs_mcache_pool); +} + +int __init pohmelfs_mcache_init(void) +{ + pohmelfs_mcache_cache = kmem_cache_create("pohmelfs_mcache_cache", + sizeof(struct pohmelfs_mcache), + 0, (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD), NULL); + if (!pohmelfs_mcache_cache) + goto err_out_exit; + + pohmelfs_mcache_pool = mempool_create_slab_pool(256, pohmelfs_mcache_cache); + if (!pohmelfs_mcache_pool) + goto err_out_free; + + return 0; + +err_out_free: + kmem_cache_destroy(pohmelfs_mcache_cache); +err_out_exit: + return -ENOMEM; +} + +void pohmelfs_mcache_exit(void) +{ + mempool_destroy(pohmelfs_mcache_pool); + kmem_cache_destroy(pohmelfs_mcache_cache); +} -- cgit v1.2.3