diff options
-rw-r--r-- | drivers/tty/tty_buffer.c | 85 |
1 files changed, 65 insertions, 20 deletions
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 6c9b7cd6778a..91e326ffe7db 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c | |||
@@ -185,25 +185,19 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) | |||
185 | /* Should possibly check if this fails for the largest buffer we | 185 | /* Should possibly check if this fails for the largest buffer we |
186 | have queued and recycle that ? */ | 186 | have queued and recycle that ? */ |
187 | } | 187 | } |
188 | |||
189 | /** | 188 | /** |
190 | * tty_buffer_request_room - grow tty buffer if needed | 189 | * __tty_buffer_request_room - grow tty buffer if needed |
191 | * @tty: tty structure | 190 | * @tty: tty structure |
192 | * @size: size desired | 191 | * @size: size desired |
193 | * | 192 | * |
194 | * Make at least size bytes of linear space available for the tty | 193 | * Make at least size bytes of linear space available for the tty |
195 | * buffer. If we fail return the size we managed to find. | 194 | * buffer. If we fail return the size we managed to find. |
196 | * | 195 | * Locking: Caller must hold tty->buf.lock |
197 | * Locking: Takes tty->buf.lock | ||
198 | */ | 196 | */ |
199 | int tty_buffer_request_room(struct tty_struct *tty, size_t size) | 197 | static int __tty_buffer_request_room(struct tty_struct *tty, size_t size) |
200 | { | 198 | { |
201 | struct tty_buffer *b, *n; | 199 | struct tty_buffer *b, *n; |
202 | int left; | 200 | int left; |
203 | unsigned long flags; | ||
204 | |||
205 | spin_lock_irqsave(&tty->buf.lock, flags); | ||
206 | |||
207 | /* OPTIMISATION: We could keep a per tty "zero" sized buffer to | 201 | /* OPTIMISATION: We could keep a per tty "zero" sized buffer to |
208 | remove this conditional if its worth it. This would be invisible | 202 | remove this conditional if its worth it. This would be invisible |
209 | to the callers */ | 203 | to the callers */ |
@@ -225,9 +219,30 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size) | |||
225 | size = left; | 219 | size = left; |
226 | } | 220 | } |
227 | 221 | ||
228 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
229 | return size; | 222 | return size; |
230 | } | 223 | } |
224 | |||
225 | |||
226 | /** | ||
227 | * tty_buffer_request_room - grow tty buffer if needed | ||
228 | * @tty: tty structure | ||
229 | * @size: size desired | ||
230 | * | ||
231 | * Make at least size bytes of linear space available for the tty | ||
232 | * buffer. If we fail return the size we managed to find. | ||
233 | * | ||
234 | * Locking: Takes tty->buf.lock | ||
235 | */ | ||
236 | int tty_buffer_request_room(struct tty_struct *tty, size_t size) | ||
237 | { | ||
238 | unsigned long flags; | ||
239 | int length; | ||
240 | |||
241 | spin_lock_irqsave(&tty->buf.lock, flags); | ||
242 | length = __tty_buffer_request_room(tty, size); | ||
243 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
244 | return length; | ||
245 | } | ||
231 | EXPORT_SYMBOL_GPL(tty_buffer_request_room); | 246 | EXPORT_SYMBOL_GPL(tty_buffer_request_room); |
232 | 247 | ||
233 | /** | 248 | /** |
@@ -249,14 +264,22 @@ int tty_insert_flip_string_fixed_flag(struct tty_struct *tty, | |||
249 | int copied = 0; | 264 | int copied = 0; |
250 | do { | 265 | do { |
251 | int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); | 266 | int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); |
252 | int space = tty_buffer_request_room(tty, goal); | 267 | int space; |
253 | struct tty_buffer *tb = tty->buf.tail; | 268 | unsigned long flags; |
269 | struct tty_buffer *tb; | ||
270 | |||
271 | spin_lock_irqsave(&tty->buf.lock, flags); | ||
272 | space = __tty_buffer_request_room(tty, goal); | ||
273 | tb = tty->buf.tail; | ||
254 | /* If there is no space then tb may be NULL */ | 274 | /* If there is no space then tb may be NULL */ |
255 | if (unlikely(space == 0)) | 275 | if (unlikely(space == 0)) { |
276 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
256 | break; | 277 | break; |
278 | } | ||
257 | memcpy(tb->char_buf_ptr + tb->used, chars, space); | 279 | memcpy(tb->char_buf_ptr + tb->used, chars, space); |
258 | memset(tb->flag_buf_ptr + tb->used, flag, space); | 280 | memset(tb->flag_buf_ptr + tb->used, flag, space); |
259 | tb->used += space; | 281 | tb->used += space; |
282 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
260 | copied += space; | 283 | copied += space; |
261 | chars += space; | 284 | chars += space; |
262 | /* There is a small chance that we need to split the data over | 285 | /* There is a small chance that we need to split the data over |
@@ -286,14 +309,22 @@ int tty_insert_flip_string_flags(struct tty_struct *tty, | |||
286 | int copied = 0; | 309 | int copied = 0; |
287 | do { | 310 | do { |
288 | int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); | 311 | int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); |
289 | int space = tty_buffer_request_room(tty, goal); | 312 | int space; |
290 | struct tty_buffer *tb = tty->buf.tail; | 313 | unsigned long __flags; |
314 | struct tty_buffer *tb; | ||
315 | |||
316 | spin_lock_irqsave(&tty->buf.lock, __flags); | ||
317 | space = __tty_buffer_request_room(tty, goal); | ||
318 | tb = tty->buf.tail; | ||
291 | /* If there is no space then tb may be NULL */ | 319 | /* If there is no space then tb may be NULL */ |
292 | if (unlikely(space == 0)) | 320 | if (unlikely(space == 0)) { |
321 | spin_unlock_irqrestore(&tty->buf.lock, __flags); | ||
293 | break; | 322 | break; |
323 | } | ||
294 | memcpy(tb->char_buf_ptr + tb->used, chars, space); | 324 | memcpy(tb->char_buf_ptr + tb->used, chars, space); |
295 | memcpy(tb->flag_buf_ptr + tb->used, flags, space); | 325 | memcpy(tb->flag_buf_ptr + tb->used, flags, space); |
296 | tb->used += space; | 326 | tb->used += space; |
327 | spin_unlock_irqrestore(&tty->buf.lock, __flags); | ||
297 | copied += space; | 328 | copied += space; |
298 | chars += space; | 329 | chars += space; |
299 | flags += space; | 330 | flags += space; |
@@ -344,13 +375,20 @@ EXPORT_SYMBOL(tty_schedule_flip); | |||
344 | int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, | 375 | int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, |
345 | size_t size) | 376 | size_t size) |
346 | { | 377 | { |
347 | int space = tty_buffer_request_room(tty, size); | 378 | int space; |
379 | unsigned long flags; | ||
380 | struct tty_buffer *tb; | ||
381 | |||
382 | spin_lock_irqsave(&tty->buf.lock, flags); | ||
383 | space = __tty_buffer_request_room(tty, size); | ||
384 | |||
385 | tb = tty->buf.tail; | ||
348 | if (likely(space)) { | 386 | if (likely(space)) { |
349 | struct tty_buffer *tb = tty->buf.tail; | ||
350 | *chars = tb->char_buf_ptr + tb->used; | 387 | *chars = tb->char_buf_ptr + tb->used; |
351 | memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); | 388 | memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); |
352 | tb->used += space; | 389 | tb->used += space; |
353 | } | 390 | } |
391 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
354 | return space; | 392 | return space; |
355 | } | 393 | } |
356 | EXPORT_SYMBOL_GPL(tty_prepare_flip_string); | 394 | EXPORT_SYMBOL_GPL(tty_prepare_flip_string); |
@@ -374,13 +412,20 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string); | |||
374 | int tty_prepare_flip_string_flags(struct tty_struct *tty, | 412 | int tty_prepare_flip_string_flags(struct tty_struct *tty, |
375 | unsigned char **chars, char **flags, size_t size) | 413 | unsigned char **chars, char **flags, size_t size) |
376 | { | 414 | { |
377 | int space = tty_buffer_request_room(tty, size); | 415 | int space; |
416 | unsigned long __flags; | ||
417 | struct tty_buffer *tb; | ||
418 | |||
419 | spin_lock_irqsave(&tty->buf.lock, __flags); | ||
420 | space = __tty_buffer_request_room(tty, size); | ||
421 | |||
422 | tb = tty->buf.tail; | ||
378 | if (likely(space)) { | 423 | if (likely(space)) { |
379 | struct tty_buffer *tb = tty->buf.tail; | ||
380 | *chars = tb->char_buf_ptr + tb->used; | 424 | *chars = tb->char_buf_ptr + tb->used; |
381 | *flags = tb->flag_buf_ptr + tb->used; | 425 | *flags = tb->flag_buf_ptr + tb->used; |
382 | tb->used += space; | 426 | tb->used += space; |
383 | } | 427 | } |
428 | spin_unlock_irqrestore(&tty->buf.lock, __flags); | ||
384 | return space; | 429 | return space; |
385 | } | 430 | } |
386 | EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); | 431 | EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); |