diff options
author | Jan Harkes <jaharkes@cs.cmu.edu> | 2007-07-19 01:48:46 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-19 10:04:48 -0700 |
commit | fe71b5f3871af2c281a08acd4bedd2da25e46bc3 (patch) | |
tree | cdd4eafff85d86d5495eb4f7c51cfbdf689ec78a | |
parent | 87065519633af79e0577e32a58dcd9cf3c45a8a0 (diff) |
coda: cleanup for upcall handling path
Make the code that processes upcall responses more straightforward, uncovered
at least one bad assumption. We trusted that vc_inuse would be 0 when upcalls
are aborted, however the device may have been reopened.
Signed-off-by: Jan Harkes <jaharkes@cs.cmu.edu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | fs/coda/upcall.c | 121 |
1 files changed, 58 insertions, 63 deletions
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index a44ca4155fd..44332efa841 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c @@ -687,27 +687,27 @@ static inline void coda_waitfor_upcall(struct upc_req *vmp) * are all mapped to -EINTR, while showing a nice warning message. (jh) * */ -static int coda_upcall(struct coda_sb_info *sbi, - int inSize, int *outSize, - union inputArgs *buffer) +static int coda_upcall(struct coda_sb_info *sbi, + int inSize, int *outSize, + union inputArgs *buffer) { struct venus_comm *vcommp; union outputArgs *out; - struct upc_req *req; + union inputArgs *sig_inputArgs; + struct upc_req *req, *sig_req; int error = 0; vcommp = sbi->sbi_vcomm; - if ( !vcommp->vc_inuse ) { - printk("No pseudo device in upcall comms at %p\n", vcommp); - return -ENXIO; + if (!vcommp->vc_inuse) { + printk(KERN_NOTICE "coda: Venus dead, not sending upcall\n"); + return -ENXIO; } /* Format the request message. */ req = upc_alloc(); - if (!req) { - printk("Failed to allocate upc_req structure\n"); + if (!req) return -ENOMEM; - } + req->uc_data = (void *)buffer; req->uc_flags = 0; req->uc_inSize = inSize; @@ -715,13 +715,13 @@ static int coda_upcall(struct coda_sb_info *sbi, req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode; req->uc_unique = ++vcommp->vc_seq; init_waitqueue_head(&req->uc_sleep); - + /* Fill in the common input args. */ ((union inputArgs *)buffer)->ih.unique = req->uc_unique; /* Append msg to pending queue and poke Venus. */ - list_add_tail(&(req->uc_chain), &vcommp->vc_pending); - + list_add_tail(&req->uc_chain, &vcommp->vc_pending); + wake_up_interruptible(&vcommp->vc_waitq); /* We can be interrupted while we wait for Venus to process * our request. If the interrupt occurs before Venus has read @@ -735,64 +735,59 @@ static int coda_upcall(struct coda_sb_info *sbi, /* Go to sleep. Wake up on signals only after the timeout. */ coda_waitfor_upcall(req); - if (vcommp->vc_inuse) { /* i.e. Venus is still alive */ - /* Op went through, interrupt or not... */ - if (req->uc_flags & REQ_WRITE) { + /* Op went through, interrupt or not... */ + if (req->uc_flags & REQ_WRITE) { out = (union outputArgs *)req->uc_data; /* here we map positive Venus errors to kernel errors */ error = -out->oh.result; *outSize = req->uc_outSize; goto exit; - } - if ( !(req->uc_flags & REQ_READ) && signal_pending(current)) { - /* Interrupted before venus read it. */ - list_del(&(req->uc_chain)); - /* perhaps the best way to convince the app to - give up? */ - error = -EINTR; + } + + error = -EINTR; + if ((req->uc_flags & REQ_ABORT) || !signal_pending(current)) { + printk(KERN_WARNING "coda: Unexpected interruption.\n"); goto exit; - } - if ( (req->uc_flags & REQ_READ) && signal_pending(current) ) { - /* interrupted after Venus did its read, send signal */ - union inputArgs *sig_inputArgs; - struct upc_req *sig_req; - - list_del(&(req->uc_chain)); - error = -ENOMEM; - sig_req = upc_alloc(); - if (!sig_req) goto exit; - - CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr)); - if (!sig_req->uc_data) { - upc_free(sig_req); - goto exit; - } - - error = -EINTR; - sig_inputArgs = (union inputArgs *)sig_req->uc_data; - sig_inputArgs->ih.opcode = CODA_SIGNAL; - sig_inputArgs->ih.unique = req->uc_unique; - - sig_req->uc_flags = REQ_ASYNC; - sig_req->uc_opcode = sig_inputArgs->ih.opcode; - sig_req->uc_unique = sig_inputArgs->ih.unique; - sig_req->uc_inSize = sizeof(struct coda_in_hdr); - sig_req->uc_outSize = sizeof(struct coda_in_hdr); - - /* insert at head of queue! */ - list_add(&(sig_req->uc_chain), &vcommp->vc_pending); - wake_up_interruptible(&vcommp->vc_waitq); - } else { - printk("Coda: Strange interruption..\n"); - error = -EINTR; - } - } else { /* If venus died i.e. !VC_OPEN(vcommp) */ - printk("coda_upcall: Venus dead on (op,un) (%d.%d) flags %d\n", - req->uc_opcode, req->uc_unique, req->uc_flags); - error = -ENODEV; } - exit: + list_del(&(req->uc_chain)); + + /* Interrupted before venus read it. */ + if (!(req->uc_flags & REQ_READ)) + goto exit; + + /* Venus saw the upcall, make sure we can send interrupt signal */ + if (!vcommp->vc_inuse) { + printk(KERN_INFO "coda: Venus dead, not sending signal.\n"); + goto exit; + } + + error = -ENOMEM; + sig_req = upc_alloc(); + if (!sig_req) goto exit; + + CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr)); + if (!sig_req->uc_data) { + upc_free(sig_req); + goto exit; + } + + error = -EINTR; + sig_inputArgs = (union inputArgs *)sig_req->uc_data; + sig_inputArgs->ih.opcode = CODA_SIGNAL; + sig_inputArgs->ih.unique = req->uc_unique; + + sig_req->uc_flags = REQ_ASYNC; + sig_req->uc_opcode = sig_inputArgs->ih.opcode; + sig_req->uc_unique = sig_inputArgs->ih.unique; + sig_req->uc_inSize = sizeof(struct coda_in_hdr); + sig_req->uc_outSize = sizeof(struct coda_in_hdr); + + /* insert at head of queue! */ + list_add(&(sig_req->uc_chain), &vcommp->vc_pending); + wake_up_interruptible(&vcommp->vc_waitq); + +exit: upc_free(req); return error; } |