]>
Commit | Line | Data |
---|---|---|
ac7036c1 EP |
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> | |
ac7036c1 EP |
20 | #include <linux/mempool.h> |
21 | ||
22 | #include "netfs.h" | |
23 | ||
24 | static 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; | |
d43f3612 EP |
43 | t = netfs_trans_alloc(psb, path_len + sizeof(struct netfs_lock) + isize, |
44 | NETFS_TRANS_SINGLE_DST, 0); | |
ac7036c1 EP |
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 | } |