1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
3 *
4 * Copyright (C) 2001, 2002 Cluster File Systems, Inc. <braam@clusterfs.com>
5 * Copyright (C) 2001 Tacit Networks, Inc. <phil@off.net>
6 *
7 * This file is part of InterMezzo, http://www.inter-mezzo.org.
8 *
9 * InterMezzo is free software; you can redistribute it and/or
10 * modify it under the terms of version 2 of the GNU General Public
11 * License as published by the Free Software Foundation.
12 *
13 * InterMezzo is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with InterMezzo; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 * Mostly platform independent upcall operations to a cache manager:
23 * -- upcalls
24 * -- upcall routines
25 *
26 */
27
28 #include <asm/system.h>
29 #include <asm/segment.h>
30 #include <asm/signal.h>
31 #include <linux/signal.h>
32
33 #include <linux/types.h>
34 #include <linux/kernel.h>
35 #include <linux/mm.h>
36 #include <linux/vmalloc.h>
37 #include <linux/slab.h>
38 #include <linux/sched.h>
39 #include <linux/fs.h>
40 #include <linux/stat.h>
41 #include <linux/errno.h>
42 #include <linux/locks.h>
43 #include <linux/string.h>
44 #include <asm/uaccess.h>
45 #include <linux/vmalloc.h>
46 #include <asm/segment.h>
47
48 #include <linux/intermezzo_lib.h>
49 #include <linux/intermezzo_fs.h>
50 #include <linux/intermezzo_psdev.h>
51
52 #include <linux/intermezzo_idl.h>
53
54 /*
55 At present:
56 -- Asynchronous calls:
57 - kml: give a "more" kml indication to userland
58 - kml_truncate: initiate KML truncation
59 - release_permit: kernel is done with permit
60 -- Synchronous
61 - open: fetch file
62 - permit: get a permit
63
64 Errors returned by user level code are positive
65
66 */
67
upc_pack(__u32 opcode,int pathlen,char * path,char * fsetname,int reclen,char * rec,int * size)68 static struct izo_upcall_hdr *upc_pack(__u32 opcode, int pathlen, char *path,
69 char *fsetname, int reclen, char *rec,
70 int *size)
71 {
72 struct izo_upcall_hdr *hdr;
73 char *ptr;
74 ENTRY;
75
76 *size = sizeof(struct izo_upcall_hdr);
77 if ( fsetname ) {
78 *size += round_strlen(fsetname);
79 }
80 if ( path ) {
81 *size += round_strlen(path);
82 }
83 if ( rec ) {
84 *size += size_round(reclen);
85 }
86 PRESTO_ALLOC(hdr, *size);
87 if (!hdr) {
88 CERROR("intermezzo upcall: out of memory (opc %d)\n", opcode);
89 EXIT;
90 return NULL;
91 }
92 memset(hdr, 0, *size);
93
94 ptr = (char *)hdr + sizeof(*hdr);
95
96 /* XXX do we need fsuid ? */
97 hdr->u_len = *size;
98 hdr->u_version = IZO_UPC_VERSION;
99 hdr->u_opc = opcode;
100 hdr->u_pid = current->pid;
101 hdr->u_uid = current->fsuid;
102
103 if (path) {
104 /*XXX Robert: please review what len to pass in for
105 NUL terminated strings */
106 hdr->u_pathlen = strlen(path);
107 LOGL0(path, hdr->u_pathlen, ptr);
108 }
109 if (fsetname) {
110 hdr->u_fsetlen = strlen(fsetname);
111 LOGL0(fsetname, strlen(fsetname), ptr);
112 }
113 if (rec) {
114 hdr->u_reclen = reclen;
115 LOGL(rec, reclen, ptr);
116 }
117
118 EXIT;
119 return hdr;
120 }
121
122 /* the upcalls */
izo_upc_kml(int minor,__u64 offset,__u32 first_recno,__u64 length,__u32 last_recno,char * fsetname)123 int izo_upc_kml(int minor, __u64 offset, __u32 first_recno, __u64 length, __u32 last_recno, char *fsetname)
124 {
125 int size;
126 int error;
127 struct izo_upcall_hdr *hdr;
128
129 ENTRY;
130 if (!presto_lento_up(minor)) {
131 EXIT;
132 return 0;
133 }
134
135 hdr = upc_pack(IZO_UPC_KML, 0, NULL, fsetname, 0, NULL, &size);
136 if (!hdr || IS_ERR(hdr)) {
137 EXIT;
138 return -PTR_ERR(hdr);
139 }
140
141 hdr->u_offset = offset;
142 hdr->u_first_recno = first_recno;
143 hdr->u_length = length;
144 hdr->u_last_recno = last_recno;
145
146 CDEBUG(D_UPCALL, "KML: fileset %s, offset %Lu, length %Lu, "
147 "first %u, last %d; minor %d\n",
148 fsetname, hdr->u_offset, hdr->u_length, hdr->u_first_recno,
149 hdr->u_last_recno, minor);
150
151 error = izo_upc_upcall(minor, &size, hdr, ASYNCHRONOUS);
152
153 EXIT;
154 return -error;
155 }
156
izo_upc_kml_truncate(int minor,__u64 length,__u32 last_recno,char * fsetname)157 int izo_upc_kml_truncate(int minor, __u64 length, __u32 last_recno, char *fsetname)
158 {
159 int size;
160 int error;
161 struct izo_upcall_hdr *hdr;
162
163 ENTRY;
164 if (!presto_lento_up(minor)) {
165 EXIT;
166 return 0;
167 }
168
169 hdr = upc_pack(IZO_UPC_KML_TRUNC, 0, NULL, fsetname, 0, NULL, &size);
170 if (!hdr || IS_ERR(hdr)) {
171 EXIT;
172 return -PTR_ERR(hdr);
173 }
174
175 hdr->u_length = length;
176 hdr->u_last_recno = last_recno;
177
178 CDEBUG(D_UPCALL, "KML TRUNCATE: fileset %s, length %Lu, "
179 "last recno %d, minor %d\n",
180 fsetname, hdr->u_length, hdr->u_last_recno, minor);
181
182 error = izo_upc_upcall(minor, &size, hdr, ASYNCHRONOUS);
183
184 EXIT;
185 return error;
186 }
187
izo_upc_open(int minor,__u32 pathlen,char * path,char * fsetname,struct lento_vfs_context * info)188 int izo_upc_open(int minor, __u32 pathlen, char *path, char *fsetname, struct lento_vfs_context *info)
189 {
190 int size;
191 int error;
192 struct izo_upcall_hdr *hdr;
193 ENTRY;
194
195 if (!presto_lento_up(minor)) {
196 EXIT;
197 return -EIO;
198 }
199
200 hdr = upc_pack(IZO_UPC_OPEN, pathlen, path, fsetname,
201 sizeof(*info), (char*)info, &size);
202 if (!hdr || IS_ERR(hdr)) {
203 EXIT;
204 return -PTR_ERR(hdr);
205 }
206
207 CDEBUG(D_UPCALL, "path %s\n", path);
208
209 error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
210 if (error)
211 CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
212
213 EXIT;
214 return -error;
215 }
216
izo_upc_get_fileid(int minor,__u32 reclen,char * rec,__u32 pathlen,char * path,char * fsetname)217 int izo_upc_get_fileid(int minor, __u32 reclen, char *rec,
218 __u32 pathlen, char *path, char *fsetname)
219 {
220 int size;
221 int error;
222 struct izo_upcall_hdr *hdr;
223 ENTRY;
224
225 if (!presto_lento_up(minor)) {
226 EXIT;
227 return -EIO;
228 }
229
230 hdr = upc_pack(IZO_UPC_GET_FILEID, pathlen, path, fsetname, reclen, rec, &size);
231 if (!hdr || IS_ERR(hdr)) {
232 EXIT;
233 return -PTR_ERR(hdr);
234 }
235
236 CDEBUG(D_UPCALL, "path %s\n", path);
237
238 error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
239 if (error)
240 CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
241
242 EXIT;
243 return -error;
244 }
245
izo_upc_backfetch(int minor,char * path,char * fsetname,struct lento_vfs_context * info)246 int izo_upc_backfetch(int minor, char *path, char *fsetname, struct lento_vfs_context *info)
247 {
248 int size;
249 int error;
250 struct izo_upcall_hdr *hdr;
251 ENTRY;
252
253 if (!presto_lento_up(minor)) {
254 EXIT;
255 return -EIO;
256 }
257
258 hdr = upc_pack(IZO_UPC_BACKFETCH, strlen(path), path, fsetname,
259 sizeof(*info), (char *)info, &size);
260 if (!hdr || IS_ERR(hdr)) {
261 EXIT;
262 return -PTR_ERR(hdr);
263 }
264
265 /* This is currently synchronous, kml_reint_record blocks */
266 error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
267 if (error)
268 CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
269
270 EXIT;
271 return -error;
272 }
273
izo_upc_permit(int minor,struct dentry * dentry,__u32 pathlen,char * path,char * fsetname)274 int izo_upc_permit(int minor, struct dentry *dentry, __u32 pathlen, char *path,
275 char *fsetname)
276 {
277 int size;
278 int error;
279 struct izo_upcall_hdr *hdr;
280
281 ENTRY;
282
283 hdr = upc_pack(IZO_UPC_PERMIT, pathlen, path, fsetname, 0, NULL, &size);
284 if (!hdr || IS_ERR(hdr)) {
285 EXIT;
286 return -PTR_ERR(hdr);
287 }
288
289 CDEBUG(D_UPCALL, "Permit minor %d path %s\n", minor, path);
290
291 error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
292
293 if (error == -EROFS) {
294 int err;
295 CERROR("InterMezzo: ERROR - requested permit for read-only "
296 "fileset.\n Setting \"%s\" read-only!\n", path);
297 err = izo_mark_cache(dentry, 0xFFFFFFFF, CACHE_CLIENT_RO, NULL);
298 if (err)
299 CERROR("InterMezzo ERROR: mark_cache %d\n", err);
300 } else if (error) {
301 CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
302 }
303
304 EXIT;
305 return error;
306 }
307
308 /* This is a ping-pong upcall handled on the server when a client (uuid)
309 * requests the permit for itself. */
izo_upc_revoke_permit(int minor,char * fsetname,__u8 uuid[16])310 int izo_upc_revoke_permit(int minor, char *fsetname, __u8 uuid[16])
311 {
312 int size;
313 int error;
314 struct izo_upcall_hdr *hdr;
315
316 ENTRY;
317
318 hdr = upc_pack(IZO_UPC_REVOKE_PERMIT, 0, NULL, fsetname, 0, NULL, &size);
319 if (!hdr || IS_ERR(hdr)) {
320 EXIT;
321 return -PTR_ERR(hdr);
322 }
323
324 memcpy(hdr->u_uuid, uuid, sizeof(hdr->u_uuid));
325
326 error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
327
328 if (error)
329 CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
330
331 EXIT;
332 return -error;
333 }
334
izo_upc_go_fetch_kml(int minor,char * fsetname,__u8 uuid[16],__u64 kmlsize)335 int izo_upc_go_fetch_kml(int minor, char *fsetname, __u8 uuid[16],
336 __u64 kmlsize)
337 {
338 int size;
339 int error;
340 struct izo_upcall_hdr *hdr;
341 ENTRY;
342
343 if (!presto_lento_up(minor)) {
344 EXIT;
345 return -EIO;
346 }
347
348 hdr = upc_pack(IZO_UPC_GO_FETCH_KML, 0, NULL, fsetname, 0, NULL, &size);
349 if (!hdr || IS_ERR(hdr)) {
350 EXIT;
351 return -PTR_ERR(hdr);
352 }
353
354 hdr->u_offset = kmlsize;
355 memcpy(hdr->u_uuid, uuid, sizeof(hdr->u_uuid));
356
357 error = izo_upc_upcall(minor, &size, hdr, ASYNCHRONOUS);
358 if (error)
359 CERROR("%s: error %d\n", __FUNCTION__, error);
360
361 EXIT;
362 return -error;
363 }
364
izo_upc_connect(int minor,__u64 ip_address,__u64 port,__u8 uuid[16],int client_flag)365 int izo_upc_connect(int minor, __u64 ip_address, __u64 port, __u8 uuid[16],
366 int client_flag)
367 {
368 int size;
369 int error;
370 struct izo_upcall_hdr *hdr;
371 ENTRY;
372
373 if (!presto_lento_up(minor)) {
374 EXIT;
375 return -EIO;
376 }
377
378 hdr = upc_pack(IZO_UPC_CONNECT, 0, NULL, NULL, 0, NULL, &size);
379 if (!hdr || IS_ERR(hdr)) {
380 EXIT;
381 return -PTR_ERR(hdr);
382 }
383
384 hdr->u_offset = ip_address;
385 hdr->u_length = port;
386 memcpy(hdr->u_uuid, uuid, sizeof(hdr->u_uuid));
387 hdr->u_first_recno = client_flag;
388
389 error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
390 if (error) {
391 CERROR("%s: error %d\n", __FUNCTION__, error);
392 }
393
394 EXIT;
395 return -error;
396 }
397
izo_upc_set_kmlsize(int minor,char * fsetname,__u8 uuid[16],__u64 kmlsize)398 int izo_upc_set_kmlsize(int minor, char *fsetname, __u8 uuid[16], __u64 kmlsize)
399 {
400 int size;
401 int error;
402 struct izo_upcall_hdr *hdr;
403 ENTRY;
404
405 if (!presto_lento_up(minor)) {
406 EXIT;
407 return -EIO;
408 }
409
410 hdr = upc_pack(IZO_UPC_SET_KMLSIZE, 0, NULL, fsetname, 0, NULL, &size);
411 if (!hdr || IS_ERR(hdr)) {
412 EXIT;
413 return -PTR_ERR(hdr);
414 }
415
416 memcpy(hdr->u_uuid, uuid, sizeof(hdr->u_uuid));
417 hdr->u_length = kmlsize;
418
419 error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
420 if (error)
421 CERROR("%s: error %d\n", __FUNCTION__, error);
422
423 EXIT;
424 return -error;
425 }
426
izo_upc_repstatus(int minor,char * fsetname,struct izo_rcvd_rec * lr_server)427 int izo_upc_repstatus(int minor, char * fsetname, struct izo_rcvd_rec *lr_server)
428 {
429 int size;
430 int error;
431 struct izo_upcall_hdr *hdr;
432 ENTRY;
433
434 if (!presto_lento_up(minor)) {
435 EXIT;
436 return -EIO;
437 }
438
439 hdr = upc_pack(IZO_UPC_REPSTATUS, 0, NULL, fsetname,
440 sizeof(*lr_server), (char*)lr_server,
441 &size);
442 if (!hdr || IS_ERR(hdr)) {
443 EXIT;
444 return -PTR_ERR(hdr);
445 }
446
447 error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
448 if (error)
449 CERROR("%s: error %d\n", __FUNCTION__, error);
450
451 EXIT;
452 return -error;
453 }
454
455
456 #if 0
457 int izo_upc_client_make_branch(int minor, char *fsetname, char *tagname,
458 char *branchname)
459 {
460 int size, error;
461 struct izo_upcall_hdr *hdr;
462 int pathlen;
463 char *path;
464 ENTRY;
465
466 hdr = upc_pack(IZO_UPC_CLIENT_MAKE_BRANCH, strlen(tagname), tagname,
467 fsetname, strlen(branchname) + 1, branchname, &size);
468 if (!hdr || IS_ERR(hdr)) {
469 error = -PTR_ERR(hdr);
470 goto error;
471 }
472
473 error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
474 if (error)
475 CERROR("InterMezzo: error %d\n", error);
476
477 error:
478 PRESTO_FREE(path, pathlen);
479 EXIT;
480 return error;
481 }
482 #endif
483
izo_upc_server_make_branch(int minor,char * fsetname)484 int izo_upc_server_make_branch(int minor, char *fsetname)
485 {
486 int size, error;
487 struct izo_upcall_hdr *hdr;
488 ENTRY;
489
490 hdr = upc_pack(IZO_UPC_SERVER_MAKE_BRANCH, 0, NULL, fsetname, 0, NULL, &size);
491 if (!hdr || IS_ERR(hdr)) {
492 error = -PTR_ERR(hdr);
493 goto error;
494 }
495
496 error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
497 if (error)
498 CERROR("InterMezzo: error %d\n", error);
499
500 error:
501 EXIT;
502 return -error;
503 }
504
izo_upc_branch_undo(int minor,char * fsetname,char * branchname)505 int izo_upc_branch_undo(int minor, char *fsetname, char *branchname)
506 {
507 int size;
508 int error;
509 struct izo_upcall_hdr *hdr;
510 ENTRY;
511
512 if (!presto_lento_up(minor)) {
513 EXIT;
514 return -EIO;
515 }
516
517 hdr = upc_pack(IZO_UPC_BRANCH_UNDO, strlen(branchname), branchname,
518 fsetname, 0, NULL, &size);
519 if (!hdr || IS_ERR(hdr)) {
520 EXIT;
521 return -PTR_ERR(hdr);
522 }
523
524 error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
525 if (error)
526 CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
527
528 EXIT;
529 return -error;
530 }
531
izo_upc_branch_redo(int minor,char * fsetname,char * branchname)532 int izo_upc_branch_redo(int minor, char *fsetname, char *branchname)
533 {
534 int size;
535 int error;
536 struct izo_upcall_hdr *hdr;
537 ENTRY;
538
539 if (!presto_lento_up(minor)) {
540 EXIT;
541 return -EIO;
542 }
543
544 hdr = upc_pack(IZO_UPC_BRANCH_REDO, strlen(branchname) + 1, branchname,
545 fsetname, 0, NULL, &size);
546 if (!hdr || IS_ERR(hdr)) {
547 EXIT;
548 return -PTR_ERR(hdr);
549 }
550
551 error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
552 if (error)
553 CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
554
555 EXIT;
556 return -error;
557 }
558