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

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

Version: ~ [ linux-5.2 ] ~ [ linux-5.1.16 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.57 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.132 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.184 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.184 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.69 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
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 <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 
 42 static int coda_upcall(struct venus_comm *vc, int inSize, int *outSize,
 43                        union inputArgs *buffer);
 44 
 45 static 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)\
 62 do {\
 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 */
 75 int 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 
 92 int 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 
111 int 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 
130 int 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 
160 int 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 
180 int 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 
201 int 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 
232 int 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 
269 int 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 
302 int 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 
325 int 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 
347 int 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 
379 int 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 
405 int 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 
440 int 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 
457 int 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 
476 int 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 
551 int 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  */
576 static 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 
590 static 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 
609 static 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  */
667 static 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 
768 exit:
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 
808 int 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 
851 unlock_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 

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

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp