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