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/mempool.h> 21 22#include "netfs.h" 23 24static int pohmelfs_send_lock_trans(struct pohmelfs_inode *pi, 25 u64 id, u64 start, u32 size, int type) 26{ 27 struct inode *inode = &pi->vfs_inode; 28 struct pohmelfs_sb *psb = POHMELFS_SB(inode->i_sb); 29 struct netfs_trans *t; 30 struct netfs_cmd *cmd; 31 int path_len, err; 32 void *data; 33 struct netfs_lock *l; 34 int isize = (type & POHMELFS_LOCK_GRAB) ? 0 : sizeof(struct netfs_inode_info); 35 36 err = pohmelfs_path_length(pi); 37 if (err < 0) 38 goto err_out_exit; 39 40 path_len = err; 41 42 err = -ENOMEM; 43 t = netfs_trans_alloc(psb, path_len + sizeof(struct netfs_lock) + isize, 44 NETFS_TRANS_SINGLE_DST, 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 92err_out_free: 93 netfs_trans_free(t); 94err_out_exit: 95 printk("%s: err: %d.\n", __func__, err); 96 return err; 97} 98 99int 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 169err_out_put: 170 pohmelfs_mcache_put(psb, m); 171 return err; 172} 173 174int 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} 183