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