diff options
Diffstat (limited to 'fs/coda/upcall.c')
-rw-r--r-- | fs/coda/upcall.c | 146 |
1 files changed, 112 insertions, 34 deletions
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index 1175a1722411..eb3b1898da46 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c | |||
@@ -33,7 +33,7 @@ | |||
33 | #include <linux/vfs.h> | 33 | #include <linux/vfs.h> |
34 | 34 | ||
35 | #include <linux/coda.h> | 35 | #include <linux/coda.h> |
36 | #include <linux/coda_psdev.h> | 36 | #include "coda_psdev.h" |
37 | #include "coda_linux.h" | 37 | #include "coda_linux.h" |
38 | #include "coda_cache.h" | 38 | #include "coda_cache.h" |
39 | 39 | ||
@@ -46,7 +46,7 @@ static void *alloc_upcall(int opcode, int size) | |||
46 | { | 46 | { |
47 | union inputArgs *inp; | 47 | union inputArgs *inp; |
48 | 48 | ||
49 | CODA_ALLOC(inp, union inputArgs *, size); | 49 | inp = kvzalloc(size, GFP_KERNEL); |
50 | if (!inp) | 50 | if (!inp) |
51 | return ERR_PTR(-ENOMEM); | 51 | return ERR_PTR(-ENOMEM); |
52 | 52 | ||
@@ -85,7 +85,7 @@ int venus_rootfid(struct super_block *sb, struct CodaFid *fidp) | |||
85 | if (!error) | 85 | if (!error) |
86 | *fidp = outp->coda_root.VFid; | 86 | *fidp = outp->coda_root.VFid; |
87 | 87 | ||
88 | CODA_FREE(inp, insize); | 88 | kvfree(inp); |
89 | return error; | 89 | return error; |
90 | } | 90 | } |
91 | 91 | ||
@@ -104,7 +104,7 @@ int venus_getattr(struct super_block *sb, struct CodaFid *fid, | |||
104 | if (!error) | 104 | if (!error) |
105 | *attr = outp->coda_getattr.attr; | 105 | *attr = outp->coda_getattr.attr; |
106 | 106 | ||
107 | CODA_FREE(inp, insize); | 107 | kvfree(inp); |
108 | return error; | 108 | return error; |
109 | } | 109 | } |
110 | 110 | ||
@@ -123,7 +123,7 @@ int venus_setattr(struct super_block *sb, struct CodaFid *fid, | |||
123 | 123 | ||
124 | error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); | 124 | error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); |
125 | 125 | ||
126 | CODA_FREE(inp, insize); | 126 | kvfree(inp); |
127 | return error; | 127 | return error; |
128 | } | 128 | } |
129 | 129 | ||
@@ -153,7 +153,7 @@ int venus_lookup(struct super_block *sb, struct CodaFid *fid, | |||
153 | *type = outp->coda_lookup.vtype; | 153 | *type = outp->coda_lookup.vtype; |
154 | } | 154 | } |
155 | 155 | ||
156 | CODA_FREE(inp, insize); | 156 | kvfree(inp); |
157 | return error; | 157 | return error; |
158 | } | 158 | } |
159 | 159 | ||
@@ -173,7 +173,7 @@ int venus_close(struct super_block *sb, struct CodaFid *fid, int flags, | |||
173 | 173 | ||
174 | error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); | 174 | error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); |
175 | 175 | ||
176 | CODA_FREE(inp, insize); | 176 | kvfree(inp); |
177 | return error; | 177 | return error; |
178 | } | 178 | } |
179 | 179 | ||
@@ -194,7 +194,7 @@ int venus_open(struct super_block *sb, struct CodaFid *fid, | |||
194 | if (!error) | 194 | if (!error) |
195 | *fh = outp->coda_open_by_fd.fh; | 195 | *fh = outp->coda_open_by_fd.fh; |
196 | 196 | ||
197 | CODA_FREE(inp, insize); | 197 | kvfree(inp); |
198 | return error; | 198 | return error; |
199 | } | 199 | } |
200 | 200 | ||
@@ -224,7 +224,7 @@ int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid, | |||
224 | *newfid = outp->coda_mkdir.VFid; | 224 | *newfid = outp->coda_mkdir.VFid; |
225 | } | 225 | } |
226 | 226 | ||
227 | CODA_FREE(inp, insize); | 227 | kvfree(inp); |
228 | return error; | 228 | return error; |
229 | } | 229 | } |
230 | 230 | ||
@@ -262,7 +262,7 @@ int venus_rename(struct super_block *sb, struct CodaFid *old_fid, | |||
262 | 262 | ||
263 | error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); | 263 | error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); |
264 | 264 | ||
265 | CODA_FREE(inp, insize); | 265 | kvfree(inp); |
266 | return error; | 266 | return error; |
267 | } | 267 | } |
268 | 268 | ||
@@ -295,7 +295,7 @@ int venus_create(struct super_block *sb, struct CodaFid *dirfid, | |||
295 | *newfid = outp->coda_create.VFid; | 295 | *newfid = outp->coda_create.VFid; |
296 | } | 296 | } |
297 | 297 | ||
298 | CODA_FREE(inp, insize); | 298 | kvfree(inp); |
299 | return error; | 299 | return error; |
300 | } | 300 | } |
301 | 301 | ||
@@ -318,7 +318,7 @@ int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid, | |||
318 | 318 | ||
319 | error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); | 319 | error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); |
320 | 320 | ||
321 | CODA_FREE(inp, insize); | 321 | kvfree(inp); |
322 | return error; | 322 | return error; |
323 | } | 323 | } |
324 | 324 | ||
@@ -340,7 +340,7 @@ int venus_remove(struct super_block *sb, struct CodaFid *dirfid, | |||
340 | 340 | ||
341 | error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); | 341 | error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); |
342 | 342 | ||
343 | CODA_FREE(inp, insize); | 343 | kvfree(inp); |
344 | return error; | 344 | return error; |
345 | } | 345 | } |
346 | 346 | ||
@@ -370,7 +370,7 @@ int venus_readlink(struct super_block *sb, struct CodaFid *fid, | |||
370 | *(buffer + retlen) = '\0'; | 370 | *(buffer + retlen) = '\0'; |
371 | } | 371 | } |
372 | 372 | ||
373 | CODA_FREE(inp, insize); | 373 | kvfree(inp); |
374 | return error; | 374 | return error; |
375 | } | 375 | } |
376 | 376 | ||
@@ -398,7 +398,7 @@ int venus_link(struct super_block *sb, struct CodaFid *fid, | |||
398 | 398 | ||
399 | error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); | 399 | error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); |
400 | 400 | ||
401 | CODA_FREE(inp, insize); | 401 | kvfree(inp); |
402 | return error; | 402 | return error; |
403 | } | 403 | } |
404 | 404 | ||
@@ -433,7 +433,7 @@ int venus_symlink(struct super_block *sb, struct CodaFid *fid, | |||
433 | 433 | ||
434 | error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); | 434 | error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); |
435 | 435 | ||
436 | CODA_FREE(inp, insize); | 436 | kvfree(inp); |
437 | return error; | 437 | return error; |
438 | } | 438 | } |
439 | 439 | ||
@@ -449,7 +449,7 @@ int venus_fsync(struct super_block *sb, struct CodaFid *fid) | |||
449 | inp->coda_fsync.VFid = *fid; | 449 | inp->coda_fsync.VFid = *fid; |
450 | error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); | 450 | error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); |
451 | 451 | ||
452 | CODA_FREE(inp, insize); | 452 | kvfree(inp); |
453 | return error; | 453 | return error; |
454 | } | 454 | } |
455 | 455 | ||
@@ -467,7 +467,7 @@ int venus_access(struct super_block *sb, struct CodaFid *fid, int mask) | |||
467 | 467 | ||
468 | error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); | 468 | error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); |
469 | 469 | ||
470 | CODA_FREE(inp, insize); | 470 | kvfree(inp); |
471 | return error; | 471 | return error; |
472 | } | 472 | } |
473 | 473 | ||
@@ -543,7 +543,7 @@ int venus_pioctl(struct super_block *sb, struct CodaFid *fid, | |||
543 | } | 543 | } |
544 | 544 | ||
545 | exit: | 545 | exit: |
546 | CODA_FREE(inp, insize); | 546 | kvfree(inp); |
547 | return error; | 547 | return error; |
548 | } | 548 | } |
549 | 549 | ||
@@ -553,7 +553,7 @@ int venus_statfs(struct dentry *dentry, struct kstatfs *sfs) | |||
553 | union outputArgs *outp; | 553 | union outputArgs *outp; |
554 | int insize, outsize, error; | 554 | int insize, outsize, error; |
555 | 555 | ||
556 | insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs)); | 556 | insize = SIZE(statfs); |
557 | UPARG(CODA_STATFS); | 557 | UPARG(CODA_STATFS); |
558 | 558 | ||
559 | error = coda_upcall(coda_vcp(dentry->d_sb), insize, &outsize, inp); | 559 | error = coda_upcall(coda_vcp(dentry->d_sb), insize, &outsize, inp); |
@@ -565,10 +565,51 @@ int venus_statfs(struct dentry *dentry, struct kstatfs *sfs) | |||
565 | sfs->f_ffree = outp->coda_statfs.stat.f_ffree; | 565 | sfs->f_ffree = outp->coda_statfs.stat.f_ffree; |
566 | } | 566 | } |
567 | 567 | ||
568 | CODA_FREE(inp, insize); | 568 | kvfree(inp); |
569 | return error; | 569 | return error; |
570 | } | 570 | } |
571 | 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 | |||
572 | /* | 613 | /* |
573 | * coda_upcall and coda_downcall routines. | 614 | * coda_upcall and coda_downcall routines. |
574 | */ | 615 | */ |
@@ -598,10 +639,12 @@ static void coda_unblock_signals(sigset_t *old) | |||
598 | * has seen them, | 639 | * has seen them, |
599 | * - CODA_CLOSE or CODA_RELEASE upcall (to avoid reference count problems) | 640 | * - CODA_CLOSE or CODA_RELEASE upcall (to avoid reference count problems) |
600 | * - CODA_STORE (to avoid data loss) | 641 | * - CODA_STORE (to avoid data loss) |
642 | * - CODA_ACCESS_INTENT (to avoid reference count problems) | ||
601 | */ | 643 | */ |
602 | #define CODA_INTERRUPTIBLE(r) (!coda_hard && \ | 644 | #define CODA_INTERRUPTIBLE(r) (!coda_hard && \ |
603 | (((r)->uc_opcode != CODA_CLOSE && \ | 645 | (((r)->uc_opcode != CODA_CLOSE && \ |
604 | (r)->uc_opcode != CODA_STORE && \ | 646 | (r)->uc_opcode != CODA_STORE && \ |
647 | (r)->uc_opcode != CODA_ACCESS_INTENT && \ | ||
605 | (r)->uc_opcode != CODA_RELEASE) || \ | 648 | (r)->uc_opcode != CODA_RELEASE) || \ |
606 | (r)->uc_flags & CODA_REQ_READ)) | 649 | (r)->uc_flags & CODA_REQ_READ)) |
607 | 650 | ||
@@ -687,21 +730,25 @@ static int coda_upcall(struct venus_comm *vcp, | |||
687 | goto exit; | 730 | goto exit; |
688 | } | 731 | } |
689 | 732 | ||
733 | buffer->ih.unique = ++vcp->vc_seq; | ||
734 | |||
690 | req->uc_data = (void *)buffer; | 735 | req->uc_data = (void *)buffer; |
691 | req->uc_flags = 0; | 736 | req->uc_flags = outSize ? 0 : CODA_REQ_ASYNC; |
692 | req->uc_inSize = inSize; | 737 | req->uc_inSize = inSize; |
693 | req->uc_outSize = *outSize ? *outSize : inSize; | 738 | req->uc_outSize = (outSize && *outSize) ? *outSize : inSize; |
694 | req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode; | 739 | req->uc_opcode = buffer->ih.opcode; |
695 | req->uc_unique = ++vcp->vc_seq; | 740 | req->uc_unique = buffer->ih.unique; |
696 | init_waitqueue_head(&req->uc_sleep); | 741 | init_waitqueue_head(&req->uc_sleep); |
697 | 742 | ||
698 | /* Fill in the common input args. */ | ||
699 | ((union inputArgs *)buffer)->ih.unique = req->uc_unique; | ||
700 | |||
701 | /* Append msg to pending queue and poke Venus. */ | 743 | /* Append msg to pending queue and poke Venus. */ |
702 | list_add_tail(&req->uc_chain, &vcp->vc_pending); | 744 | list_add_tail(&req->uc_chain, &vcp->vc_pending); |
703 | |||
704 | wake_up_interruptible(&vcp->vc_waitq); | 745 | wake_up_interruptible(&vcp->vc_waitq); |
746 | |||
747 | if (req->uc_flags & CODA_REQ_ASYNC) { | ||
748 | mutex_unlock(&vcp->vc_mutex); | ||
749 | return 0; | ||
750 | } | ||
751 | |||
705 | /* We can be interrupted while we wait for Venus to process | 752 | /* We can be interrupted while we wait for Venus to process |
706 | * our request. If the interrupt occurs before Venus has read | 753 | * our request. If the interrupt occurs before Venus has read |
707 | * the request, we dequeue and return. If it occurs after the | 754 | * the request, we dequeue and return. If it occurs after the |
@@ -743,20 +790,20 @@ static int coda_upcall(struct venus_comm *vcp, | |||
743 | sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL); | 790 | sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL); |
744 | if (!sig_req) goto exit; | 791 | if (!sig_req) goto exit; |
745 | 792 | ||
746 | CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr)); | 793 | sig_inputArgs = kvzalloc(sizeof(struct coda_in_hdr), GFP_KERNEL); |
747 | if (!sig_req->uc_data) { | 794 | if (!sig_inputArgs) { |
748 | kfree(sig_req); | 795 | kfree(sig_req); |
749 | goto exit; | 796 | goto exit; |
750 | } | 797 | } |
751 | 798 | ||
752 | error = -EINTR; | 799 | error = -EINTR; |
753 | sig_inputArgs = (union inputArgs *)sig_req->uc_data; | ||
754 | sig_inputArgs->ih.opcode = CODA_SIGNAL; | 800 | sig_inputArgs->ih.opcode = CODA_SIGNAL; |
755 | sig_inputArgs->ih.unique = req->uc_unique; | 801 | sig_inputArgs->ih.unique = req->uc_unique; |
756 | 802 | ||
757 | sig_req->uc_flags = CODA_REQ_ASYNC; | 803 | sig_req->uc_flags = CODA_REQ_ASYNC; |
758 | sig_req->uc_opcode = sig_inputArgs->ih.opcode; | 804 | sig_req->uc_opcode = sig_inputArgs->ih.opcode; |
759 | sig_req->uc_unique = sig_inputArgs->ih.unique; | 805 | sig_req->uc_unique = sig_inputArgs->ih.unique; |
806 | sig_req->uc_data = (void *)sig_inputArgs; | ||
760 | sig_req->uc_inSize = sizeof(struct coda_in_hdr); | 807 | sig_req->uc_inSize = sizeof(struct coda_in_hdr); |
761 | sig_req->uc_outSize = sizeof(struct coda_in_hdr); | 808 | sig_req->uc_outSize = sizeof(struct coda_in_hdr); |
762 | 809 | ||
@@ -804,12 +851,44 @@ exit: | |||
804 | * | 851 | * |
805 | * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */ | 852 | * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */ |
806 | 853 | ||
807 | int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out) | 854 | int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out, |
855 | size_t nbytes) | ||
808 | { | 856 | { |
809 | struct inode *inode = NULL; | 857 | struct inode *inode = NULL; |
810 | struct CodaFid *fid = NULL, *newfid; | 858 | struct CodaFid *fid = NULL, *newfid; |
811 | struct super_block *sb; | 859 | struct super_block *sb; |
812 | 860 | ||
861 | /* | ||
862 | * Make sure we have received enough data from the cache | ||
863 | * manager to populate the necessary fields in the buffer | ||
864 | */ | ||
865 | switch (opcode) { | ||
866 | case CODA_PURGEUSER: | ||
867 | if (nbytes < sizeof(struct coda_purgeuser_out)) | ||
868 | return -EINVAL; | ||
869 | break; | ||
870 | |||
871 | case CODA_ZAPDIR: | ||
872 | if (nbytes < sizeof(struct coda_zapdir_out)) | ||
873 | return -EINVAL; | ||
874 | break; | ||
875 | |||
876 | case CODA_ZAPFILE: | ||
877 | if (nbytes < sizeof(struct coda_zapfile_out)) | ||
878 | return -EINVAL; | ||
879 | break; | ||
880 | |||
881 | case CODA_PURGEFID: | ||
882 | if (nbytes < sizeof(struct coda_purgefid_out)) | ||
883 | return -EINVAL; | ||
884 | break; | ||
885 | |||
886 | case CODA_REPLACE: | ||
887 | if (nbytes < sizeof(struct coda_replace_out)) | ||
888 | return -EINVAL; | ||
889 | break; | ||
890 | } | ||
891 | |||
813 | /* Handle invalidation requests. */ | 892 | /* Handle invalidation requests. */ |
814 | mutex_lock(&vcp->vc_mutex); | 893 | mutex_lock(&vcp->vc_mutex); |
815 | sb = vcp->vc_sb; | 894 | sb = vcp->vc_sb; |
@@ -879,4 +958,3 @@ unlock_out: | |||
879 | iput(inode); | 958 | iput(inode); |
880 | return 0; | 959 | return 0; |
881 | } | 960 | } |
882 | |||