Evgeniy Polyakov | ac7036c | 2009-02-09 17:02:39 +0300 | [diff] [blame] | 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; |
Evgeniy Polyakov | d43f361 | 2009-03-27 15:04:30 +0300 | [diff] [blame] | 44 | t = netfs_trans_alloc(psb, path_len + sizeof(struct netfs_lock) + isize, |
| 45 | NETFS_TRANS_SINGLE_DST, 0); |
Evgeniy Polyakov | ac7036c | 2009-02-09 17:02:39 +0300 | [diff] [blame] | 46 | if (!t) |
| 47 | goto err_out_exit; |
| 48 | |
| 49 | cmd = netfs_trans_current(t); |
| 50 | data = cmd + 1; |
| 51 | |
| 52 | err = pohmelfs_construct_path_string(pi, data, path_len); |
| 53 | if (err < 0) |
| 54 | goto err_out_free; |
| 55 | path_len = err; |
| 56 | |
| 57 | l = data + path_len; |
| 58 | |
| 59 | l->start = start; |
| 60 | l->size = size; |
| 61 | l->type = type; |
| 62 | l->ino = pi->ino; |
| 63 | |
| 64 | cmd->cmd = NETFS_LOCK; |
| 65 | cmd->start = 0; |
| 66 | cmd->id = id; |
| 67 | cmd->size = sizeof(struct netfs_lock) + path_len + isize; |
| 68 | cmd->ext = path_len; |
| 69 | cmd->csize = 0; |
| 70 | |
| 71 | netfs_convert_cmd(cmd); |
| 72 | netfs_convert_lock(l); |
| 73 | |
| 74 | if (isize) { |
| 75 | struct netfs_inode_info *info = (struct netfs_inode_info *)(l + 1); |
| 76 | |
| 77 | info->mode = inode->i_mode; |
| 78 | info->nlink = inode->i_nlink; |
| 79 | info->uid = inode->i_uid; |
| 80 | info->gid = inode->i_gid; |
| 81 | info->blocks = inode->i_blocks; |
| 82 | info->rdev = inode->i_rdev; |
| 83 | info->size = inode->i_size; |
| 84 | info->version = inode->i_version; |
| 85 | |
| 86 | netfs_convert_inode_info(info); |
| 87 | } |
| 88 | |
| 89 | netfs_trans_update(cmd, t, path_len + sizeof(struct netfs_lock) + isize); |
| 90 | |
| 91 | return netfs_trans_finish(t, psb); |
| 92 | |
| 93 | err_out_free: |
| 94 | netfs_trans_free(t); |
| 95 | err_out_exit: |
| 96 | printk("%s: err: %d.\n", __func__, err); |
| 97 | return err; |
| 98 | } |
| 99 | |
| 100 | int pohmelfs_data_lock(struct pohmelfs_inode *pi, u64 start, u32 size, int type) |
| 101 | { |
| 102 | struct pohmelfs_sb *psb = POHMELFS_SB(pi->vfs_inode.i_sb); |
| 103 | struct pohmelfs_mcache *m; |
| 104 | int err = -ENOMEM; |
| 105 | struct iattr iattr; |
| 106 | struct inode *inode = &pi->vfs_inode; |
| 107 | |
| 108 | dprintk("%s: %p: ino: %llu, start: %llu, size: %u, " |
| 109 | "type: %d, locked as: %d, owned: %d.\n", |
| 110 | __func__, &pi->vfs_inode, pi->ino, |
| 111 | start, size, type, pi->lock_type, |
| 112 | !!test_bit(NETFS_INODE_OWNED, &pi->state)); |
| 113 | |
| 114 | if (!pohmelfs_need_lock(pi, type)) |
| 115 | return 0; |
| 116 | |
| 117 | m = pohmelfs_mcache_alloc(psb, start, size, NULL); |
| 118 | if (IS_ERR(m)) |
| 119 | return PTR_ERR(m); |
| 120 | |
| 121 | err = pohmelfs_send_lock_trans(pi, m->gen, start, size, |
| 122 | type | POHMELFS_LOCK_GRAB); |
| 123 | if (err) |
| 124 | goto err_out_put; |
| 125 | |
| 126 | err = wait_for_completion_timeout(&m->complete, psb->mcache_timeout); |
| 127 | if (err) |
| 128 | err = m->err; |
| 129 | else |
| 130 | err = -ETIMEDOUT; |
| 131 | |
| 132 | if (err) { |
| 133 | printk("%s: %p: ino: %llu, mgen: %llu, start: %llu, size: %u, err: %d.\n", |
| 134 | __func__, &pi->vfs_inode, pi->ino, m->gen, start, size, err); |
| 135 | } |
| 136 | |
| 137 | if (err && (err != -ENOENT)) |
| 138 | goto err_out_put; |
| 139 | |
| 140 | if (!err) { |
| 141 | netfs_convert_inode_info(&m->info); |
| 142 | |
| 143 | iattr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_SIZE | ATTR_ATIME; |
| 144 | iattr.ia_mode = m->info.mode; |
| 145 | iattr.ia_uid = m->info.uid; |
| 146 | iattr.ia_gid = m->info.gid; |
| 147 | iattr.ia_size = m->info.size; |
| 148 | iattr.ia_atime = CURRENT_TIME; |
| 149 | |
| 150 | dprintk("%s: %p: ino: %llu, mgen: %llu, start: %llu, isize: %llu -> %llu.\n", |
| 151 | __func__, &pi->vfs_inode, pi->ino, m->gen, start, inode->i_size, m->info.size); |
| 152 | |
| 153 | err = pohmelfs_setattr_raw(inode, &iattr); |
| 154 | if (!err) { |
| 155 | struct dentry *dentry = d_find_alias(inode); |
| 156 | if (dentry) { |
| 157 | fsnotify_change(dentry, iattr.ia_valid); |
| 158 | dput(dentry); |
| 159 | } |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | pi->lock_type = type; |
| 164 | set_bit(NETFS_INODE_OWNED, &pi->state); |
| 165 | |
| 166 | pohmelfs_mcache_put(psb, m); |
| 167 | |
| 168 | return 0; |
| 169 | |
| 170 | err_out_put: |
| 171 | pohmelfs_mcache_put(psb, m); |
| 172 | return err; |
| 173 | } |
| 174 | |
| 175 | int pohmelfs_data_unlock(struct pohmelfs_inode *pi, u64 start, u32 size, int type) |
| 176 | { |
| 177 | dprintk("%s: %p: ino: %llu, start: %llu, size: %u, type: %d.\n", |
| 178 | __func__, &pi->vfs_inode, pi->ino, start, size, type); |
| 179 | pi->lock_type = 0; |
| 180 | clear_bit(NETFS_INODE_REMOTE_DIR_SYNCED, &pi->state); |
| 181 | clear_bit(NETFS_INODE_OWNED, &pi->state); |
| 182 | return pohmelfs_send_lock_trans(pi, pi->ino, start, size, type); |
| 183 | } |