aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmit Shah <amit.shah@redhat.com>2010-05-20 00:15:50 -0400
committerRusty Russell <rusty@rustcorp.com.au>2010-05-19 08:45:50 -0400
commitcdfadfc1adb87fc7e8a631b1f299715feacbde90 (patch)
treefc7ace0ea80df94ed85176c493d9ae341f146b9d
parent60caacd3eeab68672961e88db01e26735527d521 (diff)
virtio: console: Add support for nonblocking write()s
If the host port is not open, a write() should either just return if the file is opened in non-blocking mode, or block till the host port is opened. Also, don't spin till host consumes data for nonblocking ports. For non-blocking ports, we can do away with the spinning and reclaim the buffers consumed by the host on the next write call or on the condition that'll make poll return. Signed-off-by: Amit Shah <amit.shah@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
-rw-r--r--drivers/char/virtio_console.c119
1 files changed, 111 insertions, 8 deletions
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index a39bf191da02..4175a2ae972f 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -159,6 +159,9 @@ struct port {
159 */ 159 */
160 spinlock_t inbuf_lock; 160 spinlock_t inbuf_lock;
161 161
162 /* Protect the operations on the out_vq. */
163 spinlock_t outvq_lock;
164
162 /* The IO vqs for this port */ 165 /* The IO vqs for this port */
163 struct virtqueue *in_vq, *out_vq; 166 struct virtqueue *in_vq, *out_vq;
164 167
@@ -184,6 +187,8 @@ struct port {
184 /* The 'id' to identify the port with the Host */ 187 /* The 'id' to identify the port with the Host */
185 u32 id; 188 u32 id;
186 189
190 bool outvq_full;
191
187 /* Is the host device open */ 192 /* Is the host device open */
188 bool host_connected; 193 bool host_connected;
189 194
@@ -405,15 +410,33 @@ static ssize_t send_control_msg(struct port *port, unsigned int event,
405 return __send_control_msg(port->portdev, port->id, event, value); 410 return __send_control_msg(port->portdev, port->id, event, value);
406} 411}
407 412
408static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count) 413/* Callers must take the port->outvq_lock */
414static void reclaim_consumed_buffers(struct port *port)
415{
416 void *buf;
417 unsigned int len;
418
419 while ((buf = virtqueue_get_buf(port->out_vq, &len))) {
420 kfree(buf);
421 port->outvq_full = false;
422 }
423}
424
425static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count,
426 bool nonblock)
409{ 427{
410 struct scatterlist sg[1]; 428 struct scatterlist sg[1];
411 struct virtqueue *out_vq; 429 struct virtqueue *out_vq;
412 ssize_t ret; 430 ssize_t ret;
431 unsigned long flags;
413 unsigned int len; 432 unsigned int len;
414 433
415 out_vq = port->out_vq; 434 out_vq = port->out_vq;
416 435
436 spin_lock_irqsave(&port->outvq_lock, flags);
437
438 reclaim_consumed_buffers(port);
439
417 sg_init_one(sg, in_buf, in_count); 440 sg_init_one(sg, in_buf, in_count);
418 ret = virtqueue_add_buf(out_vq, sg, 1, 0, in_buf); 441 ret = virtqueue_add_buf(out_vq, sg, 1, 0, in_buf);
419 442
@@ -422,14 +445,29 @@ static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count)
422 445
423 if (ret < 0) { 446 if (ret < 0) {
424 in_count = 0; 447 in_count = 0;
425 goto fail; 448 goto done;
426 } 449 }
427 450
428 /* Wait till the host acknowledges it pushed out the data we sent. */ 451 if (ret == 0)
452 port->outvq_full = true;
453
454 if (nonblock)
455 goto done;
456
457 /*
458 * Wait till the host acknowledges it pushed out the data we
459 * sent. This is done for ports in blocking mode or for data
460 * from the hvc_console; the tty operations are performed with
461 * spinlocks held so we can't sleep here.
462 */
429 while (!virtqueue_get_buf(out_vq, &len)) 463 while (!virtqueue_get_buf(out_vq, &len))
430 cpu_relax(); 464 cpu_relax();
431fail: 465done:
432 /* We're expected to return the amount of data we wrote */ 466 spin_unlock_irqrestore(&port->outvq_lock, flags);
467 /*
468 * We're expected to return the amount of data we wrote -- all
469 * of it
470 */
433 return in_count; 471 return in_count;
434} 472}
435 473
@@ -484,6 +522,25 @@ static bool will_read_block(struct port *port)
484 return !port_has_data(port) && port->host_connected; 522 return !port_has_data(port) && port->host_connected;
485} 523}
486 524
525static bool will_write_block(struct port *port)
526{
527 bool ret;
528
529 if (!port->host_connected)
530 return true;
531
532 spin_lock_irq(&port->outvq_lock);
533 /*
534 * Check if the Host has consumed any buffers since we last
535 * sent data (this is only applicable for nonblocking ports).
536 */
537 reclaim_consumed_buffers(port);
538 ret = port->outvq_full;
539 spin_unlock_irq(&port->outvq_lock);
540
541 return ret;
542}
543
487static ssize_t port_fops_read(struct file *filp, char __user *ubuf, 544static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
488 size_t count, loff_t *offp) 545 size_t count, loff_t *offp)
489{ 546{
@@ -530,9 +587,22 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
530 struct port *port; 587 struct port *port;
531 char *buf; 588 char *buf;
532 ssize_t ret; 589 ssize_t ret;
590 bool nonblock;
533 591
534 port = filp->private_data; 592 port = filp->private_data;
535 593
594 nonblock = filp->f_flags & O_NONBLOCK;
595
596 if (will_write_block(port)) {
597 if (nonblock)
598 return -EAGAIN;
599
600 ret = wait_event_interruptible(port->waitqueue,
601 !will_write_block(port));
602 if (ret < 0)
603 return ret;
604 }
605
536 count = min((size_t)(32 * 1024), count); 606 count = min((size_t)(32 * 1024), count);
537 607
538 buf = kmalloc(count, GFP_KERNEL); 608 buf = kmalloc(count, GFP_KERNEL);
@@ -545,9 +615,14 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
545 goto free_buf; 615 goto free_buf;
546 } 616 }
547 617
548 ret = send_buf(port, buf, count); 618 ret = send_buf(port, buf, count, nonblock);
619
620 if (nonblock && ret > 0)
621 goto out;
622
549free_buf: 623free_buf:
550 kfree(buf); 624 kfree(buf);
625out:
551 return ret; 626 return ret;
552} 627}
553 628
@@ -562,7 +637,7 @@ static unsigned int port_fops_poll(struct file *filp, poll_table *wait)
562 ret = 0; 637 ret = 0;
563 if (port->inbuf) 638 if (port->inbuf)
564 ret |= POLLIN | POLLRDNORM; 639 ret |= POLLIN | POLLRDNORM;
565 if (port->host_connected) 640 if (!will_write_block(port))
566 ret |= POLLOUT; 641 ret |= POLLOUT;
567 if (!port->host_connected) 642 if (!port->host_connected)
568 ret |= POLLHUP; 643 ret |= POLLHUP;
@@ -586,6 +661,10 @@ static int port_fops_release(struct inode *inode, struct file *filp)
586 661
587 spin_unlock_irq(&port->inbuf_lock); 662 spin_unlock_irq(&port->inbuf_lock);
588