0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #include <linux/signal.h>
0019 #include <linux/sched/signal.h>
0020 #include <linux/types.h>
0021 #include <linux/kernel.h>
0022 #include <linux/mm.h>
0023 #include <linux/time.h>
0024 #include <linux/fs.h>
0025 #include <linux/file.h>
0026 #include <linux/stat.h>
0027 #include <linux/errno.h>
0028 #include <linux/string.h>
0029 #include <linux/slab.h>
0030 #include <linux/mutex.h>
0031 #include <linux/uaccess.h>
0032 #include <linux/vmalloc.h>
0033 #include <linux/vfs.h>
0034
0035 #include <linux/coda.h>
0036 #include "coda_psdev.h"
0037 #include "coda_linux.h"
0038 #include "coda_cache.h"
0039
0040 #include "coda_int.h"
0041
0042 static int coda_upcall(struct venus_comm *vc, int inSize, int *outSize,
0043 union inputArgs *buffer);
0044
0045 static void *alloc_upcall(int opcode, int size)
0046 {
0047 union inputArgs *inp;
0048
0049 inp = kvzalloc(size, GFP_KERNEL);
0050 if (!inp)
0051 return ERR_PTR(-ENOMEM);
0052
0053 inp->ih.opcode = opcode;
0054 inp->ih.pid = task_pid_nr_ns(current, &init_pid_ns);
0055 inp->ih.pgid = task_pgrp_nr_ns(current, &init_pid_ns);
0056 inp->ih.uid = from_kuid(&init_user_ns, current_fsuid());
0057
0058 return (void*)inp;
0059 }
0060
0061 #define UPARG(op)\
0062 do {\
0063 inp = (union inputArgs *)alloc_upcall(op, insize); \
0064 if (IS_ERR(inp)) { return PTR_ERR(inp); }\
0065 outp = (union outputArgs *)(inp); \
0066 outsize = insize; \
0067 } while (0)
0068
0069 #define INSIZE(tag) sizeof(struct coda_ ## tag ## _in)
0070 #define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out)
0071 #define SIZE(tag) max_t(unsigned int, INSIZE(tag), OUTSIZE(tag))
0072
0073
0074
0075 int venus_rootfid(struct super_block *sb, struct CodaFid *fidp)
0076 {
0077 union inputArgs *inp;
0078 union outputArgs *outp;
0079 int insize, outsize, error;
0080
0081 insize = SIZE(root);
0082 UPARG(CODA_ROOT);
0083
0084 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0085 if (!error)
0086 *fidp = outp->coda_root.VFid;
0087
0088 kvfree(inp);
0089 return error;
0090 }
0091
0092 int venus_getattr(struct super_block *sb, struct CodaFid *fid,
0093 struct coda_vattr *attr)
0094 {
0095 union inputArgs *inp;
0096 union outputArgs *outp;
0097 int insize, outsize, error;
0098
0099 insize = SIZE(getattr);
0100 UPARG(CODA_GETATTR);
0101 inp->coda_getattr.VFid = *fid;
0102
0103 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0104 if (!error)
0105 *attr = outp->coda_getattr.attr;
0106
0107 kvfree(inp);
0108 return error;
0109 }
0110
0111 int venus_setattr(struct super_block *sb, struct CodaFid *fid,
0112 struct coda_vattr *vattr)
0113 {
0114 union inputArgs *inp;
0115 union outputArgs *outp;
0116 int insize, outsize, error;
0117
0118 insize = SIZE(setattr);
0119 UPARG(CODA_SETATTR);
0120
0121 inp->coda_setattr.VFid = *fid;
0122 inp->coda_setattr.attr = *vattr;
0123
0124 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0125
0126 kvfree(inp);
0127 return error;
0128 }
0129
0130 int venus_lookup(struct super_block *sb, struct CodaFid *fid,
0131 const char *name, int length, int * type,
0132 struct CodaFid *resfid)
0133 {
0134 union inputArgs *inp;
0135 union outputArgs *outp;
0136 int insize, outsize, error;
0137 int offset;
0138
0139 offset = INSIZE(lookup);
0140 insize = max_t(unsigned int, offset + length +1, OUTSIZE(lookup));
0141 UPARG(CODA_LOOKUP);
0142
0143 inp->coda_lookup.VFid = *fid;
0144 inp->coda_lookup.name = offset;
0145 inp->coda_lookup.flags = CLU_CASE_SENSITIVE;
0146
0147 memcpy((char *)(inp) + offset, name, length);
0148 *((char *)inp + offset + length) = '\0';
0149
0150 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0151 if (!error) {
0152 *resfid = outp->coda_lookup.VFid;
0153 *type = outp->coda_lookup.vtype;
0154 }
0155
0156 kvfree(inp);
0157 return error;
0158 }
0159
0160 int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
0161 kuid_t uid)
0162 {
0163 union inputArgs *inp;
0164 union outputArgs *outp;
0165 int insize, outsize, error;
0166
0167 insize = SIZE(release);
0168 UPARG(CODA_CLOSE);
0169
0170 inp->ih.uid = from_kuid(&init_user_ns, uid);
0171 inp->coda_close.VFid = *fid;
0172 inp->coda_close.flags = flags;
0173
0174 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0175
0176 kvfree(inp);
0177 return error;
0178 }
0179
0180 int venus_open(struct super_block *sb, struct CodaFid *fid,
0181 int flags, struct file **fh)
0182 {
0183 union inputArgs *inp;
0184 union outputArgs *outp;
0185 int insize, outsize, error;
0186
0187 insize = SIZE(open_by_fd);
0188 UPARG(CODA_OPEN_BY_FD);
0189
0190 inp->coda_open_by_fd.VFid = *fid;
0191 inp->coda_open_by_fd.flags = flags;
0192
0193 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0194 if (!error)
0195 *fh = outp->coda_open_by_fd.fh;
0196
0197 kvfree(inp);
0198 return error;
0199 }
0200
0201 int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid,
0202 const char *name, int length,
0203 struct CodaFid *newfid, struct coda_vattr *attrs)
0204 {
0205 union inputArgs *inp;
0206 union outputArgs *outp;
0207 int insize, outsize, error;
0208 int offset;
0209
0210 offset = INSIZE(mkdir);
0211 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(mkdir));
0212 UPARG(CODA_MKDIR);
0213
0214 inp->coda_mkdir.VFid = *dirfid;
0215 inp->coda_mkdir.attr = *attrs;
0216 inp->coda_mkdir.name = offset;
0217
0218 memcpy((char *)(inp) + offset, name, length);
0219 *((char *)inp + offset + length) = '\0';
0220
0221 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0222 if (!error) {
0223 *attrs = outp->coda_mkdir.attr;
0224 *newfid = outp->coda_mkdir.VFid;
0225 }
0226
0227 kvfree(inp);
0228 return error;
0229 }
0230
0231
0232 int venus_rename(struct super_block *sb, struct CodaFid *old_fid,
0233 struct CodaFid *new_fid, size_t old_length,
0234 size_t new_length, const char *old_name,
0235 const char *new_name)
0236 {
0237 union inputArgs *inp;
0238 union outputArgs *outp;
0239 int insize, outsize, error;
0240 int offset, s;
0241
0242 offset = INSIZE(rename);
0243 insize = max_t(unsigned int, offset + new_length + old_length + 8,
0244 OUTSIZE(rename));
0245 UPARG(CODA_RENAME);
0246
0247 inp->coda_rename.sourceFid = *old_fid;
0248 inp->coda_rename.destFid = *new_fid;
0249 inp->coda_rename.srcname = offset;
0250
0251
0252 s = ( old_length & ~0x3) +4;
0253 memcpy((char *)(inp) + offset, old_name, old_length);
0254 *((char *)inp + offset + old_length) = '\0';
0255
0256
0257 offset += s;
0258 inp->coda_rename.destname = offset;
0259 s = ( new_length & ~0x3) +4;
0260 memcpy((char *)(inp) + offset, new_name, new_length);
0261 *((char *)inp + offset + new_length) = '\0';
0262
0263 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0264
0265 kvfree(inp);
0266 return error;
0267 }
0268
0269 int venus_create(struct super_block *sb, struct CodaFid *dirfid,
0270 const char *name, int length, int excl, int mode,
0271 struct CodaFid *newfid, struct coda_vattr *attrs)
0272 {
0273 union inputArgs *inp;
0274 union outputArgs *outp;
0275 int insize, outsize, error;
0276 int offset;
0277
0278 offset = INSIZE(create);
0279 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(create));
0280 UPARG(CODA_CREATE);
0281
0282 inp->coda_create.VFid = *dirfid;
0283 inp->coda_create.attr.va_mode = mode;
0284 inp->coda_create.excl = excl;
0285 inp->coda_create.mode = mode;
0286 inp->coda_create.name = offset;
0287
0288
0289 memcpy((char *)(inp) + offset, name, length);
0290 *((char *)inp + offset + length) = '\0';
0291
0292 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0293 if (!error) {
0294 *attrs = outp->coda_create.attr;
0295 *newfid = outp->coda_create.VFid;
0296 }
0297
0298 kvfree(inp);
0299 return error;
0300 }
0301
0302 int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid,
0303 const char *name, int length)
0304 {
0305 union inputArgs *inp;
0306 union outputArgs *outp;
0307 int insize, outsize, error;
0308 int offset;
0309
0310 offset = INSIZE(rmdir);
0311 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(rmdir));
0312 UPARG(CODA_RMDIR);
0313
0314 inp->coda_rmdir.VFid = *dirfid;
0315 inp->coda_rmdir.name = offset;
0316 memcpy((char *)(inp) + offset, name, length);
0317 *((char *)inp + offset + length) = '\0';
0318
0319 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0320
0321 kvfree(inp);
0322 return error;
0323 }
0324
0325 int venus_remove(struct super_block *sb, struct CodaFid *dirfid,
0326 const char *name, int length)
0327 {
0328 union inputArgs *inp;
0329 union outputArgs *outp;
0330 int error=0, insize, outsize, offset;
0331
0332 offset = INSIZE(remove);
0333 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(remove));
0334 UPARG(CODA_REMOVE);
0335
0336 inp->coda_remove.VFid = *dirfid;
0337 inp->coda_remove.name = offset;
0338 memcpy((char *)(inp) + offset, name, length);
0339 *((char *)inp + offset + length) = '\0';
0340
0341 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0342
0343 kvfree(inp);
0344 return error;
0345 }
0346
0347 int venus_readlink(struct super_block *sb, struct CodaFid *fid,
0348 char *buffer, int *length)
0349 {
0350 union inputArgs *inp;
0351 union outputArgs *outp;
0352 int insize, outsize, error;
0353 int retlen;
0354 char *result;
0355
0356 insize = max_t(unsigned int,
0357 INSIZE(readlink), OUTSIZE(readlink)+ *length);
0358 UPARG(CODA_READLINK);
0359
0360 inp->coda_readlink.VFid = *fid;
0361
0362 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0363 if (!error) {
0364 retlen = outp->coda_readlink.count;
0365 if (retlen >= *length)
0366 retlen = *length - 1;
0367 *length = retlen;
0368 result = (char *)outp + (long)outp->coda_readlink.data;
0369 memcpy(buffer, result, retlen);
0370 *(buffer + retlen) = '\0';
0371 }
0372
0373 kvfree(inp);
0374 return error;
0375 }
0376
0377
0378
0379 int venus_link(struct super_block *sb, struct CodaFid *fid,
0380 struct CodaFid *dirfid, const char *name, int len )
0381 {
0382 union inputArgs *inp;
0383 union outputArgs *outp;
0384 int insize, outsize, error;
0385 int offset;
0386
0387 offset = INSIZE(link);
0388 insize = max_t(unsigned int, offset + len + 1, OUTSIZE(link));
0389 UPARG(CODA_LINK);
0390
0391 inp->coda_link.sourceFid = *fid;
0392 inp->coda_link.destFid = *dirfid;
0393 inp->coda_link.tname = offset;
0394
0395
0396 memcpy((char *)(inp) + offset, name, len);
0397 *((char *)inp + offset + len) = '\0';
0398
0399 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0400
0401 kvfree(inp);
0402 return error;
0403 }
0404
0405 int venus_symlink(struct super_block *sb, struct CodaFid *fid,
0406 const char *name, int len,
0407 const char *symname, int symlen)
0408 {
0409 union inputArgs *inp;
0410 union outputArgs *outp;
0411 int insize, outsize, error;
0412 int offset, s;
0413
0414 offset = INSIZE(symlink);
0415 insize = max_t(unsigned int, offset + len + symlen + 8, OUTSIZE(symlink));
0416 UPARG(CODA_SYMLINK);
0417
0418
0419 inp->coda_symlink.VFid = *fid;
0420
0421
0422 inp->coda_symlink.srcname = offset;
0423 s = ( symlen & ~0x3 ) + 4;
0424 memcpy((char *)(inp) + offset, symname, symlen);
0425 *((char *)inp + offset + symlen) = '\0';
0426
0427
0428 offset += s;
0429 inp->coda_symlink.tname = offset;
0430 s = (len & ~0x3) + 4;
0431 memcpy((char *)(inp) + offset, name, len);
0432 *((char *)inp + offset + len) = '\0';
0433
0434 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0435
0436 kvfree(inp);
0437 return error;
0438 }
0439
0440 int venus_fsync(struct super_block *sb, struct CodaFid *fid)
0441 {
0442 union inputArgs *inp;
0443 union outputArgs *outp;
0444 int insize, outsize, error;
0445
0446 insize=SIZE(fsync);
0447 UPARG(CODA_FSYNC);
0448
0449 inp->coda_fsync.VFid = *fid;
0450 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0451
0452 kvfree(inp);
0453 return error;
0454 }
0455
0456 int venus_access(struct super_block *sb, struct CodaFid *fid, int mask)
0457 {
0458 union inputArgs *inp;
0459 union outputArgs *outp;
0460 int insize, outsize, error;
0461
0462 insize = SIZE(access);
0463 UPARG(CODA_ACCESS);
0464
0465 inp->coda_access.VFid = *fid;
0466 inp->coda_access.flags = mask;
0467
0468 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0469
0470 kvfree(inp);
0471 return error;
0472 }
0473
0474
0475 int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
0476 unsigned int cmd, struct PioctlData *data)
0477 {
0478 union inputArgs *inp;
0479 union outputArgs *outp;
0480 int insize, outsize, error;
0481 int iocsize;
0482
0483 insize = VC_MAXMSGSIZE;
0484 UPARG(CODA_IOCTL);
0485
0486
0487 if (data->vi.in_size > VC_MAXDATASIZE) {
0488 error = -EINVAL;
0489 goto exit;
0490 }
0491
0492 if (data->vi.out_size > VC_MAXDATASIZE) {
0493 error = -EINVAL;
0494 goto exit;
0495 }
0496
0497 inp->coda_ioctl.VFid = *fid;
0498
0499
0500
0501
0502 inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));
0503 iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
0504 inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) << 16;
0505
0506
0507 inp->coda_ioctl.len = data->vi.in_size;
0508 inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
0509
0510
0511 if (copy_from_user((char *)inp + (long)inp->coda_ioctl.data,
0512 data->vi.in, data->vi.in_size)) {
0513 error = -EINVAL;
0514 goto exit;
0515 }
0516
0517 error = coda_upcall(coda_vcp(sb), SIZE(ioctl) + data->vi.in_size,
0518 &outsize, inp);
0519
0520 if (error) {
0521 pr_warn("%s: Venus returns: %d for %s\n",
0522 __func__, error, coda_f2s(fid));
0523 goto exit;
0524 }
0525
0526 if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) {
0527 error = -EINVAL;
0528 goto exit;
0529 }
0530
0531
0532 if (outp->coda_ioctl.len > data->vi.out_size) {
0533 error = -EINVAL;
0534 goto exit;
0535 }
0536
0537
0538 if (copy_to_user(data->vi.out,
0539 (char *)outp + (long)outp->coda_ioctl.data,
0540 outp->coda_ioctl.len)) {
0541 error = -EFAULT;
0542 goto exit;
0543 }
0544
0545 exit:
0546 kvfree(inp);
0547 return error;
0548 }
0549
0550 int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
0551 {
0552 union inputArgs *inp;
0553 union outputArgs *outp;
0554 int insize, outsize, error;
0555
0556 insize = SIZE(statfs);
0557 UPARG(CODA_STATFS);
0558
0559 error = coda_upcall(coda_vcp(dentry->d_sb), insize, &outsize, inp);
0560 if (!error) {
0561 sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
0562 sfs->f_bfree = outp->coda_statfs.stat.f_bfree;
0563 sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
0564 sfs->f_files = outp->coda_statfs.stat.f_files;
0565 sfs->f_ffree = outp->coda_statfs.stat.f_ffree;
0566 }
0567
0568 kvfree(inp);
0569 return error;
0570 }
0571
0572 int venus_access_intent(struct super_block *sb, struct CodaFid *fid,
0573 bool *access_intent_supported,
0574 size_t count, loff_t ppos, int type)
0575 {
0576 union inputArgs *inp;
0577 union outputArgs *outp;
0578 int insize, outsize, error;
0579 bool finalizer =
0580 type == CODA_ACCESS_TYPE_READ_FINISH ||
0581 type == CODA_ACCESS_TYPE_WRITE_FINISH;
0582
0583 if (!*access_intent_supported && !finalizer)
0584 return 0;
0585
0586 insize = SIZE(access_intent);
0587 UPARG(CODA_ACCESS_INTENT);
0588
0589 inp->coda_access_intent.VFid = *fid;
0590 inp->coda_access_intent.count = count;
0591 inp->coda_access_intent.pos = ppos;
0592 inp->coda_access_intent.type = type;
0593
0594 error = coda_upcall(coda_vcp(sb), insize,
0595 finalizer ? NULL : &outsize, inp);
0596
0597
0598
0599
0600
0601
0602 if (!finalizer || error)
0603 kvfree(inp);
0604
0605
0606 if (error == -EOPNOTSUPP) {
0607 *access_intent_supported = false;
0608 error = 0;
0609 }
0610 return error;
0611 }
0612
0613
0614
0615
0616 static void coda_block_signals(sigset_t *old)
0617 {
0618 spin_lock_irq(¤t->sighand->siglock);
0619 *old = current->blocked;
0620
0621 sigfillset(¤t->blocked);
0622 sigdelset(¤t->blocked, SIGKILL);
0623 sigdelset(¤t->blocked, SIGSTOP);
0624 sigdelset(¤t->blocked, SIGINT);
0625
0626 recalc_sigpending();
0627 spin_unlock_irq(¤t->sighand->siglock);
0628 }
0629
0630 static void coda_unblock_signals(sigset_t *old)
0631 {
0632 spin_lock_irq(¤t->sighand->siglock);
0633 current->blocked = *old;
0634 recalc_sigpending();
0635 spin_unlock_irq(¤t->sighand->siglock);
0636 }
0637
0638
0639
0640
0641
0642
0643
0644 #define CODA_INTERRUPTIBLE(r) (!coda_hard && \
0645 (((r)->uc_opcode != CODA_CLOSE && \
0646 (r)->uc_opcode != CODA_STORE && \
0647 (r)->uc_opcode != CODA_ACCESS_INTENT && \
0648 (r)->uc_opcode != CODA_RELEASE) || \
0649 (r)->uc_flags & CODA_REQ_READ))
0650
0651 static inline void coda_waitfor_upcall(struct venus_comm *vcp,
0652 struct upc_req *req)
0653 {
0654 DECLARE_WAITQUEUE(wait, current);
0655 unsigned long timeout = jiffies + coda_timeout * HZ;
0656 sigset_t old;
0657 int blocked;
0658
0659 coda_block_signals(&old);
0660 blocked = 1;
0661
0662 add_wait_queue(&req->uc_sleep, &wait);
0663 for (;;) {
0664 if (CODA_INTERRUPTIBLE(req))
0665 set_current_state(TASK_INTERRUPTIBLE);
0666 else
0667 set_current_state(TASK_UNINTERRUPTIBLE);
0668
0669
0670 if (req->uc_flags & (CODA_REQ_WRITE | CODA_REQ_ABORT))
0671 break;
0672
0673 if (blocked && time_after(jiffies, timeout) &&
0674 CODA_INTERRUPTIBLE(req))
0675 {
0676 coda_unblock_signals(&old);
0677 blocked = 0;
0678 }
0679
0680 if (signal_pending(current)) {
0681 list_del(&req->uc_chain);
0682 break;
0683 }
0684
0685 mutex_unlock(&vcp->vc_mutex);
0686 if (blocked)
0687 schedule_timeout(HZ);
0688 else
0689 schedule();
0690 mutex_lock(&vcp->vc_mutex);
0691 }
0692 if (blocked)
0693 coda_unblock_signals(&old);
0694
0695 remove_wait_queue(&req->uc_sleep, &wait);
0696 set_current_state(TASK_RUNNING);
0697 }
0698
0699
0700
0701
0702
0703
0704
0705
0706
0707
0708
0709 static int coda_upcall(struct venus_comm *vcp,
0710 int inSize, int *outSize,
0711 union inputArgs *buffer)
0712 {
0713 union outputArgs *out;
0714 union inputArgs *sig_inputArgs;
0715 struct upc_req *req = NULL, *sig_req;
0716 int error;
0717
0718 mutex_lock(&vcp->vc_mutex);
0719
0720 if (!vcp->vc_inuse) {
0721 pr_notice("Venus dead, not sending upcall\n");
0722 error = -ENXIO;
0723 goto exit;
0724 }
0725
0726
0727 req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
0728 if (!req) {
0729 error = -ENOMEM;
0730 goto exit;
0731 }
0732
0733 buffer->ih.unique = ++vcp->vc_seq;
0734
0735 req->uc_data = (void *)buffer;
0736 req->uc_flags = outSize ? 0 : CODA_REQ_ASYNC;
0737 req->uc_inSize = inSize;
0738 req->uc_outSize = (outSize && *outSize) ? *outSize : inSize;
0739 req->uc_opcode = buffer->ih.opcode;
0740 req->uc_unique = buffer->ih.unique;
0741 init_waitqueue_head(&req->uc_sleep);
0742
0743
0744 list_add_tail(&req->uc_chain, &vcp->vc_pending);
0745 wake_up_interruptible(&vcp->vc_waitq);
0746
0747
0748 if (outSize == NULL) {
0749 mutex_unlock(&vcp->vc_mutex);
0750 return 0;
0751 }
0752
0753
0754
0755
0756
0757
0758
0759
0760
0761
0762
0763 coda_waitfor_upcall(vcp, req);
0764
0765
0766 if (req->uc_flags & CODA_REQ_WRITE) {
0767 out = (union outputArgs *)req->uc_data;
0768
0769 error = -out->oh.result;
0770 *outSize = req->uc_outSize;
0771 goto exit;
0772 }
0773
0774 error = -EINTR;
0775 if ((req->uc_flags & CODA_REQ_ABORT) || !signal_pending(current)) {
0776 pr_warn("Unexpected interruption.\n");
0777 goto exit;
0778 }
0779
0780
0781 if (!(req->uc_flags & CODA_REQ_READ))
0782 goto exit;
0783
0784
0785 if (!vcp->vc_inuse) {
0786 pr_info("Venus dead, not sending signal.\n");
0787 goto exit;
0788 }
0789
0790 error = -ENOMEM;
0791 sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
0792 if (!sig_req) goto exit;
0793
0794 sig_inputArgs = kvzalloc(sizeof(struct coda_in_hdr), GFP_KERNEL);
0795 if (!sig_inputArgs) {
0796 kfree(sig_req);
0797 goto exit;
0798 }
0799
0800 error = -EINTR;
0801 sig_inputArgs->ih.opcode = CODA_SIGNAL;
0802 sig_inputArgs->ih.unique = req->uc_unique;
0803
0804 sig_req->uc_flags = CODA_REQ_ASYNC;
0805 sig_req->uc_opcode = sig_inputArgs->ih.opcode;
0806 sig_req->uc_unique = sig_inputArgs->ih.unique;
0807 sig_req->uc_data = (void *)sig_inputArgs;
0808 sig_req->uc_inSize = sizeof(struct coda_in_hdr);
0809 sig_req->uc_outSize = sizeof(struct coda_in_hdr);
0810
0811
0812 list_add(&(sig_req->uc_chain), &vcp->vc_pending);
0813 wake_up_interruptible(&vcp->vc_waitq);
0814
0815 exit:
0816 kfree(req);
0817 mutex_unlock(&vcp->vc_mutex);
0818 return error;
0819 }
0820
0821
0822
0823
0824
0825
0826
0827
0828
0829
0830
0831
0832
0833
0834
0835
0836
0837
0838
0839
0840
0841
0842
0843
0844
0845
0846
0847
0848
0849
0850
0851
0852
0853
0854
0855 int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out,
0856 size_t nbytes)
0857 {
0858 struct inode *inode = NULL;
0859 struct CodaFid *fid = NULL, *newfid;
0860 struct super_block *sb;
0861
0862
0863
0864
0865
0866 switch (opcode) {
0867 case CODA_PURGEUSER:
0868 if (nbytes < sizeof(struct coda_purgeuser_out))
0869 return -EINVAL;
0870 break;
0871
0872 case CODA_ZAPDIR:
0873 if (nbytes < sizeof(struct coda_zapdir_out))
0874 return -EINVAL;
0875 break;
0876
0877 case CODA_ZAPFILE:
0878 if (nbytes < sizeof(struct coda_zapfile_out))
0879 return -EINVAL;
0880 break;
0881
0882 case CODA_PURGEFID:
0883 if (nbytes < sizeof(struct coda_purgefid_out))
0884 return -EINVAL;
0885 break;
0886
0887 case CODA_REPLACE:
0888 if (nbytes < sizeof(struct coda_replace_out))
0889 return -EINVAL;
0890 break;
0891 }
0892
0893
0894 mutex_lock(&vcp->vc_mutex);
0895 sb = vcp->vc_sb;
0896 if (!sb || !sb->s_root)
0897 goto unlock_out;
0898
0899 switch (opcode) {
0900 case CODA_FLUSH:
0901 coda_cache_clear_all(sb);
0902 shrink_dcache_sb(sb);
0903 if (d_really_is_positive(sb->s_root))
0904 coda_flag_inode(d_inode(sb->s_root), C_FLUSH);
0905 break;
0906
0907 case CODA_PURGEUSER:
0908 coda_cache_clear_all(sb);
0909 break;
0910
0911 case CODA_ZAPDIR:
0912 fid = &out->coda_zapdir.CodaFid;
0913 break;
0914
0915 case CODA_ZAPFILE:
0916 fid = &out->coda_zapfile.CodaFid;
0917 break;
0918
0919 case CODA_PURGEFID:
0920 fid = &out->coda_purgefid.CodaFid;
0921 break;
0922
0923 case CODA_REPLACE:
0924 fid = &out->coda_replace.OldFid;
0925 break;
0926 }
0927 if (fid)
0928 inode = coda_fid_to_inode(fid, sb);
0929
0930 unlock_out:
0931 mutex_unlock(&vcp->vc_mutex);
0932
0933 if (!inode)
0934 return 0;
0935
0936 switch (opcode) {
0937 case CODA_ZAPDIR:
0938 coda_flag_inode_children(inode, C_PURGE);
0939 coda_flag_inode(inode, C_VATTR);
0940 break;
0941
0942 case CODA_ZAPFILE:
0943 coda_flag_inode(inode, C_VATTR);
0944 break;
0945
0946 case CODA_PURGEFID:
0947 coda_flag_inode_children(inode, C_PURGE);
0948
0949
0950 coda_flag_inode(inode, C_PURGE);
0951 d_prune_aliases(inode);
0952 break;
0953
0954 case CODA_REPLACE:
0955 newfid = &out->coda_replace.NewFid;
0956 coda_replace_fid(inode, fid, newfid);
0957 break;
0958 }
0959 iput(inode);
0960 return 0;
0961 }