OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [coda/] [upcall.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.