Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <zbr@ioremap.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Evgeniy Polyakov and committed by
Greg Kroah-Hartman
ac7036c1 b3f08cad

+353
+182
drivers/staging/pohmelfs/lock.c
··· 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/backing-dev.h> 18 + #include <linux/fs.h> 19 + #include <linux/fsnotify.h> 20 + #include <linux/slab.h> 21 + #include <linux/mempool.h> 22 + 23 + #include "netfs.h" 24 + 25 + static int pohmelfs_send_lock_trans(struct pohmelfs_inode *pi, 26 + u64 id, u64 start, u32 size, int type) 27 + { 28 + struct inode *inode = &pi->vfs_inode; 29 + struct pohmelfs_sb *psb = POHMELFS_SB(inode->i_sb); 30 + struct netfs_trans *t; 31 + struct netfs_cmd *cmd; 32 + int path_len, err; 33 + void *data; 34 + struct netfs_lock *l; 35 + int isize = (type & POHMELFS_LOCK_GRAB) ? 0 : sizeof(struct netfs_inode_info); 36 + 37 + err = pohmelfs_path_length(pi); 38 + if (err < 0) 39 + goto err_out_exit; 40 + 41 + path_len = err; 42 + 43 + err = -ENOMEM; 44 + t = netfs_trans_alloc(psb, path_len + sizeof(struct netfs_lock) + isize, 0, 0); 45 + if (!t) 46 + goto err_out_exit; 47 + 48 + cmd = netfs_trans_current(t); 49 + data = cmd + 1; 50 + 51 + err = pohmelfs_construct_path_string(pi, data, path_len); 52 + if (err < 0) 53 + goto err_out_free; 54 + path_len = err; 55 + 56 + l = data + path_len; 57 + 58 + l->start = start; 59 + l->size = size; 60 + l->type = type; 61 + l->ino = pi->ino; 62 + 63 + cmd->cmd = NETFS_LOCK; 64 + cmd->start = 0; 65 + cmd->id = id; 66 + cmd->size = sizeof(struct netfs_lock) + path_len + isize; 67 + cmd->ext = path_len; 68 + cmd->csize = 0; 69 + 70 + netfs_convert_cmd(cmd); 71 + netfs_convert_lock(l); 72 + 73 + if (isize) { 74 + struct netfs_inode_info *info = (struct netfs_inode_info *)(l + 1); 75 + 76 + info->mode = inode->i_mode; 77 + info->nlink = inode->i_nlink; 78 + info->uid = inode->i_uid; 79 + info->gid = inode->i_gid; 80 + info->blocks = inode->i_blocks; 81 + info->rdev = inode->i_rdev; 82 + info->size = inode->i_size; 83 + info->version = inode->i_version; 84 + 85 + netfs_convert_inode_info(info); 86 + } 87 + 88 + netfs_trans_update(cmd, t, path_len + sizeof(struct netfs_lock) + isize); 89 + 90 + return netfs_trans_finish(t, psb); 91 + 92 + err_out_free: 93 + netfs_trans_free(t); 94 + err_out_exit: 95 + printk("%s: err: %d.\n", __func__, err); 96 + return err; 97 + } 98 + 99 + int pohmelfs_data_lock(struct pohmelfs_inode *pi, u64 start, u32 size, int type) 100 + { 101 + struct pohmelfs_sb *psb = POHMELFS_SB(pi->vfs_inode.i_sb); 102 + struct pohmelfs_mcache *m; 103 + int err = -ENOMEM; 104 + struct iattr iattr; 105 + struct inode *inode = &pi->vfs_inode; 106 + 107 + dprintk("%s: %p: ino: %llu, start: %llu, size: %u, " 108 + "type: %d, locked as: %d, owned: %d.\n", 109 + __func__, &pi->vfs_inode, pi->ino, 110 + start, size, type, pi->lock_type, 111 + !!test_bit(NETFS_INODE_OWNED, &pi->state)); 112 + 113 + if (!pohmelfs_need_lock(pi, type)) 114 + return 0; 115 + 116 + m = pohmelfs_mcache_alloc(psb, start, size, NULL); 117 + if (IS_ERR(m)) 118 + return PTR_ERR(m); 119 + 120 + err = pohmelfs_send_lock_trans(pi, m->gen, start, size, 121 + type | POHMELFS_LOCK_GRAB); 122 + if (err) 123 + goto err_out_put; 124 + 125 + err = wait_for_completion_timeout(&m->complete, psb->mcache_timeout); 126 + if (err) 127 + err = m->err; 128 + else 129 + err = -ETIMEDOUT; 130 + 131 + if (err) { 132 + printk("%s: %p: ino: %llu, mgen: %llu, start: %llu, size: %u, err: %d.\n", 133 + __func__, &pi->vfs_inode, pi->ino, m->gen, start, size, err); 134 + } 135 + 136 + if (err && (err != -ENOENT)) 137 + goto err_out_put; 138 + 139 + if (!err) { 140 + netfs_convert_inode_info(&m->info); 141 + 142 + iattr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_SIZE | ATTR_ATIME; 143 + iattr.ia_mode = m->info.mode; 144 + iattr.ia_uid = m->info.uid; 145 + iattr.ia_gid = m->info.gid; 146 + iattr.ia_size = m->info.size; 147 + iattr.ia_atime = CURRENT_TIME; 148 + 149 + dprintk("%s: %p: ino: %llu, mgen: %llu, start: %llu, isize: %llu -> %llu.\n", 150 + __func__, &pi->vfs_inode, pi->ino, m->gen, start, inode->i_size, m->info.size); 151 + 152 + err = pohmelfs_setattr_raw(inode, &iattr); 153 + if (!err) { 154 + struct dentry *dentry = d_find_alias(inode); 155 + if (dentry) { 156 + fsnotify_change(dentry, iattr.ia_valid); 157 + dput(dentry); 158 + } 159 + } 160 + } 161 + 162 + pi->lock_type = type; 163 + set_bit(NETFS_INODE_OWNED, &pi->state); 164 + 165 + pohmelfs_mcache_put(psb, m); 166 + 167 + return 0; 168 + 169 + err_out_put: 170 + pohmelfs_mcache_put(psb, m); 171 + return err; 172 + } 173 + 174 + int pohmelfs_data_unlock(struct pohmelfs_inode *pi, u64 start, u32 size, int type) 175 + { 176 + dprintk("%s: %p: ino: %llu, start: %llu, size: %u, type: %d.\n", 177 + __func__, &pi->vfs_inode, pi->ino, start, size, type); 178 + pi->lock_type = 0; 179 + clear_bit(NETFS_INODE_REMOTE_DIR_SYNCED, &pi->state); 180 + clear_bit(NETFS_INODE_OWNED, &pi->state); 181 + return pohmelfs_send_lock_trans(pi, pi->ino, start, size, type); 182 + }
+171
drivers/staging/pohmelfs/mcache.c
··· 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 + 22 + static struct kmem_cache *pohmelfs_mcache_cache; 23 + static mempool_t *pohmelfs_mcache_pool; 24 + 25 + static 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 + 34 + struct 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 + 59 + static 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 + 91 + static 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 + 101 + void 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 + 108 + struct 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 + 134 + err_out_free: 135 + mempool_free(m, pohmelfs_mcache_pool); 136 + err_out_exit: 137 + return ERR_PTR(err); 138 + } 139 + 140 + void 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 + 147 + int __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 + 161 + err_out_free: 162 + kmem_cache_destroy(pohmelfs_mcache_cache); 163 + err_out_exit: 164 + return -ENOMEM; 165 + } 166 + 167 + void pohmelfs_mcache_exit(void) 168 + { 169 + mempool_destroy(pohmelfs_mcache_pool); 170 + kmem_cache_destroy(pohmelfs_mcache_cache); 171 + }