2004-03-05 18:13:18

by Paulo Marques

[permalink] [raw]
Subject: [PATCH] usblp.c (Was: usblp_write spins forever after an error)

--- drivers/usb/printer.c.orig 2004-03-05 17:29:50.238186624 +0000
+++ drivers/usb/printer.c 2004-03-05 17:35:05.346282912 +0000
@@ -604,14 +604,16 @@ static ssize_t usblp_write(struct file *
{
DECLARE_WAITQUEUE(wait, current);
struct usblp *usblp = file->private_data;
- int timeout, err = 0;
+ int timeout, err = 0, transfer_length = 0;
size_t writecount = 0;

while (writecount < count) {
if (!usblp->wcomplete) {
barrier();
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
+ if (file->f_flags & O_NONBLOCK) {
+ writecount += transfer_length;
+ return writecount ? writecount : -EAGAIN;
+ }

timeout = USBLP_WRITE_TIMEOUT;
add_wait_queue(&usblp->wait, &wait);
@@ -655,27 +657,36 @@ static ssize_t usblp_write(struct file *
continue;
}

- writecount += usblp->writeurb->transfer_buffer_length;
- usblp->writeurb->transfer_buffer_length = 0;
-
+ /* We must increment writecount here, and not at the
+ * end of the loop. Otherwise, the final loop iteration may
+ * be skipped, leading to incomplete printer output.
+ */
+ writecount += transfer_length;
if (writecount == count) {
up (&usblp->sem);
break;
}

- usblp->writeurb->transfer_buffer_length = (count - writecount) < USBLP_BUF_SIZE ?
- (count - writecount) : USBLP_BUF_SIZE;
+ transfer_length = count - writecount;
+ if(transfer_length > USBLP_BUF_SIZE)
+ transfer_length = USBLP_BUF_SIZE;
+
+ usblp->writeurb->transfer_buffer_length = transfer_length;

- if (copy_from_user(usblp->writeurb->transfer_buffer, buffer + writecount,
- usblp->writeurb->transfer_buffer_length)) {
+ if (copy_from_user(usblp->writeurb->transfer_buffer,
+ buffer + writecount, transfer_length)) {
up(&usblp->sem);
return writecount ? writecount : -EFAULT;
}

usblp->writeurb->dev = usblp->dev;
usblp->wcomplete = 0;
- if (usb_submit_urb(usblp->writeurb)) {
- count = -EIO;
+ err = usb_submit_urb(usblp->writeurb);
+ if (err) {
+ if (err != -ENOMEM)
+ count = -EIO;
+ else
+ count = writecount ? writecount : -ENOMEM;
up (&usblp->sem);
break;
}


Attachments:
usblp_patch_26 (916.00 B)
printer_patch_24 (2.08 kB)
Download all attachments

2004-03-11 01:45:31

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH] usblp.c (Was: usblp_write spins forever after an error)

On Fri, Mar 05, 2004 at 06:11:51PM +0000, Paulo Marques wrote:
>
> Here it is.
>
> The patch is only one line for 2.6.4-rc2. (I also did a little formatting
> adjustment to better comply with CodingStyle)
>
> For the 2.4.26-pre1 kernel, I also backported the return codes correction
> patch from Oliver Neukum.

Thanks, I've applied this to both the 2.4 and 2.6 usb trees.

greg k-h