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 <asm/signal.h>
19 #include <linux/signal.h>
21 #include <linux/types.h>
22 #include <linux/kernel.h>
24 #include <linux/time.h>
26 #include <linux/file.h>
27 #include <linux/stat.h>
28 #include <linux/errno.h>
29 #include <linux/string.h>
30 #include <asm/uaccess.h>
31 #include <linux/vmalloc.h>
32 #include <linux/vfs.h>
34 #include <linux/coda.h>
35 #include <linux/coda_linux.h>
36 #include <linux/coda_psdev.h>
37 #include <linux/coda_fs_i.h>
38 #include <linux/coda_cache.h>
39 #include <linux/coda_proc.h>
41 #define upc_alloc() kmalloc(sizeof(struct upc_req), GFP_KERNEL)
42 #define upc_free(r) kfree(r)
44 static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize,
45 union inputArgs *buffer);
47 static void *alloc_upcall(int opcode, int size)
51 CODA_ALLOC(inp, union inputArgs *, size);
53 return ERR_PTR(-ENOMEM);
55 inp->ih.opcode = opcode;
56 inp->ih.pid = current->pid;
57 inp->ih.pgid = process_group(current);
58 #ifdef CODA_FS_OLD_API
59 memset(&inp->ih.cred, 0, sizeof(struct coda_cred));
60 inp->ih.cred.cr_fsuid = current->fsuid;
62 inp->ih.uid = current->fsuid;
69 inp = (union inputArgs *)alloc_upcall(op, insize); \
70 if (IS_ERR(inp)) { return PTR_ERR(inp); }\
71 outp = (union outputArgs *)(inp); \
75 #define INSIZE(tag) sizeof(struct coda_ ## tag ## _in)
76 #define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out)
77 #define SIZE(tag) max_t(unsigned int, INSIZE(tag), OUTSIZE(tag))
81 int venus_rootfid(struct super_block *sb, struct CodaFid *fidp)
84 union outputArgs *outp;
85 int insize, outsize, error;
90 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
93 printk("coda_get_rootfid: error %d\n", error);
95 *fidp = outp->coda_root.VFid;
98 CODA_FREE(inp, insize);
102 int venus_getattr(struct super_block *sb, struct CodaFid *fid,
103 struct coda_vattr *attr)
105 union inputArgs *inp;
106 union outputArgs *outp;
107 int insize, outsize, error;
109 insize = SIZE(getattr);
111 inp->coda_getattr.VFid = *fid;
113 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
115 *attr = outp->coda_getattr.attr;
117 CODA_FREE(inp, insize);
121 int venus_setattr(struct super_block *sb, struct CodaFid *fid,
122 struct coda_vattr *vattr)
124 union inputArgs *inp;
125 union outputArgs *outp;
126 int insize, outsize, error;
128 insize = SIZE(setattr);
131 inp->coda_setattr.VFid = *fid;
132 inp->coda_setattr.attr = *vattr;
134 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
136 CODA_FREE(inp, insize);
140 int venus_lookup(struct super_block *sb, struct CodaFid *fid,
141 const char *name, int length, int * type,
142 struct CodaFid *resfid)
144 union inputArgs *inp;
145 union outputArgs *outp;
146 int insize, outsize, error;
149 offset = INSIZE(lookup);
150 insize = max_t(unsigned int, offset + length +1, OUTSIZE(lookup));
153 inp->coda_lookup.VFid = *fid;
154 inp->coda_lookup.name = offset;
155 inp->coda_lookup.flags = CLU_CASE_SENSITIVE;
156 /* send Venus a null terminated string */
157 memcpy((char *)(inp) + offset, name, length);
158 *((char *)inp + offset + length) = '\0';
160 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
162 *resfid = outp->coda_lookup.VFid;
163 *type = outp->coda_lookup.vtype;
165 CODA_FREE(inp, insize);
169 int venus_store(struct super_block *sb, struct CodaFid *fid, int flags,
172 union inputArgs *inp;
173 union outputArgs *outp;
174 int insize, outsize, error;
175 #ifdef CODA_FS_OLD_API
176 struct coda_cred cred = { 0, };
180 insize = SIZE(store);
183 #ifdef CODA_FS_OLD_API
184 memcpy(&(inp->ih.cred), &cred, sizeof(cred));
189 inp->coda_store.VFid = *fid;
190 inp->coda_store.flags = flags;
192 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
194 CODA_FREE(inp, insize);
198 int venus_release(struct super_block *sb, struct CodaFid *fid, int flags)
200 union inputArgs *inp;
201 union outputArgs *outp;
202 int insize, outsize, error;
204 insize = SIZE(release);
207 inp->coda_release.VFid = *fid;
208 inp->coda_release.flags = flags;
210 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
212 CODA_FREE(inp, insize);
216 int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
219 union inputArgs *inp;
220 union outputArgs *outp;
221 int insize, outsize, error;
222 #ifdef CODA_FS_OLD_API
223 struct coda_cred cred = { 0, };
227 insize = SIZE(release);
230 #ifdef CODA_FS_OLD_API
231 memcpy(&(inp->ih.cred), &cred, sizeof(cred));
236 inp->coda_close.VFid = *fid;
237 inp->coda_close.flags = flags;
239 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
241 CODA_FREE(inp, insize);
245 int venus_open(struct super_block *sb, struct CodaFid *fid,
246 int flags, struct file **fh)
248 union inputArgs *inp;
249 union outputArgs *outp;
250 int insize, outsize, error;
252 insize = SIZE(open_by_fd);
253 UPARG(CODA_OPEN_BY_FD);
255 inp->coda_open.VFid = *fid;
256 inp->coda_open.flags = flags;
258 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
260 *fh = outp->coda_open_by_fd.fh;
262 CODA_FREE(inp, insize);
266 int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid,
267 const char *name, int length,
268 struct CodaFid *newfid, struct coda_vattr *attrs)
270 union inputArgs *inp;
271 union outputArgs *outp;
272 int insize, outsize, error;
275 offset = INSIZE(mkdir);
276 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(mkdir));
279 inp->coda_mkdir.VFid = *dirfid;
280 inp->coda_mkdir.attr = *attrs;
281 inp->coda_mkdir.name = offset;
282 /* Venus must get null terminated string */
283 memcpy((char *)(inp) + offset, name, length);
284 *((char *)inp + offset + length) = '\0';
286 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
288 *attrs = outp->coda_mkdir.attr;
289 *newfid = outp->coda_mkdir.VFid;
291 CODA_FREE(inp, insize);
296 int venus_rename(struct super_block *sb, struct CodaFid *old_fid,
297 struct CodaFid *new_fid, size_t old_length,
298 size_t new_length, const char *old_name,
299 const char *new_name)
301 union inputArgs *inp;
302 union outputArgs *outp;
303 int insize, outsize, error;
306 offset = INSIZE(rename);
307 insize = max_t(unsigned int, offset + new_length + old_length + 8,
311 inp->coda_rename.sourceFid = *old_fid;
312 inp->coda_rename.destFid = *new_fid;
313 inp->coda_rename.srcname = offset;
315 /* Venus must receive an null terminated string */
316 s = ( old_length & ~0x3) +4; /* round up to word boundary */
317 memcpy((char *)(inp) + offset, old_name, old_length);
318 *((char *)inp + offset + old_length) = '\0';
320 /* another null terminated string for Venus */
322 inp->coda_rename.destname = offset;
323 s = ( new_length & ~0x3) +4; /* round up to word boundary */
324 memcpy((char *)(inp) + offset, new_name, new_length);
325 *((char *)inp + offset + new_length) = '\0';
327 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
329 CODA_FREE(inp, insize);
333 int venus_create(struct super_block *sb, struct CodaFid *dirfid,
334 const char *name, int length, int excl, int mode, dev_t rdev,
335 struct CodaFid *newfid, struct coda_vattr *attrs)
337 union inputArgs *inp;
338 union outputArgs *outp;
339 int insize, outsize, error;
342 offset = INSIZE(create);
343 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(create));
346 inp->coda_create.VFid = *dirfid;
347 inp->coda_create.attr.va_mode = mode;
348 inp->coda_create.attr.va_rdev = huge_encode_dev(rdev);
349 inp->coda_create.excl = excl;
350 inp->coda_create.mode = mode;
351 inp->coda_create.name = offset;
353 /* Venus must get null terminated string */
354 memcpy((char *)(inp) + offset, name, length);
355 *((char *)inp + offset + length) = '\0';
357 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
359 *attrs = outp->coda_create.attr;
360 *newfid = outp->coda_create.VFid;
362 CODA_FREE(inp, insize);
366 int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid,
367 const char *name, int length)
369 union inputArgs *inp;
370 union outputArgs *outp;
371 int insize, outsize, error;
374 offset = INSIZE(rmdir);
375 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(rmdir));
378 inp->coda_rmdir.VFid = *dirfid;
379 inp->coda_rmdir.name = offset;
380 memcpy((char *)(inp) + offset, name, length);
381 *((char *)inp + offset + length) = '\0';
383 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
385 CODA_FREE(inp, insize);
389 int venus_remove(struct super_block *sb, struct CodaFid *dirfid,
390 const char *name, int length)
392 union inputArgs *inp;
393 union outputArgs *outp;
394 int error=0, insize, outsize, offset;
396 offset = INSIZE(remove);
397 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(remove));
400 inp->coda_remove.VFid = *dirfid;
401 inp->coda_remove.name = offset;
402 memcpy((char *)(inp) + offset, name, length);
403 *((char *)inp + offset + length) = '\0';
405 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
407 CODA_FREE(inp, insize);
411 int venus_readlink(struct super_block *sb, struct CodaFid *fid,
412 char *buffer, int *length)
414 union inputArgs *inp;
415 union outputArgs *outp;
416 int insize, outsize, error;
420 insize = max_t(unsigned int,
421 INSIZE(readlink), OUTSIZE(readlink)+ *length + 1);
422 UPARG(CODA_READLINK);
424 inp->coda_readlink.VFid = *fid;
426 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
429 retlen = outp->coda_readlink.count;
430 if ( retlen > *length )
433 result = (char *)outp + (long)outp->coda_readlink.data;
434 memcpy(buffer, result, retlen);
435 *(buffer + retlen) = '\0';
438 CODA_FREE(inp, insize);
444 int venus_link(struct super_block *sb, struct CodaFid *fid,
445 struct CodaFid *dirfid, const char *name, int len )
447 union inputArgs *inp;
448 union outputArgs *outp;
449 int insize, outsize, error;
452 offset = INSIZE(link);
453 insize = max_t(unsigned int, offset + len + 1, OUTSIZE(link));
456 inp->coda_link.sourceFid = *fid;
457 inp->coda_link.destFid = *dirfid;
458 inp->coda_link.tname = offset;
460 /* make sure strings are null terminated */
461 memcpy((char *)(inp) + offset, name, len);
462 *((char *)inp + offset + len) = '\0';
464 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
466 CODA_FREE(inp, insize);
470 int venus_symlink(struct super_block *sb, struct CodaFid *fid,
471 const char *name, int len,
472 const char *symname, int symlen)
474 union inputArgs *inp;
475 union outputArgs *outp;
476 int insize, outsize, error;
479 offset = INSIZE(symlink);
480 insize = max_t(unsigned int, offset + len + symlen + 8, OUTSIZE(symlink));
483 /* inp->coda_symlink.attr = *tva; XXXXXX */
484 inp->coda_symlink.VFid = *fid;
486 /* Round up to word boundary and null terminate */
487 inp->coda_symlink.srcname = offset;
488 s = ( symlen & ~0x3 ) + 4;
489 memcpy((char *)(inp) + offset, symname, symlen);
490 *((char *)inp + offset + symlen) = '\0';
492 /* Round up to word boundary and null terminate */
494 inp->coda_symlink.tname = offset;
495 s = (len & ~0x3) + 4;
496 memcpy((char *)(inp) + offset, name, len);
497 *((char *)inp + offset + len) = '\0';
499 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
501 CODA_FREE(inp, insize);
505 int venus_fsync(struct super_block *sb, struct CodaFid *fid)
507 union inputArgs *inp;
508 union outputArgs *outp;
509 int insize, outsize, error;
514 inp->coda_fsync.VFid = *fid;
515 error = coda_upcall(coda_sbp(sb), sizeof(union inputArgs),
518 CODA_FREE(inp, insize);
522 int venus_access(struct super_block *sb, struct CodaFid *fid, int mask)
524 union inputArgs *inp;
525 union outputArgs *outp;
526 int insize, outsize, error;
528 insize = SIZE(access);
531 inp->coda_access.VFid = *fid;
532 inp->coda_access.flags = mask;
534 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
536 CODA_FREE(inp, insize);
541 int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
542 unsigned int cmd, struct PioctlData *data)
544 union inputArgs *inp;
545 union outputArgs *outp;
546 int insize, outsize, error;
549 insize = VC_MAXMSGSIZE;
552 /* build packet for Venus */
553 if (data->vi.in_size > VC_MAXDATASIZE) {
558 inp->coda_ioctl.VFid = *fid;
560 /* the cmd field was mutated by increasing its size field to
561 * reflect the path and follow args. We need to subtract that
562 * out before sending the command to Venus. */
563 inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));
564 iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
565 inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) << 16;
567 /* in->coda_ioctl.rwflag = flag; */
568 inp->coda_ioctl.len = data->vi.in_size;
569 inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
571 /* get the data out of user space */
572 if ( copy_from_user((char*)inp + (long)inp->coda_ioctl.data,
573 data->vi.in, data->vi.in_size) ) {
578 error = coda_upcall(coda_sbp(sb), SIZE(ioctl) + data->vi.in_size,
582 printk("coda_pioctl: Venus returns: %d for %s\n",
583 error, coda_f2s(fid));
587 /* Copy out the OUT buffer. */
588 if (outp->coda_ioctl.len > data->vi.out_size) {
591 if (copy_to_user(data->vi.out,
592 (char *)outp + (long)outp->coda_ioctl.data,
593 data->vi.out_size)) {
600 CODA_FREE(inp, insize);
604 int venus_statfs(struct super_block *sb, struct kstatfs *sfs)
606 union inputArgs *inp;
607 union outputArgs *outp;
608 int insize, outsize, error;
610 insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
613 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
616 sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
617 sfs->f_bfree = outp->coda_statfs.stat.f_bfree;
618 sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
619 sfs->f_files = outp->coda_statfs.stat.f_files;
620 sfs->f_ffree = outp->coda_statfs.stat.f_ffree;
622 printk("coda_statfs: Venus returns: %d\n", error);
625 CODA_FREE(inp, insize);
630 * coda_upcall and coda_downcall routines.
634 static inline void coda_waitfor_upcall(struct upc_req *vmp,
635 struct venus_comm *vcommp)
637 DECLARE_WAITQUEUE(wait, current);
639 vmp->uc_posttime = jiffies;
641 add_wait_queue(&vmp->uc_sleep, &wait);
643 if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE )
644 set_current_state(TASK_INTERRUPTIBLE);
646 set_current_state(TASK_UNINTERRUPTIBLE);
649 if ( !vcommp->vc_inuse )
653 if ( vmp->uc_flags & ( REQ_WRITE | REQ_ABORT ) )
656 if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE && signal_pending(current) ) {
657 /* if this process really wants to die, let it go */
658 if ( sigismember(&(current->pending.signal), SIGKILL) ||
659 sigismember(&(current->pending.signal), SIGINT) )
661 /* signal is present: after timeout always return
662 really smart idea, probably useless ... */
663 if ( jiffies - vmp->uc_posttime > coda_timeout * HZ )
668 remove_wait_queue(&vmp->uc_sleep, &wait);
669 set_current_state(TASK_RUNNING);
676 * coda_upcall will return an error in the case of
677 * failed communication with Venus _or_ will peek at Venus
678 * reply and return Venus' error.
680 * As venus has 2 types of errors, normal errors (positive) and internal
681 * errors (negative), normal errors are negated, while internal errors
682 * are all mapped to -EINTR, while showing a nice warning message. (jh)
685 static int coda_upcall(struct coda_sb_info *sbi,
686 int inSize, int *outSize,
687 union inputArgs *buffer)
689 struct venus_comm *vcommp;
690 union outputArgs *out;
694 vcommp = sbi->sbi_vcomm;
695 if ( !vcommp->vc_inuse ) {
696 printk("No pseudo device in upcall comms at %p\n", vcommp);
700 /* Format the request message. */
703 printk("Failed to allocate upc_req structure\n");
706 req->uc_data = (void *)buffer;
708 req->uc_inSize = inSize;
709 req->uc_outSize = *outSize ? *outSize : inSize;
710 req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
711 req->uc_unique = ++vcommp->vc_seq;
712 init_waitqueue_head(&req->uc_sleep);
714 /* Fill in the common input args. */
715 ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
717 /* Append msg to pending queue and poke Venus. */
718 list_add(&(req->uc_chain), vcommp->vc_pending.prev);
720 wake_up_interruptible(&vcommp->vc_waitq);
721 /* We can be interrupted while we wait for Venus to process
722 * our request. If the interrupt occurs before Venus has read
723 * the request, we dequeue and return. If it occurs after the
724 * read but before the reply, we dequeue, send a signal
725 * message, and return. If it occurs after the reply we ignore
726 * it. In no case do we want to restart the syscall. If it
727 * was interrupted by a venus shutdown (psdev_close), return
730 /* Go to sleep. Wake up on signals only after the timeout. */
731 coda_waitfor_upcall(req, vcommp);
733 if (vcommp->vc_inuse) { /* i.e. Venus is still alive */
734 /* Op went through, interrupt or not... */
735 if (req->uc_flags & REQ_WRITE) {
736 out = (union outputArgs *)req->uc_data;
737 /* here we map positive Venus errors to kernel errors */
738 error = -out->oh.result;
739 *outSize = req->uc_outSize;
742 if ( !(req->uc_flags & REQ_READ) && signal_pending(current)) {
743 /* Interrupted before venus read it. */
744 list_del(&(req->uc_chain));
745 /* perhaps the best way to convince the app to
750 if ( (req->uc_flags & REQ_READ) && signal_pending(current) ) {
751 /* interrupted after Venus did its read, send signal */
752 union inputArgs *sig_inputArgs;
753 struct upc_req *sig_req;
755 list_del(&(req->uc_chain));
757 sig_req = upc_alloc();
758 if (!sig_req) goto exit;
760 CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
761 if (!sig_req->uc_data) {
767 sig_inputArgs = (union inputArgs *)sig_req->uc_data;
768 sig_inputArgs->ih.opcode = CODA_SIGNAL;
769 sig_inputArgs->ih.unique = req->uc_unique;
771 sig_req->uc_flags = REQ_ASYNC;
772 sig_req->uc_opcode = sig_inputArgs->ih.opcode;
773 sig_req->uc_unique = sig_inputArgs->ih.unique;
774 sig_req->uc_inSize = sizeof(struct coda_in_hdr);
775 sig_req->uc_outSize = sizeof(struct coda_in_hdr);
777 /* insert at head of queue! */
778 list_add(&(sig_req->uc_chain), &vcommp->vc_pending);
779 wake_up_interruptible(&vcommp->vc_waitq);
781 printk("Coda: Strange interruption..\n");
784 } else { /* If venus died i.e. !VC_OPEN(vcommp) */
785 printk("coda_upcall: Venus dead on (op,un) (%d.%d) flags %d\n",
786 req->uc_opcode, req->uc_unique, req->uc_flags);
796 The statements below are part of the Coda opportunistic
797 programming -- taken from the Mach/BSD kernel code for Coda.
798 You don't get correct semantics by stating what needs to be
799 done without guaranteeing the invariants needed for it to happen.
800 When will be have time to find out what exactly is going on? (pjb)
805 * There are 7 cases where cache invalidations occur. The semantics
806 * of each is listed here:
808 * CODA_FLUSH -- flush all entries from the name cache and the cnode cache.
809 * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
810 * This call is a result of token expiration.
812 * The next arise as the result of callbacks on a file or directory.
813 * CODA_ZAPFILE -- flush the cached attributes for a file.
815 * CODA_ZAPDIR -- flush the attributes for the dir and
816 * force a new lookup for all the children
820 * The next is a result of Venus detecting an inconsistent file.
821 * CODA_PURGEFID -- flush the attribute for the file
822 * purge it and its children from the dcache
824 * The last allows Venus to replace local fids with global ones
825 * during reintegration.
827 * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
829 int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
831 /* Handle invalidation requests. */
832 if ( !sb || !sb->s_root || !sb->s_root->d_inode)
838 coda_cache_clear_all(sb);
839 shrink_dcache_sb(sb);
840 coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
844 case CODA_PURGEUSER : {
845 coda_cache_clear_all(sb);
851 struct CodaFid *fid = &out->coda_zapdir.CodaFid;
853 inode = coda_fid_to_inode(fid, sb);
855 coda_flag_inode_children(inode, C_PURGE);
856 coda_flag_inode(inode, C_VATTR);
863 case CODA_ZAPFILE : {
865 struct CodaFid *fid = &out->coda_zapfile.CodaFid;
866 inode = coda_fid_to_inode(fid, sb);
868 coda_flag_inode(inode, C_VATTR);
874 case CODA_PURGEFID : {
876 struct CodaFid *fid = &out->coda_purgefid.CodaFid;
877 inode = coda_fid_to_inode(fid, sb);
879 coda_flag_inode_children(inode, C_PURGE);
881 /* catch the dentries later if some are still busy */
882 coda_flag_inode(inode, C_PURGE);
883 d_prune_aliases(inode);
890 case CODA_REPLACE : {
892 struct CodaFid *oldfid = &out->coda_replace.OldFid;
893 struct CodaFid *newfid = &out->coda_replace.NewFid;
894 inode = coda_fid_to_inode(oldfid, sb);
896 coda_replace_fid(inode, oldfid, newfid);