diff options
-rw-r--r-- | fs/ocfs2/stack_user.c | 144 |
1 files changed, 139 insertions, 5 deletions
diff --git a/fs/ocfs2/stack_user.c b/fs/ocfs2/stack_user.c index fdca5d3c7668..ff8d30757924 100644 --- a/fs/ocfs2/stack_user.c +++ b/fs/ocfs2/stack_user.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/miscdevice.h> | 22 | #include <linux/miscdevice.h> |
23 | #include <linux/mutex.h> | 23 | #include <linux/mutex.h> |
24 | #include <linux/reboot.h> | 24 | #include <linux/reboot.h> |
25 | #include <asm/uaccess.h> | ||
25 | 26 | ||
26 | #include "stackglue.h" | 27 | #include "stackglue.h" |
27 | 28 | ||
@@ -40,6 +41,16 @@ | |||
40 | */ | 41 | */ |
41 | 42 | ||
42 | /* | 43 | /* |
44 | * Whether or not the client has done the handshake. | ||
45 | * For now, we have just one protocol version. | ||
46 | */ | ||
47 | #define OCFS2_CONTROL_PROTO "T01\n" | ||
48 | #define OCFS2_CONTROL_PROTO_LEN 4 | ||
49 | #define OCFS2_CONTROL_HANDSHAKE_INVALID (0) | ||
50 | #define OCFS2_CONTROL_HANDSHAKE_READ (1) | ||
51 | #define OCFS2_CONTROL_HANDSHAKE_VALID (2) | ||
52 | |||
53 | /* | ||
43 | * ocfs2_live_connection is refcounted because the filesystem and | 54 | * ocfs2_live_connection is refcounted because the filesystem and |
44 | * miscdevice sides can detach in different order. Let's just be safe. | 55 | * miscdevice sides can detach in different order. Let's just be safe. |
45 | */ | 56 | */ |
@@ -48,11 +59,30 @@ struct ocfs2_live_connection { | |||
48 | struct ocfs2_cluster_connection *oc_conn; | 59 | struct ocfs2_cluster_connection *oc_conn; |
49 | }; | 60 | }; |
50 | 61 | ||
62 | struct ocfs2_control_private { | ||
63 | struct list_head op_list; | ||
64 | int op_state; | ||
65 | }; | ||
66 | |||
51 | static atomic_t ocfs2_control_opened; | 67 | static atomic_t ocfs2_control_opened; |
52 | 68 | ||
53 | static LIST_HEAD(ocfs2_live_connection_list); | 69 | static LIST_HEAD(ocfs2_live_connection_list); |
70 | static LIST_HEAD(ocfs2_control_private_list); | ||
54 | static DEFINE_MUTEX(ocfs2_control_lock); | 71 | static DEFINE_MUTEX(ocfs2_control_lock); |
55 | 72 | ||
73 | static inline void ocfs2_control_set_handshake_state(struct file *file, | ||
74 | int state) | ||
75 | { | ||
76 | struct ocfs2_control_private *p = file->private_data; | ||
77 | p->op_state = state; | ||
78 | } | ||
79 | |||
80 | static inline int ocfs2_control_get_handshake_state(struct file *file) | ||
81 | { | ||
82 | struct ocfs2_control_private *p = file->private_data; | ||
83 | return p->op_state; | ||
84 | } | ||
85 | |||
56 | static struct ocfs2_live_connection *ocfs2_connection_find(const char *name) | 86 | static struct ocfs2_live_connection *ocfs2_connection_find(const char *name) |
57 | { | 87 | { |
58 | size_t len = strlen(name); | 88 | size_t len = strlen(name); |
@@ -119,27 +149,115 @@ static void ocfs2_live_connection_drop(struct ocfs2_live_connection *c) | |||
119 | kfree(c); | 149 | kfree(c); |
120 | } | 150 | } |
121 | 151 | ||
152 | static ssize_t ocfs2_control_cfu(char *target, size_t target_len, | ||
153 | const char __user *buf, size_t count) | ||
154 | { | ||
155 | /* The T01 expects write(2) calls to have exactly one command */ | ||
156 | if (count != target_len) | ||
157 | return -EINVAL; | ||
158 | |||
159 | if (copy_from_user(target, buf, target_len)) | ||
160 | return -EFAULT; | ||
161 | |||
162 | return count; | ||
163 | } | ||
164 | |||
165 | static ssize_t ocfs2_control_validate_handshake(struct file *file, | ||
166 | const char __user *buf, | ||
167 | size_t count) | ||
168 | { | ||
169 | ssize_t ret; | ||
170 | char kbuf[OCFS2_CONTROL_PROTO_LEN]; | ||
171 | |||
172 | ret = ocfs2_control_cfu(kbuf, OCFS2_CONTROL_PROTO_LEN, | ||
173 | buf, count); | ||
174 | if (ret != count) | ||
175 | return ret; | ||
176 | |||
177 | if (strncmp(kbuf, OCFS2_CONTROL_PROTO, OCFS2_CONTROL_PROTO_LEN)) | ||
178 | return -EINVAL; | ||
179 | |||
180 | atomic_inc(&ocfs2_control_opened); | ||
181 | ocfs2_control_set_handshake_state(file, | ||
182 | OCFS2_CONTROL_HANDSHAKE_VALID); | ||
183 | |||
184 | |||
185 | return count; | ||
186 | } | ||
187 | |||
122 | 188 | ||
123 | static ssize_t ocfs2_control_write(struct file *file, | 189 | static ssize_t ocfs2_control_write(struct file *file, |
124 | const char __user *buf, | 190 | const char __user *buf, |
125 | size_t count, | 191 | size_t count, |
126 | loff_t *ppos) | 192 | loff_t *ppos) |
127 | { | 193 | { |
128 | return 0; | 194 | ssize_t ret; |
195 | |||
196 | switch (ocfs2_control_get_handshake_state(file)) { | ||
197 | case OCFS2_CONTROL_HANDSHAKE_INVALID: | ||
198 | ret = -EINVAL; | ||
199 | break; | ||
200 | |||
201 | case OCFS2_CONTROL_HANDSHAKE_READ: | ||
202 | ret = ocfs2_control_validate_handshake(file, buf, | ||
203 | count); | ||
204 | break; | ||
205 | |||
206 | case OCFS2_CONTROL_HANDSHAKE_VALID: | ||
207 | ret = count; /* XXX */ | ||
208 | break; | ||
209 | |||
210 | default: | ||
211 | BUG(); | ||
212 | ret = -EIO; | ||
213 | break; | ||
214 | } | ||
215 | |||
216 | return ret; | ||
129 | } | 217 | } |
130 | 218 | ||
219 | /* | ||
220 | * This is a naive version. If we ever have a new protocol, we'll expand | ||
221 | * it. Probably using seq_file. | ||
222 | */ | ||
131 | static ssize_t ocfs2_control_read(struct file *file, | 223 | static ssize_t ocfs2_control_read(struct file *file, |
132 | char __user *buf, | 224 | char __user *buf, |
133 | size_t count, | 225 | size_t count, |
134 | loff_t *ppos) | 226 | loff_t *ppos) |
135 | { | 227 | { |
136 | return 0; | 228 | char *proto_string = OCFS2_CONTROL_PROTO; |
229 | size_t to_write = 0; | ||
230 | |||
231 | if (*ppos >= OCFS2_CONTROL_PROTO_LEN) | ||
232 | return 0; | ||
233 | |||
234 | to_write = OCFS2_CONTROL_PROTO_LEN - *ppos; | ||
235 | if (to_write > count) | ||
236 | to_write = count; | ||
237 | if (copy_to_user(buf, proto_string + *ppos, to_write)) | ||
238 | return -EFAULT; | ||
239 | |||
240 | *ppos += to_write; | ||
241 | |||
242 | /* Have we read the whole protocol list? */ | ||
243 | if (*ppos >= OCFS2_CONTROL_PROTO_LEN) | ||
244 | ocfs2_control_set_handshake_state(file, | ||
245 | OCFS2_CONTROL_HANDSHAKE_READ); | ||
246 | |||
247 | return to_write; | ||
137 | } | 248 | } |
138 | 249 | ||
139 | static int ocfs2_control_release(struct inode *inode, struct file *file) | 250 | static int ocfs2_control_release(struct inode *inode, struct file *file) |
140 | { | 251 | { |
252 | struct ocfs2_control_private *p = file->private_data; | ||
253 | |||
254 | mutex_lock(&ocfs2_control_lock); | ||
255 | |||
256 | if (ocfs2_control_get_handshake_state(file) != | ||
257 | OCFS2_CONTROL_HANDSHAKE_VALID) | ||
258 | goto out; | ||
259 | |||
141 | if (atomic_dec_and_test(&ocfs2_control_opened)) { | 260 | if (atomic_dec_and_test(&ocfs2_control_opened)) { |
142 | mutex_lock(&ocfs2_control_lock); | ||
143 | if (!list_empty(&ocfs2_live_connection_list)) { | 261 | if (!list_empty(&ocfs2_live_connection_list)) { |
144 | /* XXX: Do bad things! */ | 262 | /* XXX: Do bad things! */ |
145 | printk(KERN_ERR | 263 | printk(KERN_ERR |
@@ -148,15 +266,31 @@ static int ocfs2_control_release(struct inode *inode, struct file *file) | |||
148 | "an emergency restart!\n"); | 266 | "an emergency restart!\n"); |
149 | emergency_restart(); | 267 | emergency_restart(); |
150 | } | 268 | } |
151 | mutex_unlock(&ocfs2_control_lock); | ||
152 | } | 269 | } |
153 | 270 | ||
271 | out: | ||
272 | list_del_init(&p->op_list); | ||
273 | file->private_data = NULL; | ||
274 | |||
275 | mutex_unlock(&ocfs2_control_lock); | ||
276 | |||
277 | kfree(p); | ||
278 | |||
154 | return 0; | 279 | return 0; |
155 | } | 280 | } |
156 | 281 | ||
157 | static int ocfs2_control_open(struct inode *inode, struct file *file) | 282 | static int ocfs2_control_open(struct inode *inode, struct file *file) |
158 | { | 283 | { |
159 | atomic_inc(&ocfs2_control_opened); | 284 | struct ocfs2_control_private *p; |
285 | |||
286 | p = kzalloc(sizeof(struct ocfs2_control_private), GFP_KERNEL); | ||
287 | if (!p) | ||
288 | return -ENOMEM; | ||
289 | |||
290 | mutex_lock(&ocfs2_control_lock); | ||
291 | file->private_data = p; | ||
292 | list_add(&p->op_list, &ocfs2_control_private_list); | ||
293 | mutex_unlock(&ocfs2_control_lock); | ||
160 | 294 | ||
161 | return 0; | 295 | return 0; |
162 | } | 296 | } |