mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	tty: hvc: hvc_write() may sleep
Rework the hvc_write loop to drop and re-take the spinlock on each iteration, add a cond_resched. Don't bother with an initial hvc_push initially, which makes the logic simpler -- just do a hvc_push on each time around the loop. Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
		
							parent
							
								
									cfb5946b55
								
							
						
					
					
						commit
						550ddadcc7
					
				
					 1 changed files with 20 additions and 14 deletions
				
			
		| 
						 | 
					@ -493,23 +493,29 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count
 | 
				
			||||||
	if (hp->port.count <= 0)
 | 
						if (hp->port.count <= 0)
 | 
				
			||||||
		return -EIO;
 | 
							return -EIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock_irqsave(&hp->lock, flags);
 | 
						while (count > 0) {
 | 
				
			||||||
 | 
							spin_lock_irqsave(&hp->lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Push pending writes */
 | 
							rsize = hp->outbuf_size - hp->n_outbuf;
 | 
				
			||||||
	if (hp->n_outbuf > 0)
 | 
					 | 
				
			||||||
		hvc_push(hp);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (count > 0 && (rsize = hp->outbuf_size - hp->n_outbuf) > 0) {
 | 
							if (rsize) {
 | 
				
			||||||
		if (rsize > count)
 | 
								if (rsize > count)
 | 
				
			||||||
			rsize = count;
 | 
									rsize = count;
 | 
				
			||||||
		memcpy(hp->outbuf + hp->n_outbuf, buf, rsize);
 | 
								memcpy(hp->outbuf + hp->n_outbuf, buf, rsize);
 | 
				
			||||||
		count -= rsize;
 | 
								count -= rsize;
 | 
				
			||||||
		buf += rsize;
 | 
								buf += rsize;
 | 
				
			||||||
		hp->n_outbuf += rsize;
 | 
								hp->n_outbuf += rsize;
 | 
				
			||||||
		written += rsize;
 | 
								written += rsize;
 | 
				
			||||||
		hvc_push(hp);
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (hp->n_outbuf > 0)
 | 
				
			||||||
 | 
								hvc_push(hp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							spin_unlock_irqrestore(&hp->lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (count)
 | 
				
			||||||
 | 
								cond_resched();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	spin_unlock_irqrestore(&hp->lock, flags);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Racy, but harmless, kick thread if there is still pending data.
 | 
						 * Racy, but harmless, kick thread if there is still pending data.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue