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

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

Version: ~ [ linux-5.14-rc3 ] ~ [ linux-5.13.5 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.53 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.135 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.198 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.240 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.276 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.276 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ 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 <linux/signal.h>
 18 #include <linux/sched/signal.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 <linux/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 = task_pid_nr_ns(current, &init_pid_ns);
 54         inp->ih.pgid = task_pgrp_nr_ns(current, &init_pid_ns);
 55         inp->ih.uid = from_kuid(&init_user_ns, 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);
 81         UPARG(CODA_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); 
 99         UPARG(CODA_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);
118         UPARG(CODA_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));
140         UPARG(CODA_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                 kuid_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 = from_kuid(&init_user_ns, 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);
187         UPARG(CODA_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)); 
244         UPARG(CODA_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));
279         UPARG(CODA_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));
333         UPARG(CODA_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);
357         UPARG(CODA_READLINK);
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 - 1;
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));
415         UPARG(CODA_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), insize, &outsize, inp);
450 
451         CODA_FREE(inp, insize);
452         return error;
453 }
454 
455 int venus_access(struct super_block *sb, struct CodaFid *fid, int mask)
456 {
457         union inputArgs *inp;
458         union outputArgs *outp; 
459         int insize, outsize, error;
460 
461         insize = SIZE(access);
462         UPARG(CODA_ACCESS);
463 
464         inp->coda_access.VFid = *fid;
465         inp->coda_access.flags = mask;
466 
467         error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
468 
469         CODA_FREE(inp, insize);
470         return error;
471 }
472 
473 
474 int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
475                  unsigned int cmd, struct PioctlData *data)
476 {
477         union inputArgs *inp;
478         union outputArgs *outp;  
479         int insize, outsize, error;
480         int iocsize;
481 
482         insize = VC_MAXMSGSIZE;
483         UPARG(CODA_IOCTL);
484 
485         /* build packet for Venus */
486         if (data->vi.in_size > VC_MAXDATASIZE) {
487                 error = -EINVAL;
488                 goto exit;
489         }
490 
491         if (data->vi.out_size > VC_MAXDATASIZE) {
492                 error = -EINVAL;
493                 goto exit;
494         }
495 
496         inp->coda_ioctl.VFid = *fid;
497     
498         /* the cmd field was mutated by increasing its size field to
499          * reflect the path and follow args. We need to subtract that
500          * out before sending the command to Venus.  */
501         inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));   
502         iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
503         inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) <<     16;     
504     
505         /* in->coda_ioctl.rwflag = flag; */
506         inp->coda_ioctl.len = data->vi.in_size;
507         inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
508      
509         /* get the data out of user space */
510         if (copy_from_user((char *)inp + (long)inp->coda_ioctl.data,
511                            data->vi.in, data->vi.in_size)) {
512                 error = -EINVAL;
513                 goto exit;
514         }
515 
516         error = coda_upcall(coda_vcp(sb), SIZE(ioctl) + data->vi.in_size,
517                             &outsize, inp);
518 
519         if (error) {
520                 pr_warn("%s: Venus returns: %d for %s\n",
521                         __func__, error, coda_f2s(fid));
522                 goto exit; 
523         }
524 
525         if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) {
526                 error = -EINVAL;
527                 goto exit;
528         }
529         
530         /* Copy out the OUT buffer. */
531         if (outp->coda_ioctl.len > data->vi.out_size) {
532                 error = -EINVAL;
533                 goto exit;
534         }
535 
536         /* Copy out the OUT buffer. */
537         if (copy_to_user(data->vi.out,
538                          (char *)outp + (long)outp->coda_ioctl.data,
539                          outp->coda_ioctl.len)) {
540                 error = -EFAULT;
541                 goto exit;
542         }
543 
544  exit:
545         CODA_FREE(inp, insize);
546         return error;
547 }
548 
549 int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
550 { 
551         union inputArgs *inp;
552         union outputArgs *outp;
553         int insize, outsize, error;
554         
555         insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
556         UPARG(CODA_STATFS);
557 
558         error = coda_upcall(coda_vcp(dentry->d_sb), insize, &outsize, inp);
559         if (!error) {
560                 sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
561                 sfs->f_bfree  = outp->coda_statfs.stat.f_bfree;
562                 sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
563                 sfs->f_files  = outp->coda_statfs.stat.f_files;
564                 sfs->f_ffree  = outp->coda_statfs.stat.f_ffree;
565         }
566 
567         CODA_FREE(inp, insize);
568         return error;
569 }
570 
571 /*
572  * coda_upcall and coda_downcall routines.
573  */
574 static void coda_block_signals(sigset_t *old)
575 {
576         spin_lock_irq(&current->sighand->siglock);
577         *old = current->blocked;
578 
579         sigfillset(&current->blocked);
580         sigdelset(&current->blocked, SIGKILL);
581         sigdelset(&current->blocked, SIGSTOP);
582         sigdelset(&current->blocked, SIGINT);
583 
584         recalc_sigpending();
585         spin_unlock_irq(&current->sighand->siglock);
586 }
587 
588 static void coda_unblock_signals(sigset_t *old)
589 {
590         spin_lock_irq(&current->sighand->siglock);
591         current->blocked = *old;
592         recalc_sigpending();
593         spin_unlock_irq(&current->sighand->siglock);
594 }
595 
596 /* Don't allow signals to interrupt the following upcalls before venus
597  * has seen them,
598  * - CODA_CLOSE or CODA_RELEASE upcall  (to avoid reference count problems)
599  * - CODA_STORE                         (to avoid data loss)
600  */
601 #define CODA_INTERRUPTIBLE(r) (!coda_hard && \
602                                (((r)->uc_opcode != CODA_CLOSE && \
603                                  (r)->uc_opcode != CODA_STORE && \
604                                  (r)->uc_opcode != CODA_RELEASE) || \
605                                 (r)->uc_flags & CODA_REQ_READ))
606 
607 static inline void coda_waitfor_upcall(struct venus_comm *vcp,
608                                        struct upc_req *req)
609 {
610         DECLARE_WAITQUEUE(wait, current);
611         unsigned long timeout = jiffies + coda_timeout * HZ;
612         sigset_t old;
613         int blocked;
614 
615         coda_block_signals(&old);
616         blocked = 1;
617 
618         add_wait_queue(&req->uc_sleep, &wait);
619         for (;;) {
620                 if (CODA_INTERRUPTIBLE(req))
621                         set_current_state(TASK_INTERRUPTIBLE);
622                 else
623                         set_current_state(TASK_UNINTERRUPTIBLE);
624 
625                 /* got a reply */
626                 if (req->uc_flags & (CODA_REQ_WRITE | CODA_REQ_ABORT))
627                         break;
628 
629                 if (blocked && time_after(jiffies, timeout) &&
630                     CODA_INTERRUPTIBLE(req))
631                 {
632                         coda_unblock_signals(&old);
633                         blocked = 0;
634                 }
635 
636                 if (signal_pending(current)) {
637                         list_del(&req->uc_chain);
638                         break;
639                 }
640 
641                 mutex_unlock(&vcp->vc_mutex);
642                 if (blocked)
643                         schedule_timeout(HZ);
644                 else
645                         schedule();
646                 mutex_lock(&vcp->vc_mutex);
647         }
648         if (blocked)
649                 coda_unblock_signals(&old);
650 
651         remove_wait_queue(&req->uc_sleep, &wait);
652         set_current_state(TASK_RUNNING);
653 }
654 
655 
656 /*
657  * coda_upcall will return an error in the case of
658  * failed communication with Venus _or_ will peek at Venus
659  * reply and return Venus' error.
660  *
661  * As venus has 2 types of errors, normal errors (positive) and internal
662  * errors (negative), normal errors are negated, while internal errors
663  * are all mapped to -EINTR, while showing a nice warning message. (jh)
664  */
665 static int coda_upcall(struct venus_comm *vcp,
666                        int inSize, int *outSize,
667                        union inputArgs *buffer)
668 {
669         union outputArgs *out;
670         union inputArgs *sig_inputArgs;
671         struct upc_req *req = NULL, *sig_req;
672         int error;
673 
674         mutex_lock(&vcp->vc_mutex);
675 
676         if (!vcp->vc_inuse) {
677                 pr_notice("Venus dead, not sending upcall\n");
678                 error = -ENXIO;
679                 goto exit;
680         }
681 
682         /* Format the request message. */
683         req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
684         if (!req) {
685                 error = -ENOMEM;
686                 goto exit;
687         }
688 
689         req->uc_data = (void *)buffer;
690         req->uc_flags = 0;
691         req->uc_inSize = inSize;
692         req->uc_outSize = *outSize ? *outSize : inSize;
693         req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
694         req->uc_unique = ++vcp->vc_seq;
695         init_waitqueue_head(&req->uc_sleep);
696 
697         /* Fill in the common input args. */
698         ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
699 
700         /* Append msg to pending queue and poke Venus. */
701         list_add_tail(&req->uc_chain, &vcp->vc_pending);
702 
703         wake_up_interruptible(&vcp->vc_waitq);
704         /* We can be interrupted while we wait for Venus to process
705          * our request.  If the interrupt occurs before Venus has read
706          * the request, we dequeue and return. If it occurs after the
707          * read but before the reply, we dequeue, send a signal
708          * message, and return. If it occurs after the reply we ignore
709          * it. In no case do we want to restart the syscall.  If it
710          * was interrupted by a venus shutdown (psdev_close), return
711          * ENODEV.  */
712 
713         /* Go to sleep.  Wake up on signals only after the timeout. */
714         coda_waitfor_upcall(vcp, req);
715 
716         /* Op went through, interrupt or not... */
717         if (req->uc_flags & CODA_REQ_WRITE) {
718                 out = (union outputArgs *)req->uc_data;
719                 /* here we map positive Venus errors to kernel errors */
720                 error = -out->oh.result;
721                 *outSize = req->uc_outSize;
722                 goto exit;
723         }
724 
725         error = -EINTR;
726         if ((req->uc_flags & CODA_REQ_ABORT) || !signal_pending(current)) {
727                 pr_warn("Unexpected interruption.\n");
728                 goto exit;
729         }
730 
731         /* Interrupted before venus read it. */
732         if (!(req->uc_flags & CODA_REQ_READ))
733                 goto exit;
734 
735         /* Venus saw the upcall, make sure we can send interrupt signal */
736         if (!vcp->vc_inuse) {
737                 pr_info("Venus dead, not sending signal.\n");
738                 goto exit;
739         }
740 
741         error = -ENOMEM;
742         sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
743         if (!sig_req) goto exit;
744 
745         CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
746         if (!sig_req->uc_data) {
747                 kfree(sig_req);
748                 goto exit;
749         }
750 
751         error = -EINTR;
752         sig_inputArgs = (union inputArgs *)sig_req->uc_data;
753         sig_inputArgs->ih.opcode = CODA_SIGNAL;
754         sig_inputArgs->ih.unique = req->uc_unique;
755 
756         sig_req->uc_flags = CODA_REQ_ASYNC;
757         sig_req->uc_opcode = sig_inputArgs->ih.opcode;
758         sig_req->uc_unique = sig_inputArgs->ih.unique;
759         sig_req->uc_inSize = sizeof(struct coda_in_hdr);
760         sig_req->uc_outSize = sizeof(struct coda_in_hdr);
761 
762         /* insert at head of queue! */
763         list_add(&(sig_req->uc_chain), &vcp->vc_pending);
764         wake_up_interruptible(&vcp->vc_waitq);
765 
766 exit:
767         kfree(req);
768         mutex_unlock(&vcp->vc_mutex);
769         return error;
770 }
771 
772 /*  
773     The statements below are part of the Coda opportunistic
774     programming -- taken from the Mach/BSD kernel code for Coda. 
775     You don't get correct semantics by stating what needs to be
776     done without guaranteeing the invariants needed for it to happen.
777     When will be have time to find out what exactly is going on?  (pjb)
778 */
779 
780 
781 /* 
782  * There are 7 cases where cache invalidations occur.  The semantics
783  *  of each is listed here:
784  *
785  * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
786  * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
787  *                  This call is a result of token expiration.
788  *
789  * The next arise as the result of callbacks on a file or directory.
790  * CODA_ZAPFILE   -- flush the cached attributes for a file.
791 
792  * CODA_ZAPDIR    -- flush the attributes for the dir and
793  *                  force a new lookup for all the children
794                     of this dir.
795 
796  *
797  * The next is a result of Venus detecting an inconsistent file.
798  * CODA_PURGEFID  -- flush the attribute for the file
799  *                  purge it and its children from the dcache
800  *
801  * The last  allows Venus to replace local fids with global ones
802  * during reintegration.
803  *
804  * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
805 
806 int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out)
807 {
808         struct inode *inode = NULL;
809         struct CodaFid *fid = NULL, *newfid;
810         struct super_block *sb;
811 
812         /* Handle invalidation requests. */
813         mutex_lock(&vcp->vc_mutex);
814         sb = vcp->vc_sb;
815         if (!sb || !sb->s_root)
816                 goto unlock_out;
817 
818         switch (opcode) {
819         case CODA_FLUSH:
820                 coda_cache_clear_all(sb);
821                 shrink_dcache_sb(sb);
822                 if (d_really_is_positive(sb->s_root))
823                         coda_flag_inode(d_inode(sb->s_root), C_FLUSH);
824                 break;
825 
826         case CODA_PURGEUSER:
827                 coda_cache_clear_all(sb);
828                 break;
829 
830         case CODA_ZAPDIR:
831                 fid = &out->coda_zapdir.CodaFid;
832                 break;
833 
834         case CODA_ZAPFILE:
835                 fid = &out->coda_zapfile.CodaFid;
836                 break;
837 
838         case CODA_PURGEFID:
839                 fid = &out->coda_purgefid.CodaFid;
840                 break;
841 
842         case CODA_REPLACE:
843                 fid = &out->coda_replace.OldFid;
844                 break;
845         }
846         if (fid)
847                 inode = coda_fid_to_inode(fid, sb);
848 
849 unlock_out:
850         mutex_unlock(&vcp->vc_mutex);
851 
852         if (!inode)
853                 return 0;
854 
855         switch (opcode) {
856         case CODA_ZAPDIR:
857                 coda_flag_inode_children(inode, C_PURGE);
858                 coda_flag_inode(inode, C_VATTR);
859                 break;
860 
861         case CODA_ZAPFILE:
862                 coda_flag_inode(inode, C_VATTR);
863                 break;
864 
865         case CODA_PURGEFID:
866                 coda_flag_inode_children(inode, C_PURGE);
867 
868                 /* catch the dentries later if some are still busy */
869                 coda_flag_inode(inode, C_PURGE);
870                 d_prune_aliases(inode);
871                 break;
872 
873         case CODA_REPLACE:
874                 newfid = &out->coda_replace.NewFid;
875                 coda_replace_fid(inode, fid, newfid);
876                 break;
877         }
878         iput(inode);
879         return 0;
880 }
881 
882 

~ [ 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