2 * Mostly platform independent upcall operations to Venus:
7 * Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk>,
8 * Michael Callahan <callahan@maths.ox.ac.uk>
10 * Redone for Linux 2.1
11 * Copyright (C) 1997 Carnegie Mellon University
13 * Carnegie Mellon University encourages users of this code to contribute
14 * improvements to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
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>
23 #include <linux/time.h>
25 #include <linux/file.h>
26 #include <linux/stat.h>
27 #include <linux/errno.h>
28 #include <linux/string.h>
29 #include <asm/uaccess.h>
30 #include <linux/vmalloc.h>
31 #include <linux/vfs.h>
33 #include <linux/coda.h>
34 #include <linux/coda_linux.h>
35 #include <linux/coda_psdev.h>
36 #include <linux/coda_fs_i.h>
37 #include <linux/coda_cache.h>
41 static int coda_upcall(struct venus_comm *vc, int inSize, int *outSize,
42 union inputArgs *buffer);
44 static void *alloc_upcall(int opcode, int size)
48 CODA_ALLOC(inp, union inputArgs *, size);
50 return ERR_PTR(-ENOMEM);
52 inp->ih.opcode = opcode;
53 inp->ih.pid = current->pid;
54 inp->ih.pgid = task_pgrp_nr(current);
55 #ifdef CONFIG_CODA_FS_OLD_API
56 memset(&inp->ih.cred, 0, sizeof(struct coda_cred));
57 inp->ih.cred.cr_fsuid = current->fsuid;
59 inp->ih.uid = current->fsuid;
66 inp = (union inputArgs *)alloc_upcall(op, insize); \
67 if (IS_ERR(inp)) { return PTR_ERR(inp); }\
68 outp = (union outputArgs *)(inp); \
72 #define INSIZE(tag) sizeof(struct coda_ ## tag ## _in)
73 #define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out)
74 #define SIZE(tag) max_t(unsigned int, INSIZE(tag), OUTSIZE(tag))
78 int venus_rootfid(struct super_block *sb, struct CodaFid *fidp)
81 union outputArgs *outp;
82 int insize, outsize, error;
87 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
89 *fidp = outp->coda_root.VFid;
91 CODA_FREE(inp, insize);
95 int venus_getattr(struct super_block *sb, struct CodaFid *fid,
96 struct coda_vattr *attr)
99 union outputArgs *outp;
100 int insize, outsize, error;
102 insize = SIZE(getattr);
104 inp->coda_getattr.VFid = *fid;
106 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
108 *attr = outp->coda_getattr.attr;
110 CODA_FREE(inp, insize);
114 int venus_setattr(struct super_block *sb, struct CodaFid *fid,
115 struct coda_vattr *vattr)
117 union inputArgs *inp;
118 union outputArgs *outp;
119 int insize, outsize, error;
121 insize = SIZE(setattr);
124 inp->coda_setattr.VFid = *fid;
125 inp->coda_setattr.attr = *vattr;
127 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
129 CODA_FREE(inp, insize);
133 int venus_lookup(struct super_block *sb, struct CodaFid *fid,
134 const char *name, int length, int * type,
135 struct CodaFid *resfid)
137 union inputArgs *inp;
138 union outputArgs *outp;
139 int insize, outsize, error;
142 offset = INSIZE(lookup);
143 insize = max_t(unsigned int, offset + length +1, OUTSIZE(lookup));
146 inp->coda_lookup.VFid = *fid;
147 inp->coda_lookup.name = offset;
148 inp->coda_lookup.flags = CLU_CASE_SENSITIVE;
149 /* send Venus a null terminated string */
150 memcpy((char *)(inp) + offset, name, length);
151 *((char *)inp + offset + length) = '\0';
153 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
155 *resfid = outp->coda_lookup.VFid;
156 *type = outp->coda_lookup.vtype;
159 CODA_FREE(inp, insize);
163 int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
166 union inputArgs *inp;
167 union outputArgs *outp;
168 int insize, outsize, error;
169 #ifdef CONFIG_CODA_FS_OLD_API
170 struct coda_cred cred = { 0, };
174 insize = SIZE(release);
177 #ifdef CONFIG_CODA_FS_OLD_API
178 memcpy(&(inp->ih.cred), &cred, sizeof(cred));
183 inp->coda_close.VFid = *fid;
184 inp->coda_close.flags = flags;
186 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
188 CODA_FREE(inp, insize);
192 int venus_open(struct super_block *sb, struct CodaFid *fid,
193 int flags, struct file **fh)
195 union inputArgs *inp;
196 union outputArgs *outp;
197 int insize, outsize, error;
199 insize = SIZE(open_by_fd);
200 UPARG(CODA_OPEN_BY_FD);
202 inp->coda_open_by_fd.VFid = *fid;
203 inp->coda_open_by_fd.flags = flags;
205 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
207 *fh = outp->coda_open_by_fd.fh;
209 CODA_FREE(inp, insize);
213 int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid,
214 const char *name, int length,
215 struct CodaFid *newfid, struct coda_vattr *attrs)
217 union inputArgs *inp;
218 union outputArgs *outp;
219 int insize, outsize, error;
222 offset = INSIZE(mkdir);
223 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(mkdir));
226 inp->coda_mkdir.VFid = *dirfid;
227 inp->coda_mkdir.attr = *attrs;
228 inp->coda_mkdir.name = offset;
229 /* Venus must get null terminated string */
230 memcpy((char *)(inp) + offset, name, length);
231 *((char *)inp + offset + length) = '\0';
233 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
235 *attrs = outp->coda_mkdir.attr;
236 *newfid = outp->coda_mkdir.VFid;
239 CODA_FREE(inp, insize);
244 int venus_rename(struct super_block *sb, struct CodaFid *old_fid,
245 struct CodaFid *new_fid, size_t old_length,
246 size_t new_length, const char *old_name,
247 const char *new_name)
249 union inputArgs *inp;
250 union outputArgs *outp;
251 int insize, outsize, error;
254 offset = INSIZE(rename);
255 insize = max_t(unsigned int, offset + new_length + old_length + 8,
259 inp->coda_rename.sourceFid = *old_fid;
260 inp->coda_rename.destFid = *new_fid;
261 inp->coda_rename.srcname = offset;
263 /* Venus must receive an null terminated string */
264 s = ( old_length & ~0x3) +4; /* round up to word boundary */
265 memcpy((char *)(inp) + offset, old_name, old_length);
266 *((char *)inp + offset + old_length) = '\0';
268 /* another null terminated string for Venus */
270 inp->coda_rename.destname = offset;
271 s = ( new_length & ~0x3) +4; /* round up to word boundary */
272 memcpy((char *)(inp) + offset, new_name, new_length);
273 *((char *)inp + offset + new_length) = '\0';
275 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
277 CODA_FREE(inp, insize);
281 int venus_create(struct super_block *sb, struct CodaFid *dirfid,
282 const char *name, int length, int excl, int mode,
283 struct CodaFid *newfid, struct coda_vattr *attrs)
285 union inputArgs *inp;
286 union outputArgs *outp;
287 int insize, outsize, error;
290 offset = INSIZE(create);
291 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(create));
294 inp->coda_create.VFid = *dirfid;
295 inp->coda_create.attr.va_mode = mode;
296 inp->coda_create.excl = excl;
297 inp->coda_create.mode = mode;
298 inp->coda_create.name = offset;
300 /* Venus must get null terminated string */
301 memcpy((char *)(inp) + offset, name, length);
302 *((char *)inp + offset + length) = '\0';
304 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
306 *attrs = outp->coda_create.attr;
307 *newfid = outp->coda_create.VFid;
310 CODA_FREE(inp, insize);
314 int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid,
315 const char *name, int length)
317 union inputArgs *inp;
318 union outputArgs *outp;
319 int insize, outsize, error;
322 offset = INSIZE(rmdir);
323 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(rmdir));
326 inp->coda_rmdir.VFid = *dirfid;
327 inp->coda_rmdir.name = offset;
328 memcpy((char *)(inp) + offset, name, length);
329 *((char *)inp + offset + length) = '\0';
331 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
333 CODA_FREE(inp, insize);
337 int venus_remove(struct super_block *sb, struct CodaFid *dirfid,
338 const char *name, int length)
340 union inputArgs *inp;
341 union outputArgs *outp;
342 int error=0, insize, outsize, offset;
344 offset = INSIZE(remove);
345 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(remove));
348 inp->coda_remove.VFid = *dirfid;
349 inp->coda_remove.name = offset;
350 memcpy((char *)(inp) + offset, name, length);
351 *((char *)inp + offset + length) = '\0';
353 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
355 CODA_FREE(inp, insize);
359 int venus_readlink(struct super_block *sb, struct CodaFid *fid,
360 char *buffer, int *length)
362 union inputArgs *inp;
363 union outputArgs *outp;
364 int insize, outsize, error;
368 insize = max_t(unsigned int,
369 INSIZE(readlink), OUTSIZE(readlink)+ *length + 1);
370 UPARG(CODA_READLINK);
372 inp->coda_readlink.VFid = *fid;
374 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
376 retlen = outp->coda_readlink.count;
377 if ( retlen > *length )
380 result = (char *)outp + (long)outp->coda_readlink.data;
381 memcpy(buffer, result, retlen);
382 *(buffer + retlen) = '\0';
385 CODA_FREE(inp, insize);
391 int venus_link(struct super_block *sb, struct CodaFid *fid,
392 struct CodaFid *dirfid, const char *name, int len )
394 union inputArgs *inp;
395 union outputArgs *outp;
396 int insize, outsize, error;
399 offset = INSIZE(link);
400 insize = max_t(unsigned int, offset + len + 1, OUTSIZE(link));
403 inp->coda_link.sourceFid = *fid;
404 inp->coda_link.destFid = *dirfid;
405 inp->coda_link.tname = offset;
407 /* make sure strings are null terminated */
408 memcpy((char *)(inp) + offset, name, len);
409 *((char *)inp + offset + len) = '\0';
411 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
413 CODA_FREE(inp, insize);
417 int venus_symlink(struct super_block *sb, struct CodaFid *fid,
418 const char *name, int len,
419 const char *symname, int symlen)
421 union inputArgs *inp;
422 union outputArgs *outp;
423 int insize, outsize, error;
426 offset = INSIZE(symlink);
427 insize = max_t(unsigned int, offset + len + symlen + 8, OUTSIZE(symlink));
430 /* inp->coda_symlink.attr = *tva; XXXXXX */
431 inp->coda_symlink.VFid = *fid;
433 /* Round up to word boundary and null terminate */
434 inp->coda_symlink.srcname = offset;
435 s = ( symlen & ~0x3 ) + 4;
436 memcpy((char *)(inp) + offset, symname, symlen);
437 *((char *)inp + offset + symlen) = '\0';
439 /* Round up to word boundary and null terminate */
441 inp->coda_symlink.tname = offset;
442 s = (len & ~0x3) + 4;
443 memcpy((char *)(inp) + offset, name, len);
444 *((char *)inp + offset + len) = '\0';
446 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
448 CODA_FREE(inp, insize);
452 int venus_fsync(struct super_block *sb, struct CodaFid *fid)
454 union inputArgs *inp;
455 union outputArgs *outp;
456 int insize, outsize, error;
461 inp->coda_fsync.VFid = *fid;
462 error = coda_upcall(coda_vcp(sb), sizeof(union inputArgs),
465 CODA_FREE(inp, insize);
469 int venus_access(struct super_block *sb, struct CodaFid *fid, int mask)
471 union inputArgs *inp;
472 union outputArgs *outp;
473 int insize, outsize, error;
475 insize = SIZE(access);
478 inp->coda_access.VFid = *fid;
479 inp->coda_access.flags = mask;
481 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
483 CODA_FREE(inp, insize);
488 int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
489 unsigned int cmd, struct PioctlData *data)
491 union inputArgs *inp;
492 union outputArgs *outp;
493 int insize, outsize, error;
496 insize = VC_MAXMSGSIZE;
499 /* build packet for Venus */
500 if (data->vi.in_size > VC_MAXDATASIZE) {
505 if (data->vi.out_size > VC_MAXDATASIZE) {
510 inp->coda_ioctl.VFid = *fid;
512 /* the cmd field was mutated by increasing its size field to
513 * reflect the path and follow args. We need to subtract that
514 * out before sending the command to Venus. */
515 inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));
516 iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
517 inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) << 16;
519 /* in->coda_ioctl.rwflag = flag; */
520 inp->coda_ioctl.len = data->vi.in_size;
521 inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
523 /* get the data out of user space */
524 if ( copy_from_user((char*)inp + (long)inp->coda_ioctl.data,
525 data->vi.in, data->vi.in_size) ) {
530 error = coda_upcall(coda_vcp(sb), SIZE(ioctl) + data->vi.in_size,
534 printk("coda_pioctl: Venus returns: %d for %s\n",
535 error, coda_f2s(fid));
539 if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) {
544 /* Copy out the OUT buffer. */
545 if (outp->coda_ioctl.len > data->vi.out_size) {
550 /* Copy out the OUT buffer. */
551 if (copy_to_user(data->vi.out,
552 (char *)outp + (long)outp->coda_ioctl.data,
553 outp->coda_ioctl.len)) {
559 CODA_FREE(inp, insize);
563 int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
565 union inputArgs *inp;
566 union outputArgs *outp;
567 int insize, outsize, error;
569 insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
572 error = coda_upcall(coda_vcp(dentry->d_sb), insize, &outsize, inp);
574 sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
575 sfs->f_bfree = outp->coda_statfs.stat.f_bfree;
576 sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
577 sfs->f_files = outp->coda_statfs.stat.f_files;
578 sfs->f_ffree = outp->coda_statfs.stat.f_ffree;
581 CODA_FREE(inp, insize);
586 * coda_upcall and coda_downcall routines.
588 static void coda_block_signals(sigset_t *old)
590 spin_lock_irq(¤t->sighand->siglock);
591 *old = current->blocked;
593 sigfillset(¤t->blocked);
594 sigdelset(¤t->blocked, SIGKILL);
595 sigdelset(¤t->blocked, SIGSTOP);
596 sigdelset(¤t->blocked, SIGINT);
599 spin_unlock_irq(¤t->sighand->siglock);
602 static void coda_unblock_signals(sigset_t *old)
604 spin_lock_irq(¤t->sighand->siglock);
605 current->blocked = *old;
607 spin_unlock_irq(¤t->sighand->siglock);
610 /* Don't allow signals to interrupt the following upcalls before venus
612 * - CODA_CLOSE or CODA_RELEASE upcall (to avoid reference count problems)
613 * - CODA_STORE (to avoid data loss)
615 #define CODA_INTERRUPTIBLE(r) (!coda_hard && \
616 (((r)->uc_opcode != CODA_CLOSE && \
617 (r)->uc_opcode != CODA_STORE && \
618 (r)->uc_opcode != CODA_RELEASE) || \
619 (r)->uc_flags & REQ_READ))
621 static inline void coda_waitfor_upcall(struct upc_req *req)
623 DECLARE_WAITQUEUE(wait, current);
624 unsigned long timeout = jiffies + coda_timeout * HZ;
628 coda_block_signals(&old);
631 add_wait_queue(&req->uc_sleep, &wait);
633 if (CODA_INTERRUPTIBLE(req))
634 set_current_state(TASK_INTERRUPTIBLE);
636 set_current_state(TASK_UNINTERRUPTIBLE);
639 if (req->uc_flags & (REQ_WRITE | REQ_ABORT))
642 if (blocked && time_after(jiffies, timeout) &&
643 CODA_INTERRUPTIBLE(req))
645 coda_unblock_signals(&old);
649 if (signal_pending(current)) {
650 list_del(&req->uc_chain);
655 schedule_timeout(HZ);
660 coda_unblock_signals(&old);
662 remove_wait_queue(&req->uc_sleep, &wait);
663 set_current_state(TASK_RUNNING);
668 * coda_upcall will return an error in the case of
669 * failed communication with Venus _or_ will peek at Venus
670 * reply and return Venus' error.
672 * As venus has 2 types of errors, normal errors (positive) and internal
673 * errors (negative), normal errors are negated, while internal errors
674 * are all mapped to -EINTR, while showing a nice warning message. (jh)
676 static int coda_upcall(struct venus_comm *vcp,
677 int inSize, int *outSize,
678 union inputArgs *buffer)
680 union outputArgs *out;
681 union inputArgs *sig_inputArgs;
682 struct upc_req *req, *sig_req;
685 if (!vcp->vc_inuse) {
686 printk(KERN_NOTICE "coda: Venus dead, not sending upcall\n");
690 /* Format the request message. */
691 req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
695 req->uc_data = (void *)buffer;
697 req->uc_inSize = inSize;
698 req->uc_outSize = *outSize ? *outSize : inSize;
699 req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
700 req->uc_unique = ++vcp->vc_seq;
701 init_waitqueue_head(&req->uc_sleep);
703 /* Fill in the common input args. */
704 ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
706 /* Append msg to pending queue and poke Venus. */
707 list_add_tail(&req->uc_chain, &vcp->vc_pending);
709 wake_up_interruptible(&vcp->vc_waitq);
710 /* We can be interrupted while we wait for Venus to process
711 * our request. If the interrupt occurs before Venus has read
712 * the request, we dequeue and return. If it occurs after the
713 * read but before the reply, we dequeue, send a signal
714 * message, and return. If it occurs after the reply we ignore
715 * it. In no case do we want to restart the syscall. If it
716 * was interrupted by a venus shutdown (psdev_close), return
719 /* Go to sleep. Wake up on signals only after the timeout. */
720 coda_waitfor_upcall(req);
722 /* Op went through, interrupt or not... */
723 if (req->uc_flags & REQ_WRITE) {
724 out = (union outputArgs *)req->uc_data;
725 /* here we map positive Venus errors to kernel errors */
726 error = -out->oh.result;
727 *outSize = req->uc_outSize;
732 if ((req->uc_flags & REQ_ABORT) || !signal_pending(current)) {
733 printk(KERN_WARNING "coda: Unexpected interruption.\n");
737 /* Interrupted before venus read it. */
738 if (!(req->uc_flags & REQ_READ))
741 /* Venus saw the upcall, make sure we can send interrupt signal */
742 if (!vcp->vc_inuse) {
743 printk(KERN_INFO "coda: Venus dead, not sending signal.\n");
748 sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
749 if (!sig_req) goto exit;
751 CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
752 if (!sig_req->uc_data) {
758 sig_inputArgs = (union inputArgs *)sig_req->uc_data;
759 sig_inputArgs->ih.opcode = CODA_SIGNAL;
760 sig_inputArgs->ih.unique = req->uc_unique;
762 sig_req->uc_flags = REQ_ASYNC;
763 sig_req->uc_opcode = sig_inputArgs->ih.opcode;
764 sig_req->uc_unique = sig_inputArgs->ih.unique;
765 sig_req->uc_inSize = sizeof(struct coda_in_hdr);
766 sig_req->uc_outSize = sizeof(struct coda_in_hdr);
768 /* insert at head of queue! */
769 list_add(&(sig_req->uc_chain), &vcp->vc_pending);
770 wake_up_interruptible(&vcp->vc_waitq);
778 The statements below are part of the Coda opportunistic
779 programming -- taken from the Mach/BSD kernel code for Coda.
780 You don't get correct semantics by stating what needs to be
781 done without guaranteeing the invariants needed for it to happen.
782 When will be have time to find out what exactly is going on? (pjb)
787 * There are 7 cases where cache invalidations occur. The semantics
788 * of each is listed here:
790 * CODA_FLUSH -- flush all entries from the name cache and the cnode cache.
791 * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
792 * This call is a result of token expiration.
794 * The next arise as the result of callbacks on a file or directory.
795 * CODA_ZAPFILE -- flush the cached attributes for a file.
797 * CODA_ZAPDIR -- flush the attributes for the dir and
798 * force a new lookup for all the children
802 * The next is a result of Venus detecting an inconsistent file.
803 * CODA_PURGEFID -- flush the attribute for the file
804 * purge it and its children from the dcache
806 * The last allows Venus to replace local fids with global ones
807 * during reintegration.
809 * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
811 int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
813 struct inode *inode = NULL;
814 struct CodaFid *fid, *newfid;
816 /* Handle invalidation requests. */
817 if ( !sb || !sb->s_root)
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);
829 coda_cache_clear_all(sb);
833 fid = &out->coda_zapdir.CodaFid;
834 inode = coda_fid_to_inode(fid, sb);
836 coda_flag_inode_children(inode, C_PURGE);
837 coda_flag_inode(inode, C_VATTR);
842 fid = &out->coda_zapfile.CodaFid;
843 inode = coda_fid_to_inode(fid, sb);
845 coda_flag_inode(inode, C_VATTR);
849 fid = &out->coda_purgefid.CodaFid;
850 inode = coda_fid_to_inode(fid, sb);
852 coda_flag_inode_children(inode, C_PURGE);
854 /* catch the dentries later if some are still busy */
855 coda_flag_inode(inode, C_PURGE);
856 d_prune_aliases(inode);
862 fid = &out->coda_replace.OldFid;
863 newfid = &out->coda_replace.NewFid;
864 inode = coda_fid_to_inode(fid, sb);
866 coda_replace_fid(inode, fid, newfid);