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