coda: block signals during upcall processing
[deliverable/linux.git] / fs / coda / upcall.c
CommitLineData
1da177e4
LT
1/*
2 * Mostly platform independent upcall operations to Venus:
3 * -- upcalls
4 * -- upcall routines
5 *
6 * Linux 2.0 version
7 * Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk>,
8 * Michael Callahan <callahan@maths.ox.ac.uk>
9 *
10 * Redone for Linux 2.1
11 * Copyright (C) 1997 Carnegie Mellon University
12 *
13 * Carnegie Mellon University encourages users of this code to contribute
14 * improvements to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
15 */
16
17#include <asm/system.h>
18#include <linux/signal.h>
e8edc6e0 19#include <linux/sched.h>
1da177e4
LT
20#include <linux/types.h>
21#include <linux/kernel.h>
22#include <linux/mm.h>
23#include <linux/time.h>
24#include <linux/fs.h>
25#include <linux/file.h>
26#include <linux/stat.h>
27#include <linux/errno.h>
28#include <linux/string.h>
29#include <asm/uaccess.h>
30#include <linux/vmalloc.h>
31#include <linux/vfs.h>
32
33#include <linux/coda.h>
34#include <linux/coda_linux.h>
35#include <linux/coda_psdev.h>
36#include <linux/coda_fs_i.h>
37#include <linux/coda_cache.h>
38#include <linux/coda_proc.h>
39
40#define upc_alloc() kmalloc(sizeof(struct upc_req), GFP_KERNEL)
41#define upc_free(r) kfree(r)
42
43static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize,
44 union inputArgs *buffer);
45
46static void *alloc_upcall(int opcode, int size)
47{
48 union inputArgs *inp;
49
50 CODA_ALLOC(inp, union inputArgs *, size);
51 if (!inp)
52 return ERR_PTR(-ENOMEM);
53
54 inp->ih.opcode = opcode;
55 inp->ih.pid = current->pid;
56 inp->ih.pgid = process_group(current);
57#ifdef CONFIG_CODA_FS_OLD_API
58 memset(&inp->ih.cred, 0, sizeof(struct coda_cred));
59 inp->ih.cred.cr_fsuid = current->fsuid;
60#else
61 inp->ih.uid = current->fsuid;
62#endif
63 return (void*)inp;
64}
65
66#define UPARG(op)\
67do {\
68 inp = (union inputArgs *)alloc_upcall(op, insize); \
69 if (IS_ERR(inp)) { return PTR_ERR(inp); }\
70 outp = (union outputArgs *)(inp); \
71 outsize = insize; \
72} while (0)
73
74#define INSIZE(tag) sizeof(struct coda_ ## tag ## _in)
75#define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out)
76#define SIZE(tag) max_t(unsigned int, INSIZE(tag), OUTSIZE(tag))
77
78
79/* the upcalls */
80int venus_rootfid(struct super_block *sb, struct CodaFid *fidp)
81{
82 union inputArgs *inp;
83 union outputArgs *outp;
84 int insize, outsize, error;
85
86 insize = SIZE(root);
87 UPARG(CODA_ROOT);
88
89 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
90
91 if (error) {
92 printk("coda_get_rootfid: error %d\n", error);
93 } else {
94 *fidp = outp->coda_root.VFid;
95 }
96
97 CODA_FREE(inp, insize);
98 return error;
99}
100
101int venus_getattr(struct super_block *sb, struct CodaFid *fid,
102 struct coda_vattr *attr)
103{
104 union inputArgs *inp;
105 union outputArgs *outp;
106 int insize, outsize, error;
107
108 insize = SIZE(getattr);
109 UPARG(CODA_GETATTR);
110 inp->coda_getattr.VFid = *fid;
111
112 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
113
114 *attr = outp->coda_getattr.attr;
115
116 CODA_FREE(inp, insize);
117 return error;
118}
119
120int venus_setattr(struct super_block *sb, struct CodaFid *fid,
121 struct coda_vattr *vattr)
122{
123 union inputArgs *inp;
124 union outputArgs *outp;
125 int insize, outsize, error;
126
127 insize = SIZE(setattr);
128 UPARG(CODA_SETATTR);
129
130 inp->coda_setattr.VFid = *fid;
131 inp->coda_setattr.attr = *vattr;
132
133 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
134
135 CODA_FREE(inp, insize);
136 return error;
137}
138
139int venus_lookup(struct super_block *sb, struct CodaFid *fid,
140 const char *name, int length, int * type,
141 struct CodaFid *resfid)
142{
143 union inputArgs *inp;
144 union outputArgs *outp;
145 int insize, outsize, error;
146 int offset;
147
148 offset = INSIZE(lookup);
149 insize = max_t(unsigned int, offset + length +1, OUTSIZE(lookup));
150 UPARG(CODA_LOOKUP);
151
152 inp->coda_lookup.VFid = *fid;
153 inp->coda_lookup.name = offset;
154 inp->coda_lookup.flags = CLU_CASE_SENSITIVE;
155 /* send Venus a null terminated string */
156 memcpy((char *)(inp) + offset, name, length);
157 *((char *)inp + offset + length) = '\0';
158
159 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
160
161 *resfid = outp->coda_lookup.VFid;
162 *type = outp->coda_lookup.vtype;
163
164 CODA_FREE(inp, insize);
165 return error;
166}
167
168int venus_store(struct super_block *sb, struct CodaFid *fid, int flags,
169 vuid_t uid)
170{
171 union inputArgs *inp;
172 union outputArgs *outp;
173 int insize, outsize, error;
174#ifdef CONFIG_CODA_FS_OLD_API
175 struct coda_cred cred = { 0, };
176 cred.cr_fsuid = uid;
177#endif
178
179 insize = SIZE(store);
180 UPARG(CODA_STORE);
181
182#ifdef CONFIG_CODA_FS_OLD_API
183 memcpy(&(inp->ih.cred), &cred, sizeof(cred));
184#else
185 inp->ih.uid = uid;
186#endif
187
188 inp->coda_store.VFid = *fid;
189 inp->coda_store.flags = flags;
190
191 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
192
193 CODA_FREE(inp, insize);
194 return error;
195}
196
197int venus_release(struct super_block *sb, struct CodaFid *fid, int flags)
198{
199 union inputArgs *inp;
200 union outputArgs *outp;
201 int insize, outsize, error;
202
203 insize = SIZE(release);
204 UPARG(CODA_RELEASE);
205
206 inp->coda_release.VFid = *fid;
207 inp->coda_release.flags = flags;
208
209 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
210
211 CODA_FREE(inp, insize);
212 return error;
213}
214
215int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
216 vuid_t uid)
217{
218 union inputArgs *inp;
219 union outputArgs *outp;
220 int insize, outsize, error;
221#ifdef CONFIG_CODA_FS_OLD_API
222 struct coda_cred cred = { 0, };
223 cred.cr_fsuid = uid;
224#endif
225
226 insize = SIZE(release);
227 UPARG(CODA_CLOSE);
228
229#ifdef CONFIG_CODA_FS_OLD_API
230 memcpy(&(inp->ih.cred), &cred, sizeof(cred));
231#else
232 inp->ih.uid = uid;
233#endif
234
235 inp->coda_close.VFid = *fid;
236 inp->coda_close.flags = flags;
237
238 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
239
240 CODA_FREE(inp, insize);
241 return error;
242}
243
244int venus_open(struct super_block *sb, struct CodaFid *fid,
245 int flags, struct file **fh)
246{
247 union inputArgs *inp;
248 union outputArgs *outp;
249 int insize, outsize, error;
250
251 insize = SIZE(open_by_fd);
252 UPARG(CODA_OPEN_BY_FD);
253
38c2e437
JH
254 inp->coda_open_by_fd.VFid = *fid;
255 inp->coda_open_by_fd.flags = flags;
1da177e4 256
38c2e437
JH
257 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
258 if (!error)
259 *fh = outp->coda_open_by_fd.fh;
1da177e4
LT
260
261 CODA_FREE(inp, insize);
262 return error;
263}
264
265int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid,
266 const char *name, int length,
267 struct CodaFid *newfid, struct coda_vattr *attrs)
268{
269 union inputArgs *inp;
270 union outputArgs *outp;
271 int insize, outsize, error;
272 int offset;
273
274 offset = INSIZE(mkdir);
275 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(mkdir));
276 UPARG(CODA_MKDIR);
277
278 inp->coda_mkdir.VFid = *dirfid;
279 inp->coda_mkdir.attr = *attrs;
280 inp->coda_mkdir.name = offset;
281 /* Venus must get null terminated string */
282 memcpy((char *)(inp) + offset, name, length);
283 *((char *)inp + offset + length) = '\0';
284
285 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
286
287 *attrs = outp->coda_mkdir.attr;
288 *newfid = outp->coda_mkdir.VFid;
289
290 CODA_FREE(inp, insize);
291 return error;
292}
293
294
295int venus_rename(struct super_block *sb, struct CodaFid *old_fid,
296 struct CodaFid *new_fid, size_t old_length,
297 size_t new_length, const char *old_name,
298 const char *new_name)
299{
300 union inputArgs *inp;
301 union outputArgs *outp;
302 int insize, outsize, error;
303 int offset, s;
304
305 offset = INSIZE(rename);
306 insize = max_t(unsigned int, offset + new_length + old_length + 8,
307 OUTSIZE(rename));
308 UPARG(CODA_RENAME);
309
310 inp->coda_rename.sourceFid = *old_fid;
311 inp->coda_rename.destFid = *new_fid;
312 inp->coda_rename.srcname = offset;
313
314 /* Venus must receive an null terminated string */
315 s = ( old_length & ~0x3) +4; /* round up to word boundary */
316 memcpy((char *)(inp) + offset, old_name, old_length);
317 *((char *)inp + offset + old_length) = '\0';
318
319 /* another null terminated string for Venus */
320 offset += s;
321 inp->coda_rename.destname = offset;
322 s = ( new_length & ~0x3) +4; /* round up to word boundary */
323 memcpy((char *)(inp) + offset, new_name, new_length);
324 *((char *)inp + offset + new_length) = '\0';
325
326 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
327
328 CODA_FREE(inp, insize);
329 return error;
330}
331
332int venus_create(struct super_block *sb, struct CodaFid *dirfid,
333 const char *name, int length, int excl, int mode,
334 struct CodaFid *newfid, struct coda_vattr *attrs)
335{
336 union inputArgs *inp;
337 union outputArgs *outp;
338 int insize, outsize, error;
339 int offset;
340
341 offset = INSIZE(create);
342 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(create));
343 UPARG(CODA_CREATE);
344
345 inp->coda_create.VFid = *dirfid;
346 inp->coda_create.attr.va_mode = mode;
347 inp->coda_create.excl = excl;
348 inp->coda_create.mode = mode;
349 inp->coda_create.name = offset;
350
351 /* Venus must get null terminated string */
352 memcpy((char *)(inp) + offset, name, length);
353 *((char *)inp + offset + length) = '\0';
354
355 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
356
357 *attrs = outp->coda_create.attr;
358 *newfid = outp->coda_create.VFid;
359
360 CODA_FREE(inp, insize);
361 return error;
362}
363
364int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid,
365 const char *name, int length)
366{
367 union inputArgs *inp;
368 union outputArgs *outp;
369 int insize, outsize, error;
370 int offset;
371
372 offset = INSIZE(rmdir);
373 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(rmdir));
374 UPARG(CODA_RMDIR);
375
376 inp->coda_rmdir.VFid = *dirfid;
377 inp->coda_rmdir.name = offset;
378 memcpy((char *)(inp) + offset, name, length);
379 *((char *)inp + offset + length) = '\0';
380
381 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
382
383 CODA_FREE(inp, insize);
384 return error;
385}
386
387int venus_remove(struct super_block *sb, struct CodaFid *dirfid,
388 const char *name, int length)
389{
390 union inputArgs *inp;
391 union outputArgs *outp;
392 int error=0, insize, outsize, offset;
393
394 offset = INSIZE(remove);
395 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(remove));
396 UPARG(CODA_REMOVE);
397
398 inp->coda_remove.VFid = *dirfid;
399 inp->coda_remove.name = offset;
400 memcpy((char *)(inp) + offset, name, length);
401 *((char *)inp + offset + length) = '\0';
402
403 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
404
405 CODA_FREE(inp, insize);
406 return error;
407}
408
409int venus_readlink(struct super_block *sb, struct CodaFid *fid,
410 char *buffer, int *length)
411{
412 union inputArgs *inp;
413 union outputArgs *outp;
414 int insize, outsize, error;
415 int retlen;
416 char *result;
417
418 insize = max_t(unsigned int,
419 INSIZE(readlink), OUTSIZE(readlink)+ *length + 1);
420 UPARG(CODA_READLINK);
421
422 inp->coda_readlink.VFid = *fid;
423
424 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
425
426 if (! error) {
427 retlen = outp->coda_readlink.count;
428 if ( retlen > *length )
429 retlen = *length;
430 *length = retlen;
431 result = (char *)outp + (long)outp->coda_readlink.data;
432 memcpy(buffer, result, retlen);
433 *(buffer + retlen) = '\0';
434 }
435
436 CODA_FREE(inp, insize);
437 return error;
438}
439
440
441
442int venus_link(struct super_block *sb, struct CodaFid *fid,
443 struct CodaFid *dirfid, const char *name, int len )
444{
445 union inputArgs *inp;
446 union outputArgs *outp;
447 int insize, outsize, error;
448 int offset;
449
450 offset = INSIZE(link);
451 insize = max_t(unsigned int, offset + len + 1, OUTSIZE(link));
452 UPARG(CODA_LINK);
453
454 inp->coda_link.sourceFid = *fid;
455 inp->coda_link.destFid = *dirfid;
456 inp->coda_link.tname = offset;
457
458 /* make sure strings are null terminated */
459 memcpy((char *)(inp) + offset, name, len);
460 *((char *)inp + offset + len) = '\0';
461
462 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
463
464 CODA_FREE(inp, insize);
465 return error;
466}
467
468int venus_symlink(struct super_block *sb, struct CodaFid *fid,
469 const char *name, int len,
470 const char *symname, int symlen)
471{
472 union inputArgs *inp;
473 union outputArgs *outp;
474 int insize, outsize, error;
475 int offset, s;
476
477 offset = INSIZE(symlink);
478 insize = max_t(unsigned int, offset + len + symlen + 8, OUTSIZE(symlink));
479 UPARG(CODA_SYMLINK);
480
481 /* inp->coda_symlink.attr = *tva; XXXXXX */
482 inp->coda_symlink.VFid = *fid;
483
484 /* Round up to word boundary and null terminate */
485 inp->coda_symlink.srcname = offset;
486 s = ( symlen & ~0x3 ) + 4;
487 memcpy((char *)(inp) + offset, symname, symlen);
488 *((char *)inp + offset + symlen) = '\0';
489
490 /* Round up to word boundary and null terminate */
491 offset += s;
492 inp->coda_symlink.tname = offset;
493 s = (len & ~0x3) + 4;
494 memcpy((char *)(inp) + offset, name, len);
495 *((char *)inp + offset + len) = '\0';
496
497 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
498
499 CODA_FREE(inp, insize);
500 return error;
501}
502
503int venus_fsync(struct super_block *sb, struct CodaFid *fid)
504{
505 union inputArgs *inp;
506 union outputArgs *outp;
507 int insize, outsize, error;
508
509 insize=SIZE(fsync);
510 UPARG(CODA_FSYNC);
511
512 inp->coda_fsync.VFid = *fid;
513 error = coda_upcall(coda_sbp(sb), sizeof(union inputArgs),
514 &outsize, inp);
515
516 CODA_FREE(inp, insize);
517 return error;
518}
519
520int venus_access(struct super_block *sb, struct CodaFid *fid, int mask)
521{
522 union inputArgs *inp;
523 union outputArgs *outp;
524 int insize, outsize, error;
525
526 insize = SIZE(access);
527 UPARG(CODA_ACCESS);
528
529 inp->coda_access.VFid = *fid;
530 inp->coda_access.flags = mask;
531
532 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
533
534 CODA_FREE(inp, insize);
535 return error;
536}
537
538
539int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
540 unsigned int cmd, struct PioctlData *data)
541{
542 union inputArgs *inp;
543 union outputArgs *outp;
544 int insize, outsize, error;
545 int iocsize;
546
547 insize = VC_MAXMSGSIZE;
548 UPARG(CODA_IOCTL);
549
550 /* build packet for Venus */
551 if (data->vi.in_size > VC_MAXDATASIZE) {
552 error = -EINVAL;
553 goto exit;
554 }
555
556 if (data->vi.out_size > VC_MAXDATASIZE) {
557 error = -EINVAL;
558 goto exit;
559 }
560
561 inp->coda_ioctl.VFid = *fid;
562
563 /* the cmd field was mutated by increasing its size field to
564 * reflect the path and follow args. We need to subtract that
565 * out before sending the command to Venus. */
566 inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));
567 iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
568 inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) << 16;
569
570 /* in->coda_ioctl.rwflag = flag; */
571 inp->coda_ioctl.len = data->vi.in_size;
572 inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
573
574 /* get the data out of user space */
575 if ( copy_from_user((char*)inp + (long)inp->coda_ioctl.data,
576 data->vi.in, data->vi.in_size) ) {
577 error = -EINVAL;
578 goto exit;
579 }
580
581 error = coda_upcall(coda_sbp(sb), SIZE(ioctl) + data->vi.in_size,
582 &outsize, inp);
583
584 if (error) {
585 printk("coda_pioctl: Venus returns: %d for %s\n",
586 error, coda_f2s(fid));
587 goto exit;
588 }
589
590 if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) {
591 error = -EINVAL;
592 goto exit;
593 }
594
595 /* Copy out the OUT buffer. */
596 if (outp->coda_ioctl.len > data->vi.out_size) {
597 error = -EINVAL;
598 goto exit;
599 }
600
601 /* Copy out the OUT buffer. */
602 if (copy_to_user(data->vi.out,
603 (char *)outp + (long)outp->coda_ioctl.data,
604 outp->coda_ioctl.len)) {
605 error = -EFAULT;
606 goto exit;
607 }
608
609 exit:
610 CODA_FREE(inp, insize);
611 return error;
612}
613
726c3342 614int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
1da177e4
LT
615{
616 union inputArgs *inp;
617 union outputArgs *outp;
618 int insize, outsize, error;
619
620 insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
621 UPARG(CODA_STATFS);
622
726c3342 623 error = coda_upcall(coda_sbp(dentry->d_sb), insize, &outsize, inp);
1da177e4
LT
624
625 if (!error) {
626 sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
627 sfs->f_bfree = outp->coda_statfs.stat.f_bfree;
628 sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
629 sfs->f_files = outp->coda_statfs.stat.f_files;
630 sfs->f_ffree = outp->coda_statfs.stat.f_ffree;
631 } else {
632 printk("coda_statfs: Venus returns: %d\n", error);
633 }
634
635 CODA_FREE(inp, insize);
636 return error;
637}
638
639/*
640 * coda_upcall and coda_downcall routines.
1da177e4 641 */
d9664c95
JH
642static void block_signals(sigset_t *old)
643{
644 spin_lock_irq(&current->sighand->siglock);
645 *old = current->blocked;
646
647 sigfillset(&current->blocked);
648 sigdelset(&current->blocked, SIGKILL);
649 sigdelset(&current->blocked, SIGSTOP);
650 sigdelset(&current->blocked, SIGINT);
651
652 recalc_sigpending();
653 spin_unlock_irq(&current->sighand->siglock);
654}
655
656static void unblock_signals(sigset_t *old)
657{
658 spin_lock_irq(&current->sighand->siglock);
659 current->blocked = *old;
660 recalc_sigpending();
661 spin_unlock_irq(&current->sighand->siglock);
662}
663
664/* Don't allow signals to interrupt the following upcalls before venus
665 * has seen them,
666 * - CODA_CLOSE or CODA_RELEASE upcall (to avoid reference count problems)
667 * - CODA_STORE (to avoid data loss)
668 */
669#define CODA_INTERRUPTIBLE(r) (!coda_hard && \
670 (((r)->uc_opcode != CODA_CLOSE && \
671 (r)->uc_opcode != CODA_STORE && \
672 (r)->uc_opcode != CODA_RELEASE) || \
673 (r)->uc_flags & REQ_READ))
1da177e4 674
d9664c95 675static inline void coda_waitfor_upcall(struct upc_req *req)
1da177e4
LT
676{
677 DECLARE_WAITQUEUE(wait, current);
d9664c95
JH
678 unsigned long timeout = jiffies + coda_timeout * HZ;
679 sigset_t old;
680 int blocked;
1da177e4 681
d9664c95
JH
682 block_signals(&old);
683 blocked = 1;
1da177e4 684
d9664c95 685 add_wait_queue(&req->uc_sleep, &wait);
1da177e4 686 for (;;) {
d9664c95 687 if (CODA_INTERRUPTIBLE(req))
1da177e4
LT
688 set_current_state(TASK_INTERRUPTIBLE);
689 else
690 set_current_state(TASK_UNINTERRUPTIBLE);
691
1da177e4 692 /* got a reply */
d9664c95 693 if (req->uc_flags & (REQ_WRITE | REQ_ABORT))
1da177e4
LT
694 break;
695
d9664c95
JH
696 if (blocked && time_after(jiffies, timeout) &&
697 CODA_INTERRUPTIBLE(req))
698 {
699 unblock_signals(&old);
700 blocked = 0;
1da177e4 701 }
d9664c95
JH
702
703 if (signal_pending(current)) {
704 list_del(&req->uc_chain);
705 break;
706 }
707
708 if (blocked)
709 schedule_timeout(HZ);
710 else
711 schedule();
1da177e4 712 }
d9664c95
JH
713 if (blocked)
714 unblock_signals(&old);
1da177e4 715
d9664c95
JH
716 remove_wait_queue(&req->uc_sleep, &wait);
717 set_current_state(TASK_RUNNING);
1da177e4
LT
718}
719
720
721/*
722 * coda_upcall will return an error in the case of
723 * failed communication with Venus _or_ will peek at Venus
724 * reply and return Venus' error.
725 *
726 * As venus has 2 types of errors, normal errors (positive) and internal
727 * errors (negative), normal errors are negated, while internal errors
728 * are all mapped to -EINTR, while showing a nice warning message. (jh)
729 *
730 */
fe71b5f3
JH
731static int coda_upcall(struct coda_sb_info *sbi,
732 int inSize, int *outSize,
733 union inputArgs *buffer)
1da177e4
LT
734{
735 struct venus_comm *vcommp;
736 union outputArgs *out;
fe71b5f3
JH
737 union inputArgs *sig_inputArgs;
738 struct upc_req *req, *sig_req;
1da177e4
LT
739 int error = 0;
740
741 vcommp = sbi->sbi_vcomm;
fe71b5f3
JH
742 if (!vcommp->vc_inuse) {
743 printk(KERN_NOTICE "coda: Venus dead, not sending upcall\n");
744 return -ENXIO;
1da177e4
LT
745 }
746
747 /* Format the request message. */
748 req = upc_alloc();
fe71b5f3 749 if (!req)
1da177e4 750 return -ENOMEM;
fe71b5f3 751
1da177e4
LT
752 req->uc_data = (void *)buffer;
753 req->uc_flags = 0;
754 req->uc_inSize = inSize;
755 req->uc_outSize = *outSize ? *outSize : inSize;
756 req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
757 req->uc_unique = ++vcommp->vc_seq;
758 init_waitqueue_head(&req->uc_sleep);
fe71b5f3 759
1da177e4
LT
760 /* Fill in the common input args. */
761 ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
762
763 /* Append msg to pending queue and poke Venus. */
fe71b5f3
JH
764 list_add_tail(&req->uc_chain, &vcommp->vc_pending);
765
1da177e4
LT
766 wake_up_interruptible(&vcommp->vc_waitq);
767 /* We can be interrupted while we wait for Venus to process
768 * our request. If the interrupt occurs before Venus has read
769 * the request, we dequeue and return. If it occurs after the
770 * read but before the reply, we dequeue, send a signal
771 * message, and return. If it occurs after the reply we ignore
772 * it. In no case do we want to restart the syscall. If it
773 * was interrupted by a venus shutdown (psdev_close), return
774 * ENODEV. */
775
776 /* Go to sleep. Wake up on signals only after the timeout. */
87065519 777 coda_waitfor_upcall(req);
1da177e4 778
fe71b5f3
JH
779 /* Op went through, interrupt or not... */
780 if (req->uc_flags & REQ_WRITE) {
1da177e4
LT
781 out = (union outputArgs *)req->uc_data;
782 /* here we map positive Venus errors to kernel errors */
783 error = -out->oh.result;
784 *outSize = req->uc_outSize;
785 goto exit;
fe71b5f3
JH
786 }
787
788 error = -EINTR;
789 if ((req->uc_flags & REQ_ABORT) || !signal_pending(current)) {
790 printk(KERN_WARNING "coda: Unexpected interruption.\n");
1da177e4 791 goto exit;
1da177e4
LT
792 }
793
fe71b5f3
JH
794 /* Interrupted before venus read it. */
795 if (!(req->uc_flags & REQ_READ))
796 goto exit;
797
798 /* Venus saw the upcall, make sure we can send interrupt signal */
799 if (!vcommp->vc_inuse) {
800 printk(KERN_INFO "coda: Venus dead, not sending signal.\n");
801 goto exit;
802 }
803
804 error = -ENOMEM;
805 sig_req = upc_alloc();
806 if (!sig_req) goto exit;
807
808 CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
809 if (!sig_req->uc_data) {
810 upc_free(sig_req);
811 goto exit;
812 }
813
814 error = -EINTR;
815 sig_inputArgs = (union inputArgs *)sig_req->uc_data;
816 sig_inputArgs->ih.opcode = CODA_SIGNAL;
817 sig_inputArgs->ih.unique = req->uc_unique;
818
819 sig_req->uc_flags = REQ_ASYNC;
820 sig_req->uc_opcode = sig_inputArgs->ih.opcode;
821 sig_req->uc_unique = sig_inputArgs->ih.unique;
822 sig_req->uc_inSize = sizeof(struct coda_in_hdr);
823 sig_req->uc_outSize = sizeof(struct coda_in_hdr);
824
825 /* insert at head of queue! */
826 list_add(&(sig_req->uc_chain), &vcommp->vc_pending);
827 wake_up_interruptible(&vcommp->vc_waitq);
828
829exit:
1da177e4
LT
830 upc_free(req);
831 return error;
832}
833
834/*
835 The statements below are part of the Coda opportunistic
836 programming -- taken from the Mach/BSD kernel code for Coda.
837 You don't get correct semantics by stating what needs to be
838 done without guaranteeing the invariants needed for it to happen.
839 When will be have time to find out what exactly is going on? (pjb)
840*/
841
842
843/*
844 * There are 7 cases where cache invalidations occur. The semantics
845 * of each is listed here:
846 *
847 * CODA_FLUSH -- flush all entries from the name cache and the cnode cache.
848 * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
849 * This call is a result of token expiration.
850 *
851 * The next arise as the result of callbacks on a file or directory.
852 * CODA_ZAPFILE -- flush the cached attributes for a file.
853
854 * CODA_ZAPDIR -- flush the attributes for the dir and
855 * force a new lookup for all the children
856 of this dir.
857
858 *
859 * The next is a result of Venus detecting an inconsistent file.
860 * CODA_PURGEFID -- flush the attribute for the file
861 * purge it and its children from the dcache
862 *
863 * The last allows Venus to replace local fids with global ones
864 * during reintegration.
865 *
866 * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
867
868int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
869{
870 /* Handle invalidation requests. */
871 if ( !sb || !sb->s_root || !sb->s_root->d_inode)
872 return 0;
873
874 switch (opcode) {
875
876 case CODA_FLUSH : {
877 coda_cache_clear_all(sb);
878 shrink_dcache_sb(sb);
879 coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
880 return(0);
881 }
882
883 case CODA_PURGEUSER : {
884 coda_cache_clear_all(sb);
885 return(0);
886 }
887
888 case CODA_ZAPDIR : {
889 struct inode *inode;
890 struct CodaFid *fid = &out->coda_zapdir.CodaFid;
891
892 inode = coda_fid_to_inode(fid, sb);
893 if (inode) {
894 coda_flag_inode_children(inode, C_PURGE);
895 coda_flag_inode(inode, C_VATTR);
896 iput(inode);
897 }
898
899 return(0);
900 }
901
902 case CODA_ZAPFILE : {
903 struct inode *inode;
904 struct CodaFid *fid = &out->coda_zapfile.CodaFid;
905 inode = coda_fid_to_inode(fid, sb);
906 if ( inode ) {
907 coda_flag_inode(inode, C_VATTR);
908 iput(inode);
909 }
910 return 0;
911 }
912
913 case CODA_PURGEFID : {
914 struct inode *inode;
915 struct CodaFid *fid = &out->coda_purgefid.CodaFid;
916 inode = coda_fid_to_inode(fid, sb);
917 if ( inode ) {
918 coda_flag_inode_children(inode, C_PURGE);
919
920 /* catch the dentries later if some are still busy */
921 coda_flag_inode(inode, C_PURGE);
922 d_prune_aliases(inode);
923
924 iput(inode);
925 }
926 return 0;
927 }
928
929 case CODA_REPLACE : {
930 struct inode *inode;
931 struct CodaFid *oldfid = &out->coda_replace.OldFid;
932 struct CodaFid *newfid = &out->coda_replace.NewFid;
933 inode = coda_fid_to_inode(oldfid, sb);
934 if ( inode ) {
935 coda_replace_fid(inode, oldfid, newfid);
936 iput(inode);
937 }
938 return 0;
939 }
940 }
941 return 0;
942}
943
This page took 0.268523 seconds and 5 git commands to generate.