~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/coda/upcall.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.