Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

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