Root/fs/coda/upcall.c

1/*
2 * Mostly platform independent upcall operations to Venus:
3 * -- upcalls
4 * -- upcall routines
5 *
6 * Linux 2.0 version
7 * Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk>,
8 * Michael Callahan <callahan@maths.ox.ac.uk>
9 *
10 * Redone for Linux 2.1
11 * Copyright (C) 1997 Carnegie Mellon University
12 *
13 * Carnegie Mellon University encourages users of this code to contribute
14 * improvements to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
15 */
16
17#include <asm/system.h>
18#include <linux/signal.h>
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
42static int coda_upcall(struct venus_comm *vc, int inSize, int *outSize,
43               union inputArgs *buffer);
44
45static 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)\
62do {\
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 */
75int 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
92int 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
111int 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
130int 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
160int 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
180int 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
201int 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
232int 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
269int 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
302int 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
325int 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
347int 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
379int 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
405int 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
440int 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
457int 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
476int 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
551int 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 */
576static 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
590static 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
609static 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 */
667static 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
768exit:
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
808int 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
851unlock_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

Archive Download this file



interactive