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/lock.c | 182 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 drivers/staging/pohmelfs/lock.c (limited to 'drivers/staging/pohmelfs/lock.c') diff --git a/drivers/staging/pohmelfs/lock.c b/drivers/staging/pohmelfs/lock.c new file mode 100644 index 00000000000..ad4a18559bd --- /dev/null +++ b/drivers/staging/pohmelfs/lock.c @@ -0,0 +1,182 @@ +/* + * 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 +#include +#include + +#include "netfs.h" + +static int pohmelfs_send_lock_trans(struct pohmelfs_inode *pi, + u64 id, u64 start, u32 size, int type) +{ + struct inode *inode = &pi->vfs_inode; + struct pohmelfs_sb *psb = POHMELFS_SB(inode->i_sb); + struct netfs_trans *t; + struct netfs_cmd *cmd; + int path_len, err; + void *data; + struct netfs_lock *l; + int isize = (type & POHMELFS_LOCK_GRAB) ? 0 : sizeof(struct netfs_inode_info); + + err = pohmelfs_path_length(pi); + if (err < 0) + goto err_out_exit; + + path_len = err; + + err = -ENOMEM; + t = netfs_trans_alloc(psb, path_len + sizeof(struct netfs_lock) + isize, 0, 0); + if (!t) + goto err_out_exit; + + cmd = netfs_trans_current(t); + data = cmd + 1; + + err = pohmelfs_construct_path_string(pi, data, path_len); + if (err < 0) + goto err_out_free; + path_len = err; + + l = data + path_len; + + l->start = start; + l->size = size; + l->type = type; + l->ino = pi->ino; + + cmd->cmd = NETFS_LOCK; + cmd->start = 0; + cmd->id = id; + cmd->size = sizeof(struct netfs_lock) + path_len + isize; + cmd->ext = path_len; + cmd->csize = 0; + + netfs_convert_cmd(cmd); + netfs_convert_lock(l); + + if (isize) { + struct netfs_inode_info *info = (struct netfs_inode_info *)(l + 1); + + info->mode = inode->i_mode; + info->nlink = inode->i_nlink; + info->uid = inode->i_uid; + info->gid = inode->i_gid; + info->blocks = inode->i_blocks; + info->rdev = inode->i_rdev; + info->size = inode->i_size; + info->version = inode->i_version; + + netfs_convert_inode_info(info); + } + + netfs_trans_update(cmd, t, path_len + sizeof(struct netfs_lock) + isize); + + return netfs_trans_finish(t, psb); + +err_out_free: + netfs_trans_free(t); +err_out_exit: + printk("%s: err: %d.\n", __func__, err); + return err; +} + +int pohmelfs_data_lock(struct pohmelfs_inode *pi, u64 start, u32 size, int type) +{ + struct pohmelfs_sb *psb = POHMELFS_SB(pi->vfs_inode.i_sb); + struct pohmelfs_mcache *m; + int err = -ENOMEM; + struct iattr iattr; + struct inode *inode = &pi->vfs_inode; + + dprintk("%s: %p: ino: %llu, start: %llu, size: %u, " + "type: %d, locked as: %d, owned: %d.\n", + __func__, &pi->vfs_inode, pi->ino, + start, size, type, pi->lock_type, + !!test_bit(NETFS_INODE_OWNED, &pi->state)); + + if (!pohmelfs_need_lock(pi, type)) + return 0; + + m = pohmelfs_mcache_alloc(psb, start, size, NULL); + if (IS_ERR(m)) + return PTR_ERR(m); + + err = pohmelfs_send_lock_trans(pi, m->gen, start, size, + type | POHMELFS_LOCK_GRAB); + if (err) + goto err_out_put; + + err = wait_for_completion_timeout(&m->complete, psb->mcache_timeout); + if (err) + err = m->err; + else + err = -ETIMEDOUT; + + if (err) { + printk("%s: %p: ino: %llu, mgen: %llu, start: %llu, size: %u, err: %d.\n", + __func__, &pi->vfs_inode, pi->ino, m->gen, start, size, err); + } + + if (err && (err != -ENOENT)) + goto err_out_put; + + if (!err) { + netfs_convert_inode_info(&m->info); + + iattr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_SIZE | ATTR_ATIME; + iattr.ia_mode = m->info.mode; + iattr.ia_uid = m->info.uid; + iattr.ia_gid = m->info.gid; + iattr.ia_size = m->info.size; + iattr.ia_atime = CURRENT_TIME; + + dprintk("%s: %p: ino: %llu, mgen: %llu, start: %llu, isize: %llu -> %llu.\n", + __func__, &pi->vfs_inode, pi->ino, m->gen, start, inode->i_size, m->info.size); + + err = pohmelfs_setattr_raw(inode, &iattr); + if (!err) { + struct dentry *dentry = d_find_alias(inode); + if (dentry) { + fsnotify_change(dentry, iattr.ia_valid); + dput(dentry); + } + } + } + + pi->lock_type = type; + set_bit(NETFS_INODE_OWNED, &pi->state); + + pohmelfs_mcache_put(psb, m); + + return 0; + +err_out_put: + pohmelfs_mcache_put(psb, m); + return err; +} + +int pohmelfs_data_unlock(struct pohmelfs_inode *pi, u64 start, u32 size, int type) +{ + dprintk("%s: %p: ino: %llu, start: %llu, size: %u, type: %d.\n", + __func__, &pi->vfs_inode, pi->ino, start, size, type); + pi->lock_type = 0; + clear_bit(NETFS_INODE_REMOTE_DIR_SYNCED, &pi->state); + clear_bit(NETFS_INODE_OWNED, &pi->state); + return pohmelfs_send_lock_trans(pi, pi->ino, start, size, type); +} -- cgit v1.2.3