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

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

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ 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.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * Mostly platform independent upcall operations to Venus:
  4  *  -- upcalls
  5  *  -- upcall routines
  6  *
  7  * Linux 2.0 version
  8  * Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk>, 
  9  * Michael Callahan <callahan@maths.ox.ac.uk> 
 10  * 
 11  * Redone for Linux 2.1
 12  * Copyright (C) 1997 Carnegie Mellon University
 13  *
 14  * Carnegie Mellon University encourages users of this code to contribute
 15  * improvements to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
 16  */
 17 
 18 #include <linux/signal.h>
 19 #include <linux/sched/signal.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 <linux/uaccess.h>
 32 #include <linux/vmalloc.h>
 33 #include <linux/vfs.h>
 34 
 35 #include <linux/coda.h>
 36 #include "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         inp = kvzalloc(size, GFP_KERNEL);
 50         if (!inp)
 51                 return ERR_PTR(-ENOMEM);
 52 
 53         inp->ih.opcode = opcode;
 54         inp->ih.pid = task_pid_nr_ns(current, &init_pid_ns);
 55         inp->ih.pgid = task_pgrp_nr_ns(current, &init_pid_ns);
 56         inp->ih.uid = from_kuid(&init_user_ns, 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         kvfree(inp);
 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         kvfree(inp);
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         kvfree(inp);
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         kvfree(inp);
157         return error;
158 }
159 
160 int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
161                 kuid_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 = from_kuid(&init_user_ns, 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         kvfree(inp);
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         kvfree(inp);
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         kvfree(inp);
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         kvfree(inp);
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         kvfree(inp);
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         kvfree(inp);
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         kvfree(inp);
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);
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 - 1;
367                 *length = retlen;
368                 result =  (char *)outp + (long)outp->coda_readlink.data;
369                 memcpy(buffer, result, retlen);
370                 *(buffer + retlen) = '\0';
371         }
372 
373         kvfree(inp);
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         kvfree(inp);
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         kvfree(inp);
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), insize, &outsize, inp);
451 
452         kvfree(inp);
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);
463         UPARG(CODA_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         kvfree(inp);
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                 pr_warn("%s: Venus returns: %d for %s\n",
522                         __func__, 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         kvfree(inp);
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 = SIZE(statfs);
557         UPARG(CODA_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         kvfree(inp);
569         return error;
570 }
571 
572 int venus_access_intent(struct super_block *sb, struct CodaFid *fid,
573                         bool *access_intent_supported,
574                         size_t count, loff_t ppos, int type)
575 {
576         union inputArgs *inp;
577         union outputArgs *outp;
578         int insize, outsize, error;
579         bool finalizer =
580                 type == CODA_ACCESS_TYPE_READ_FINISH ||
581                 type == CODA_ACCESS_TYPE_WRITE_FINISH;
582 
583         if (!*access_intent_supported && !finalizer)
584                 return 0;
585 
586         insize = SIZE(access_intent);
587         UPARG(CODA_ACCESS_INTENT);
588 
589         inp->coda_access_intent.VFid = *fid;
590         inp->coda_access_intent.count = count;
591         inp->coda_access_intent.pos = ppos;
592         inp->coda_access_intent.type = type;
593 
594         error = coda_upcall(coda_vcp(sb), insize,
595                             finalizer ? NULL : &outsize, inp);
596 
597         /*
598          * we have to free the request buffer for synchronous upcalls
599          * or when asynchronous upcalls fail, but not when asynchronous
600          * upcalls succeed
601          */
602         if (!finalizer || error)
603                 kvfree(inp);
604 
605         /* Chunked access is not supported or an old Coda client */
606         if (error == -EOPNOTSUPP) {
607                 *access_intent_supported = false;
608                 error = 0;
609         }
610         return error;
611 }
612 
613 /*
614  * coda_upcall and coda_downcall routines.
615  */
616 static void coda_block_signals(sigset_t *old)
617 {
618         spin_lock_irq(&current->sighand->siglock);
619         *old = current->blocked;
620 
621         sigfillset(&current->blocked);
622         sigdelset(&current->blocked, SIGKILL);
623         sigdelset(&current->blocked, SIGSTOP);
624         sigdelset(&current->blocked, SIGINT);
625 
626         recalc_sigpending();
627         spin_unlock_irq(&current->sighand->siglock);
628 }
629 
630 static void coda_unblock_signals(sigset_t *old)
631 {
632         spin_lock_irq(&current->sighand->siglock);
633         current->blocked = *old;
634         recalc_sigpending();
635         spin_unlock_irq(&current->sighand->siglock);
636 }
637 
638 /* Don't allow signals to interrupt the following upcalls before venus
639  * has seen them,
640  * - CODA_CLOSE or CODA_RELEASE upcall  (to avoid reference count problems)
641  * - CODA_STORE                         (to avoid data loss)
642  * - CODA_ACCESS_INTENT                 (to avoid reference count problems)
643  */
644 #define CODA_INTERRUPTIBLE(r) (!coda_hard && \
645                                (((r)->uc_opcode != CODA_CLOSE && \
646                                  (r)->uc_opcode != CODA_STORE && \
647                                  (r)->uc_opcode != CODA_ACCESS_INTENT && \
648                                  (r)->uc_opcode != CODA_RELEASE) || \
649                                 (r)->uc_flags & CODA_REQ_READ))
650 
651 static inline void coda_waitfor_upcall(struct venus_comm *vcp,
652                                        struct upc_req *req)
653 {
654         DECLARE_WAITQUEUE(wait, current);
655         unsigned long timeout = jiffies + coda_timeout * HZ;
656         sigset_t old;
657         int blocked;
658 
659         coda_block_signals(&old);
660         blocked = 1;
661 
662         add_wait_queue(&req->uc_sleep, &wait);
663         for (;;) {
664                 if (CODA_INTERRUPTIBLE(req))
665                         set_current_state(TASK_INTERRUPTIBLE);
666                 else
667                         set_current_state(TASK_UNINTERRUPTIBLE);
668 
669                 /* got a reply */
670                 if (req->uc_flags & (CODA_REQ_WRITE | CODA_REQ_ABORT))
671                         break;
672 
673                 if (blocked && time_after(jiffies, timeout) &&
674                     CODA_INTERRUPTIBLE(req))
675                 {
676                         coda_unblock_signals(&old);
677                         blocked = 0;
678                 }
679 
680                 if (signal_pending(current)) {
681                         list_del(&req->uc_chain);
682                         break;
683                 }
684 
685                 mutex_unlock(&vcp->vc_mutex);
686                 if (blocked)
687                         schedule_timeout(HZ);
688                 else
689                         schedule();
690                 mutex_lock(&vcp->vc_mutex);
691         }
692         if (blocked)
693                 coda_unblock_signals(&old);
694 
695         remove_wait_queue(&req->uc_sleep, &wait);
696         set_current_state(TASK_RUNNING);
697 }
698 
699 
700 /*
701  * coda_upcall will return an error in the case of
702  * failed communication with Venus _or_ will peek at Venus
703  * reply and return Venus' error.
704  *
705  * As venus has 2 types of errors, normal errors (positive) and internal
706  * errors (negative), normal errors are negated, while internal errors
707  * are all mapped to -EINTR, while showing a nice warning message. (jh)
708  */
709 static int coda_upcall(struct venus_comm *vcp,
710                        int inSize, int *outSize,
711                        union inputArgs *buffer)
712 {
713         union outputArgs *out;
714         union inputArgs *sig_inputArgs;
715         struct upc_req *req = NULL, *sig_req;
716         int error;
717 
718         mutex_lock(&vcp->vc_mutex);
719 
720         if (!vcp->vc_inuse) {
721                 pr_notice("Venus dead, not sending upcall\n");
722                 error = -ENXIO;
723                 goto exit;
724         }
725 
726         /* Format the request message. */
727         req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
728         if (!req) {
729                 error = -ENOMEM;
730                 goto exit;
731         }
732 
733         buffer->ih.unique = ++vcp->vc_seq;
734 
735         req->uc_data = (void *)buffer;
736         req->uc_flags = outSize ? 0 : CODA_REQ_ASYNC;
737         req->uc_inSize = inSize;
738         req->uc_outSize = (outSize && *outSize) ? *outSize : inSize;
739         req->uc_opcode = buffer->ih.opcode;
740         req->uc_unique = buffer->ih.unique;
741         init_waitqueue_head(&req->uc_sleep);
742 
743         /* Append msg to pending queue and poke Venus. */
744         list_add_tail(&req->uc_chain, &vcp->vc_pending);
745         wake_up_interruptible(&vcp->vc_waitq);
746 
747         /* We can return early on asynchronous requests */
748         if (outSize == NULL) {
749                 mutex_unlock(&vcp->vc_mutex);
750                 return 0;
751         }
752 
753         /* We can be interrupted while we wait for Venus to process
754          * our request.  If the interrupt occurs before Venus has read
755          * the request, we dequeue and return. If it occurs after the
756          * read but before the reply, we dequeue, send a signal
757          * message, and return. If it occurs after the reply we ignore
758          * it. In no case do we want to restart the syscall.  If it
759          * was interrupted by a venus shutdown (psdev_close), return
760          * ENODEV.  */
761 
762         /* Go to sleep.  Wake up on signals only after the timeout. */
763         coda_waitfor_upcall(vcp, req);
764 
765         /* Op went through, interrupt or not... */
766         if (req->uc_flags & CODA_REQ_WRITE) {
767                 out = (union outputArgs *)req->uc_data;
768                 /* here we map positive Venus errors to kernel errors */
769                 error = -out->oh.result;
770                 *outSize = req->uc_outSize;
771                 goto exit;
772         }
773 
774         error = -EINTR;
775         if ((req->uc_flags & CODA_REQ_ABORT) || !signal_pending(current)) {
776                 pr_warn("Unexpected interruption.\n");
777                 goto exit;
778         }
779 
780         /* Interrupted before venus read it. */
781         if (!(req->uc_flags & CODA_REQ_READ))
782                 goto exit;
783 
784         /* Venus saw the upcall, make sure we can send interrupt signal */
785         if (!vcp->vc_inuse) {
786                 pr_info("Venus dead, not sending signal.\n");
787                 goto exit;
788         }
789 
790         error = -ENOMEM;
791         sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
792         if (!sig_req) goto exit;
793 
794         sig_inputArgs = kvzalloc(sizeof(*sig_inputArgs), GFP_KERNEL);
795         if (!sig_inputArgs) {
796                 kfree(sig_req);
797                 goto exit;
798         }
799 
800         error = -EINTR;
801         sig_inputArgs->ih.opcode = CODA_SIGNAL;
802         sig_inputArgs->ih.unique = req->uc_unique;
803 
804         sig_req->uc_flags = CODA_REQ_ASYNC;
805         sig_req->uc_opcode = sig_inputArgs->ih.opcode;
806         sig_req->uc_unique = sig_inputArgs->ih.unique;
807         sig_req->uc_data = (void *)sig_inputArgs;
808         sig_req->uc_inSize = sizeof(struct coda_in_hdr);
809         sig_req->uc_outSize = sizeof(struct coda_in_hdr);
810 
811         /* insert at head of queue! */
812         list_add(&(sig_req->uc_chain), &vcp->vc_pending);
813         wake_up_interruptible(&vcp->vc_waitq);
814 
815 exit:
816         kfree(req);
817         mutex_unlock(&vcp->vc_mutex);
818         return error;
819 }
820 
821 /*  
822     The statements below are part of the Coda opportunistic
823     programming -- taken from the Mach/BSD kernel code for Coda. 
824     You don't get correct semantics by stating what needs to be
825     done without guaranteeing the invariants needed for it to happen.
826     When will be have time to find out what exactly is going on?  (pjb)
827 */
828 
829 
830 /* 
831  * There are 7 cases where cache invalidations occur.  The semantics
832  *  of each is listed here:
833  *
834  * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
835  * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
836  *                  This call is a result of token expiration.
837  *
838  * The next arise as the result of callbacks on a file or directory.
839  * CODA_ZAPFILE   -- flush the cached attributes for a file.
840 
841  * CODA_ZAPDIR    -- flush the attributes for the dir and
842  *                  force a new lookup for all the children
843                     of this dir.
844 
845  *
846  * The next is a result of Venus detecting an inconsistent file.
847  * CODA_PURGEFID  -- flush the attribute for the file
848  *                  purge it and its children from the dcache
849  *
850  * The last  allows Venus to replace local fids with global ones
851  * during reintegration.
852  *
853  * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
854 
855 int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out,
856                   size_t nbytes)
857 {
858         struct inode *inode = NULL;
859         struct CodaFid *fid = NULL, *newfid;
860         struct super_block *sb;
861 
862         /*
863          * Make sure we have received enough data from the cache
864          * manager to populate the necessary fields in the buffer
865          */
866         switch (opcode) {
867         case CODA_PURGEUSER:
868                 if (nbytes < sizeof(struct coda_purgeuser_out))
869                         return -EINVAL;
870                 break;
871 
872         case CODA_ZAPDIR:
873                 if (nbytes < sizeof(struct coda_zapdir_out))
874                         return -EINVAL;
875                 break;
876 
877         case CODA_ZAPFILE:
878                 if (nbytes < sizeof(struct coda_zapfile_out))
879                         return -EINVAL;
880                 break;
881 
882         case CODA_PURGEFID:
883                 if (nbytes < sizeof(struct coda_purgefid_out))
884                         return -EINVAL;
885                 break;
886 
887         case CODA_REPLACE:
888                 if (nbytes < sizeof(struct coda_replace_out))
889                         return -EINVAL;
890                 break;
891         }
892 
893         /* Handle invalidation requests. */
894         mutex_lock(&vcp->vc_mutex);
895         sb = vcp->vc_sb;
896         if (!sb || !sb->s_root)
897                 goto unlock_out;
898 
899         switch (opcode) {
900         case CODA_FLUSH:
901                 coda_cache_clear_all(sb);
902                 shrink_dcache_sb(sb);
903                 if (d_really_is_positive(sb->s_root))
904                         coda_flag_inode(d_inode(sb->s_root), C_FLUSH);
905                 break;
906 
907         case CODA_PURGEUSER:
908                 coda_cache_clear_all(sb);
909                 break;
910 
911         case CODA_ZAPDIR:
912                 fid = &out->coda_zapdir.CodaFid;
913                 break;
914 
915         case CODA_ZAPFILE:
916                 fid = &out->coda_zapfile.CodaFid;
917                 break;
918 
919         case CODA_PURGEFID:
920                 fid = &out->coda_purgefid.CodaFid;
921                 break;
922 
923         case CODA_REPLACE:
924                 fid = &out->coda_replace.OldFid;
925                 break;
926         }
927         if (fid)
928                 inode = coda_fid_to_inode(fid, sb);
929 
930 unlock_out:
931         mutex_unlock(&vcp->vc_mutex);
932 
933         if (!inode)
934                 return 0;
935 
936         switch (opcode) {
937         case CODA_ZAPDIR:
938                 coda_flag_inode_children(inode, C_PURGE);
939                 coda_flag_inode(inode, C_VATTR);
940                 break;
941 
942         case CODA_ZAPFILE:
943                 coda_flag_inode(inode, C_VATTR);
944                 break;
945 
946         case CODA_PURGEFID:
947                 coda_flag_inode_children(inode, C_PURGE);
948 
949                 /* catch the dentries later if some are still busy */
950                 coda_flag_inode(inode, C_PURGE);
951                 d_prune_aliases(inode);
952                 break;
953 
954         case CODA_REPLACE:
955                 newfid = &out->coda_replace.NewFid;
956                 coda_replace_fid(inode, fid, newfid);
957                 break;
958         }
959         iput(inode);
960         return 0;
961 }
962 

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

kernel.org | git.kernel.org | LWN.net | Project Home | 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.

sflogo.php