import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / fs / intermezzo / upcall.c
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
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 */
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
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
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
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
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
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. */
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
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
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
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
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
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
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
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 }