Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/fs/coda/upcall.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Mostly platform independent upcall operations to Venus:
4
* -- upcalls
5
* -- upcall routines
6
*
7
* Linux 2.0 version
8
* Copyright (C) 1996 Peter J. Braam <[email protected]>,
9
* Michael Callahan <[email protected]>
10
*
11
* Redone for Linux 2.1
12
* Copyright (C) 1997 Carnegie Mellon University
13
*
14
* Carnegie Mellon University encourages users of this code to contribute
15
* improvements to the Coda project. Contact Peter Braam <[email protected]>.
16
*/
17
18
#include <linux/signal.h>
19
#include <linux/sched/signal.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 <linux/uaccess.h>
32
#include <linux/vmalloc.h>
33
#include <linux/vfs.h>
34
35
#include <linux/coda.h>
36
#include "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
inp = kvzalloc(size, GFP_KERNEL);
50
if (!inp)
51
return ERR_PTR(-ENOMEM);
52
53
inp->ih.opcode = opcode;
54
inp->ih.pid = task_pid_nr_ns(current, &init_pid_ns);
55
inp->ih.pgid = task_pgrp_nr_ns(current, &init_pid_ns);
56
inp->ih.uid = from_kuid(&init_user_ns, 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
kvfree(inp);
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
kvfree(inp);
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
kvfree(inp);
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
kvfree(inp);
157
return error;
158
}
159
160
int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
161
kuid_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 = from_kuid(&init_user_ns, 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
kvfree(inp);
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
kvfree(inp);
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
kvfree(inp);
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
kvfree(inp);
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
kvfree(inp);
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
kvfree(inp);
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
kvfree(inp);
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);
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 - 1;
367
*length = retlen;
368
result = (char *)outp + (long)outp->coda_readlink.data;
369
memcpy(buffer, result, retlen);
370
*(buffer + retlen) = '\0';
371
}
372
373
kvfree(inp);
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
kvfree(inp);
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
kvfree(inp);
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), insize, &outsize, inp);
451
452
kvfree(inp);
453
return error;
454
}
455
456
int venus_access(struct super_block *sb, struct CodaFid *fid, int mask)
457
{
458
union inputArgs *inp;
459
union outputArgs *outp;
460
int insize, outsize, error;
461
462
insize = SIZE(access);
463
UPARG(CODA_ACCESS);
464
465
inp->coda_access.VFid = *fid;
466
inp->coda_access.flags = mask;
467
468
error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
469
470
kvfree(inp);
471
return error;
472
}
473
474
475
int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
476
unsigned int cmd, struct PioctlData *data)
477
{
478
union inputArgs *inp;
479
union outputArgs *outp;
480
int insize, outsize, error;
481
int iocsize;
482
483
insize = VC_MAXMSGSIZE;
484
UPARG(CODA_IOCTL);
485
486
/* build packet for Venus */
487
if (data->vi.in_size > VC_MAXDATASIZE) {
488
error = -EINVAL;
489
goto exit;
490
}
491
492
if (data->vi.out_size > VC_MAXDATASIZE) {
493
error = -EINVAL;
494
goto exit;
495
}
496
497
inp->coda_ioctl.VFid = *fid;
498
499
/* the cmd field was mutated by increasing its size field to
500
* reflect the path and follow args. We need to subtract that
501
* out before sending the command to Venus. */
502
inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));
503
iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
504
inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) << 16;
505
506
/* in->coda_ioctl.rwflag = flag; */
507
inp->coda_ioctl.len = data->vi.in_size;
508
inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
509
510
/* get the data out of user space */
511
if (copy_from_user((char *)inp + (long)inp->coda_ioctl.data,
512
data->vi.in, data->vi.in_size)) {
513
error = -EINVAL;
514
goto exit;
515
}
516
517
error = coda_upcall(coda_vcp(sb), SIZE(ioctl) + data->vi.in_size,
518
&outsize, inp);
519
520
if (error) {
521
pr_warn("%s: Venus returns: %d for %s\n",
522
__func__, error, coda_f2s(fid));
523
goto exit;
524
}
525
526
if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) {
527
error = -EINVAL;
528
goto exit;
529
}
530
531
/* Copy out the OUT buffer. */
532
if (outp->coda_ioctl.len > data->vi.out_size) {
533
error = -EINVAL;
534
goto exit;
535
}
536
537
/* Copy out the OUT buffer. */
538
if (copy_to_user(data->vi.out,
539
(char *)outp + (long)outp->coda_ioctl.data,
540
outp->coda_ioctl.len)) {
541
error = -EFAULT;
542
goto exit;
543
}
544
545
exit:
546
kvfree(inp);
547
return error;
548
}
549
550
int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
551
{
552
union inputArgs *inp;
553
union outputArgs *outp;
554
int insize, outsize, error;
555
556
insize = SIZE(statfs);
557
UPARG(CODA_STATFS);
558
559
error = coda_upcall(coda_vcp(dentry->d_sb), insize, &outsize, inp);
560
if (!error) {
561
sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
562
sfs->f_bfree = outp->coda_statfs.stat.f_bfree;
563
sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
564
sfs->f_files = outp->coda_statfs.stat.f_files;
565
sfs->f_ffree = outp->coda_statfs.stat.f_ffree;
566
}
567
568
kvfree(inp);
569
return error;
570
}
571
572
int venus_access_intent(struct super_block *sb, struct CodaFid *fid,
573
bool *access_intent_supported,
574
size_t count, loff_t ppos, int type)
575
{
576
union inputArgs *inp;
577
union outputArgs *outp;
578
int insize, outsize, error;
579
bool finalizer =
580
type == CODA_ACCESS_TYPE_READ_FINISH ||
581
type == CODA_ACCESS_TYPE_WRITE_FINISH;
582
583
if (!*access_intent_supported && !finalizer)
584
return 0;
585
586
insize = SIZE(access_intent);
587
UPARG(CODA_ACCESS_INTENT);
588
589
inp->coda_access_intent.VFid = *fid;
590
inp->coda_access_intent.count = count;
591
inp->coda_access_intent.pos = ppos;
592
inp->coda_access_intent.type = type;
593
594
error = coda_upcall(coda_vcp(sb), insize,
595
finalizer ? NULL : &outsize, inp);
596
597
/*
598
* we have to free the request buffer for synchronous upcalls
599
* or when asynchronous upcalls fail, but not when asynchronous
600
* upcalls succeed
601
*/
602
if (!finalizer || error)
603
kvfree(inp);
604
605
/* Chunked access is not supported or an old Coda client */
606
if (error == -EOPNOTSUPP) {
607
*access_intent_supported = false;
608
error = 0;
609
}
610
return error;
611
}
612
613
/*
614
* coda_upcall and coda_downcall routines.
615
*/
616
static void coda_block_signals(sigset_t *old)
617
{
618
spin_lock_irq(&current->sighand->siglock);
619
*old = current->blocked;
620
621
sigfillset(&current->blocked);
622
sigdelset(&current->blocked, SIGKILL);
623
sigdelset(&current->blocked, SIGSTOP);
624
sigdelset(&current->blocked, SIGINT);
625
626
recalc_sigpending();
627
spin_unlock_irq(&current->sighand->siglock);
628
}
629
630
static void coda_unblock_signals(sigset_t *old)
631
{
632
spin_lock_irq(&current->sighand->siglock);
633
current->blocked = *old;
634
recalc_sigpending();
635
spin_unlock_irq(&current->sighand->siglock);
636
}
637
638
/* Don't allow signals to interrupt the following upcalls before venus
639
* has seen them,
640
* - CODA_CLOSE or CODA_RELEASE upcall (to avoid reference count problems)
641
* - CODA_STORE (to avoid data loss)
642
* - CODA_ACCESS_INTENT (to avoid reference count problems)
643
*/
644
#define CODA_INTERRUPTIBLE(r) (!coda_hard && \
645
(((r)->uc_opcode != CODA_CLOSE && \
646
(r)->uc_opcode != CODA_STORE && \
647
(r)->uc_opcode != CODA_ACCESS_INTENT && \
648
(r)->uc_opcode != CODA_RELEASE) || \
649
(r)->uc_flags & CODA_REQ_READ))
650
651
static inline void coda_waitfor_upcall(struct venus_comm *vcp,
652
struct upc_req *req)
653
{
654
DECLARE_WAITQUEUE(wait, current);
655
unsigned long timeout = jiffies + coda_timeout * HZ;
656
sigset_t old;
657
int blocked;
658
659
coda_block_signals(&old);
660
blocked = 1;
661
662
add_wait_queue(&req->uc_sleep, &wait);
663
for (;;) {
664
if (CODA_INTERRUPTIBLE(req))
665
set_current_state(TASK_INTERRUPTIBLE);
666
else
667
set_current_state(TASK_UNINTERRUPTIBLE);
668
669
/* got a reply */
670
if (req->uc_flags & (CODA_REQ_WRITE | CODA_REQ_ABORT))
671
break;
672
673
if (blocked && time_after(jiffies, timeout) &&
674
CODA_INTERRUPTIBLE(req))
675
{
676
coda_unblock_signals(&old);
677
blocked = 0;
678
}
679
680
if (signal_pending(current)) {
681
list_del(&req->uc_chain);
682
break;
683
}
684
685
mutex_unlock(&vcp->vc_mutex);
686
if (blocked)
687
schedule_timeout(HZ);
688
else
689
schedule();
690
mutex_lock(&vcp->vc_mutex);
691
}
692
if (blocked)
693
coda_unblock_signals(&old);
694
695
remove_wait_queue(&req->uc_sleep, &wait);
696
set_current_state(TASK_RUNNING);
697
}
698
699
700
/*
701
* coda_upcall will return an error in the case of
702
* failed communication with Venus _or_ will peek at Venus
703
* reply and return Venus' error.
704
*
705
* As venus has 2 types of errors, normal errors (positive) and internal
706
* errors (negative), normal errors are negated, while internal errors
707
* are all mapped to -EINTR, while showing a nice warning message. (jh)
708
*/
709
static int coda_upcall(struct venus_comm *vcp,
710
int inSize, int *outSize,
711
union inputArgs *buffer)
712
{
713
union outputArgs *out;
714
union inputArgs *sig_inputArgs;
715
struct upc_req *req = NULL, *sig_req;
716
int error;
717
718
mutex_lock(&vcp->vc_mutex);
719
720
if (!vcp->vc_inuse) {
721
pr_notice("Venus dead, not sending upcall\n");
722
error = -ENXIO;
723
goto exit;
724
}
725
726
/* Format the request message. */
727
req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
728
if (!req) {
729
error = -ENOMEM;
730
goto exit;
731
}
732
733
buffer->ih.unique = ++vcp->vc_seq;
734
735
req->uc_data = (void *)buffer;
736
req->uc_flags = outSize ? 0 : CODA_REQ_ASYNC;
737
req->uc_inSize = inSize;
738
req->uc_outSize = (outSize && *outSize) ? *outSize : inSize;
739
req->uc_opcode = buffer->ih.opcode;
740
req->uc_unique = buffer->ih.unique;
741
init_waitqueue_head(&req->uc_sleep);
742
743
/* Append msg to pending queue and poke Venus. */
744
list_add_tail(&req->uc_chain, &vcp->vc_pending);
745
wake_up_interruptible(&vcp->vc_waitq);
746
747
/* We can return early on asynchronous requests */
748
if (outSize == NULL) {
749
mutex_unlock(&vcp->vc_mutex);
750
return 0;
751
}
752
753
/* We can be interrupted while we wait for Venus to process
754
* our request. If the interrupt occurs before Venus has read
755
* the request, we dequeue and return. If it occurs after the
756
* read but before the reply, we dequeue, send a signal
757
* message, and return. If it occurs after the reply we ignore
758
* it. In no case do we want to restart the syscall. If it
759
* was interrupted by a venus shutdown (psdev_close), return
760
* ENODEV. */
761
762
/* Go to sleep. Wake up on signals only after the timeout. */
763
coda_waitfor_upcall(vcp, req);
764
765
/* Op went through, interrupt or not... */
766
if (req->uc_flags & CODA_REQ_WRITE) {
767
out = (union outputArgs *)req->uc_data;
768
/* here we map positive Venus errors to kernel errors */
769
error = -out->oh.result;
770
*outSize = req->uc_outSize;
771
goto exit;
772
}
773
774
error = -EINTR;
775
if ((req->uc_flags & CODA_REQ_ABORT) || !signal_pending(current)) {
776
pr_warn("Unexpected interruption.\n");
777
goto exit;
778
}
779
780
/* Interrupted before venus read it. */
781
if (!(req->uc_flags & CODA_REQ_READ))
782
goto exit;
783
784
/* Venus saw the upcall, make sure we can send interrupt signal */
785
if (!vcp->vc_inuse) {
786
pr_info("Venus dead, not sending signal.\n");
787
goto exit;
788
}
789
790
error = -ENOMEM;
791
sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
792
if (!sig_req) goto exit;
793
794
sig_inputArgs = kvzalloc(sizeof(*sig_inputArgs), GFP_KERNEL);
795
if (!sig_inputArgs) {
796
kfree(sig_req);
797
goto exit;
798
}
799
800
error = -EINTR;
801
sig_inputArgs->ih.opcode = CODA_SIGNAL;
802
sig_inputArgs->ih.unique = req->uc_unique;
803
804
sig_req->uc_flags = CODA_REQ_ASYNC;
805
sig_req->uc_opcode = sig_inputArgs->ih.opcode;
806
sig_req->uc_unique = sig_inputArgs->ih.unique;
807
sig_req->uc_data = (void *)sig_inputArgs;
808
sig_req->uc_inSize = sizeof(struct coda_in_hdr);
809
sig_req->uc_outSize = sizeof(struct coda_in_hdr);
810
811
/* insert at head of queue! */
812
list_add(&(sig_req->uc_chain), &vcp->vc_pending);
813
wake_up_interruptible(&vcp->vc_waitq);
814
815
exit:
816
kfree(req);
817
mutex_unlock(&vcp->vc_mutex);
818
return error;
819
}
820
821
/*
822
The statements below are part of the Coda opportunistic
823
programming -- taken from the Mach/BSD kernel code for Coda.
824
You don't get correct semantics by stating what needs to be
825
done without guaranteeing the invariants needed for it to happen.
826
When will be have time to find out what exactly is going on? (pjb)
827
*/
828
829
830
/*
831
* There are 7 cases where cache invalidations occur. The semantics
832
* of each is listed here:
833
*
834
* CODA_FLUSH -- flush all entries from the name cache and the cnode cache.
835
* CODA_PURGEUSER -- flush all entries from the name cache for a specific user
836
* This call is a result of token expiration.
837
*
838
* The next arise as the result of callbacks on a file or directory.
839
* CODA_ZAPFILE -- flush the cached attributes for a file.
840
841
* CODA_ZAPDIR -- flush the attributes for the dir and
842
* force a new lookup for all the children
843
of this dir.
844
845
*
846
* The next is a result of Venus detecting an inconsistent file.
847
* CODA_PURGEFID -- flush the attribute for the file
848
* purge it and its children from the dcache
849
*
850
* The last allows Venus to replace local fids with global ones
851
* during reintegration.
852
*
853
* CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
854
855
int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out,
856
size_t nbytes)
857
{
858
struct inode *inode = NULL;
859
struct CodaFid *fid = NULL, *newfid;
860
struct super_block *sb;
861
862
/*
863
* Make sure we have received enough data from the cache
864
* manager to populate the necessary fields in the buffer
865
*/
866
switch (opcode) {
867
case CODA_PURGEUSER:
868
if (nbytes < sizeof(struct coda_purgeuser_out))
869
return -EINVAL;
870
break;
871
872
case CODA_ZAPDIR:
873
if (nbytes < sizeof(struct coda_zapdir_out))
874
return -EINVAL;
875
break;
876
877
case CODA_ZAPFILE:
878
if (nbytes < sizeof(struct coda_zapfile_out))
879
return -EINVAL;
880
break;
881
882
case CODA_PURGEFID:
883
if (nbytes < sizeof(struct coda_purgefid_out))
884
return -EINVAL;
885
break;
886
887
case CODA_REPLACE:
888
if (nbytes < sizeof(struct coda_replace_out))
889
return -EINVAL;
890
break;
891
}
892
893
/* Handle invalidation requests. */
894
mutex_lock(&vcp->vc_mutex);
895
sb = vcp->vc_sb;
896
if (!sb || !sb->s_root)
897
goto unlock_out;
898
899
switch (opcode) {
900
case CODA_FLUSH:
901
coda_cache_clear_all(sb);
902
shrink_dcache_sb(sb);
903
if (d_really_is_positive(sb->s_root))
904
coda_flag_inode(d_inode(sb->s_root), C_FLUSH);
905
break;
906
907
case CODA_PURGEUSER:
908
coda_cache_clear_all(sb);
909
break;
910
911
case CODA_ZAPDIR:
912
fid = &out->coda_zapdir.CodaFid;
913
break;
914
915
case CODA_ZAPFILE:
916
fid = &out->coda_zapfile.CodaFid;
917
break;
918
919
case CODA_PURGEFID:
920
fid = &out->coda_purgefid.CodaFid;
921
break;
922
923
case CODA_REPLACE:
924
fid = &out->coda_replace.OldFid;
925
break;
926
}
927
if (fid)
928
inode = coda_fid_to_inode(fid, sb);
929
930
unlock_out:
931
mutex_unlock(&vcp->vc_mutex);
932
933
if (!inode)
934
return 0;
935
936
switch (opcode) {
937
case CODA_ZAPDIR:
938
coda_flag_inode_children(inode, C_PURGE);
939
coda_flag_inode(inode, C_VATTR);
940
break;
941
942
case CODA_ZAPFILE:
943
coda_flag_inode(inode, C_VATTR);
944
break;
945
946
case CODA_PURGEFID:
947
coda_flag_inode_children(inode, C_PURGE);
948
949
/* catch the dentries later if some are still busy */
950
coda_flag_inode(inode, C_PURGE);
951
d_prune_aliases(inode);
952
break;
953
954
case CODA_REPLACE:
955
newfid = &out->coda_replace.NewFid;
956
coda_replace_fid(inode, fid, newfid);
957
break;
958
}
959
iput(inode);
960
return 0;
961
}
962
963