diff options
Diffstat (limited to 'drivers/tty/vt/vc_screen.c')
-rw-r--r-- | drivers/tty/vt/vc_screen.c | 110 |
1 files changed, 67 insertions, 43 deletions
diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c index a672ed192d33..7b3bfbe2e6de 100644 --- a/drivers/tty/vt/vc_screen.c +++ b/drivers/tty/vt/vc_screen.c | |||
@@ -28,7 +28,6 @@ | |||
28 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
29 | #include <linux/mm.h> | 29 | #include <linux/mm.h> |
30 | #include <linux/init.h> | 30 | #include <linux/init.h> |
31 | #include <linux/mutex.h> | ||
32 | #include <linux/vt_kern.h> | 31 | #include <linux/vt_kern.h> |
33 | #include <linux/selection.h> | 32 | #include <linux/selection.h> |
34 | #include <linux/kbd_kern.h> | 33 | #include <linux/kbd_kern.h> |
@@ -51,6 +50,8 @@ | |||
51 | #undef addr | 50 | #undef addr |
52 | #define HEADER_SIZE 4 | 51 | #define HEADER_SIZE 4 |
53 | 52 | ||
53 | #define CON_BUF_SIZE (CONFIG_BASE_SMALL ? 256 : PAGE_SIZE) | ||
54 | |||
54 | struct vcs_poll_data { | 55 | struct vcs_poll_data { |
55 | struct notifier_block notifier; | 56 | struct notifier_block notifier; |
56 | unsigned int cons_num; | 57 | unsigned int cons_num; |
@@ -131,21 +132,45 @@ vcs_poll_data_get(struct file *file) | |||
131 | return poll; | 132 | return poll; |
132 | } | 133 | } |
133 | 134 | ||
135 | /* | ||
136 | * Returns VC for inode. | ||
137 | * Must be called with console_lock. | ||
138 | */ | ||
139 | static struct vc_data* | ||
140 | vcs_vc(struct inode *inode, int *viewed) | ||
141 | { | ||
142 | unsigned int currcons = iminor(inode) & 127; | ||
143 | |||
144 | WARN_CONSOLE_UNLOCKED(); | ||
145 | |||
146 | if (currcons == 0) { | ||
147 | currcons = fg_console; | ||
148 | if (viewed) | ||
149 | *viewed = 1; | ||
150 | } else { | ||
151 | currcons--; | ||
152 | if (viewed) | ||
153 | *viewed = 0; | ||
154 | } | ||
155 | return vc_cons[currcons].d; | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * Returns size for VC carried by inode. | ||
160 | * Must be called with console_lock. | ||
161 | */ | ||
134 | static int | 162 | static int |
135 | vcs_size(struct inode *inode) | 163 | vcs_size(struct inode *inode) |
136 | { | 164 | { |
137 | int size; | 165 | int size; |
138 | int minor = iminor(inode); | 166 | int minor = iminor(inode); |
139 | int currcons = minor & 127; | ||
140 | struct vc_data *vc; | 167 | struct vc_data *vc; |
141 | 168 | ||
142 | if (currcons == 0) | 169 | WARN_CONSOLE_UNLOCKED(); |
143 | currcons = fg_console; | 170 | |
144 | else | 171 | vc = vcs_vc(inode, NULL); |
145 | currcons--; | 172 | if (!vc) |
146 | if (!vc_cons_allocated(currcons)) | ||
147 | return -ENXIO; | 173 | return -ENXIO; |
148 | vc = vc_cons[currcons].d; | ||
149 | 174 | ||
150 | size = vc->vc_rows * vc->vc_cols; | 175 | size = vc->vc_rows * vc->vc_cols; |
151 | 176 | ||
@@ -158,11 +183,13 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig) | |||
158 | { | 183 | { |
159 | int size; | 184 | int size; |
160 | 185 | ||
161 | mutex_lock(&con_buf_mtx); | 186 | console_lock(); |
162 | size = vcs_size(file->f_path.dentry->d_inode); | 187 | size = vcs_size(file->f_path.dentry->d_inode); |
188 | console_unlock(); | ||
189 | if (size < 0) | ||
190 | return size; | ||
163 | switch (orig) { | 191 | switch (orig) { |
164 | default: | 192 | default: |
165 | mutex_unlock(&con_buf_mtx); | ||
166 | return -EINVAL; | 193 | return -EINVAL; |
167 | case 2: | 194 | case 2: |
168 | offset += size; | 195 | offset += size; |
@@ -173,11 +200,9 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig) | |||
173 | break; | 200 | break; |
174 | } | 201 | } |
175 | if (offset < 0 || offset > size) { | 202 | if (offset < 0 || offset > size) { |
176 | mutex_unlock(&con_buf_mtx); | ||
177 | return -EINVAL; | 203 | return -EINVAL; |
178 | } | 204 | } |
179 | file->f_pos = offset; | 205 | file->f_pos = offset; |
180 | mutex_unlock(&con_buf_mtx); | ||
181 | return file->f_pos; | 206 | return file->f_pos; |
182 | } | 207 | } |
183 | 208 | ||
@@ -190,12 +215,15 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | |||
190 | struct vc_data *vc; | 215 | struct vc_data *vc; |
191 | struct vcs_poll_data *poll; | 216 | struct vcs_poll_data *poll; |
192 | long pos; | 217 | long pos; |
193 | long viewed, attr, read; | 218 | long attr, read; |
194 | int col, maxcol; | 219 | int col, maxcol, viewed; |
195 | unsigned short *org = NULL; | 220 | unsigned short *org = NULL; |
196 | ssize_t ret; | 221 | ssize_t ret; |
222 | char *con_buf; | ||
197 | 223 | ||
198 | mutex_lock(&con_buf_mtx); | 224 | con_buf = (char *) __get_free_page(GFP_KERNEL); |
225 | if (!con_buf) | ||
226 | return -ENOMEM; | ||
199 | 227 | ||
200 | pos = *ppos; | 228 | pos = *ppos; |
201 | 229 | ||
@@ -205,18 +233,10 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | |||
205 | console_lock(); | 233 | console_lock(); |
206 | 234 | ||
207 | attr = (currcons & 128); | 235 | attr = (currcons & 128); |
208 | currcons = (currcons & 127); | ||
209 | if (currcons == 0) { | ||
210 | currcons = fg_console; | ||
211 | viewed = 1; | ||
212 | } else { | ||
213 | currcons--; | ||
214 | viewed = 0; | ||
215 | } | ||
216 | ret = -ENXIO; | 236 | ret = -ENXIO; |
217 | if (!vc_cons_allocated(currcons)) | 237 | vc = vcs_vc(inode, &viewed); |
238 | if (!vc) | ||
218 | goto unlock_out; | 239 | goto unlock_out; |
219 | vc = vc_cons[currcons].d; | ||
220 | 240 | ||
221 | ret = -EINVAL; | 241 | ret = -EINVAL; |
222 | if (pos < 0) | 242 | if (pos < 0) |
@@ -237,6 +257,12 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | |||
237 | * could sleep. | 257 | * could sleep. |
238 | */ | 258 | */ |
239 | size = vcs_size(inode); | 259 | size = vcs_size(inode); |
260 | if (size < 0) { | ||
261 | if (read) | ||
262 | break; | ||
263 | ret = size; | ||
264 | goto unlock_out; | ||
265 | } | ||
240 | if (pos >= size) | 266 | if (pos >= size) |
241 | break; | 267 | break; |
242 | if (count > size - pos) | 268 | if (count > size - pos) |
@@ -355,7 +381,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | |||
355 | ret = read; | 381 | ret = read; |
356 | unlock_out: | 382 | unlock_out: |
357 | console_unlock(); | 383 | console_unlock(); |
358 | mutex_unlock(&con_buf_mtx); | 384 | free_page((unsigned long) con_buf); |
359 | return ret; | 385 | return ret; |
360 | } | 386 | } |
361 | 387 | ||
@@ -366,13 +392,16 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | |||
366 | unsigned int currcons = iminor(inode); | 392 | unsigned int currcons = iminor(inode); |
367 | struct vc_data *vc; | 393 | struct vc_data *vc; |
368 | long pos; | 394 | long pos; |
369 | long viewed, attr, size, written; | 395 | long attr, size, written; |
370 | char *con_buf0; | 396 | char *con_buf0; |
371 | int col, maxcol; | 397 | int col, maxcol, viewed; |
372 | u16 *org0 = NULL, *org = NULL; | 398 | u16 *org0 = NULL, *org = NULL; |
373 | size_t ret; | 399 | size_t ret; |
400 | char *con_buf; | ||
374 | 401 | ||
375 | mutex_lock(&con_buf_mtx); | 402 | con_buf = (char *) __get_free_page(GFP_KERNEL); |
403 | if (!con_buf) | ||
404 | return -ENOMEM; | ||
376 | 405 | ||
377 | pos = *ppos; | 406 | pos = *ppos; |
378 | 407 | ||
@@ -382,19 +411,10 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | |||
382 | console_lock(); | 411 | console_lock(); |
383 | 412 | ||
384 | attr = (currcons & 128); | 413 | attr = (currcons & 128); |
385 | currcons = (currcons & 127); | ||
386 | |||
387 | if (currcons == 0) { | ||
388 | currcons = fg_console; | ||
389 | viewed = 1; | ||
390 | } else { | ||
391 | currcons--; | ||
392 | viewed = 0; | ||
393 | } | ||
394 | ret = -ENXIO; | 414 | ret = -ENXIO; |
395 | if (!vc_cons_allocated(currcons)) | 415 | vc = vcs_vc(inode, &viewed); |
416 | if (!vc) | ||
396 | goto unlock_out; | 417 | goto unlock_out; |
397 | vc = vc_cons[currcons].d; | ||
398 | 418 | ||
399 | size = vcs_size(inode); | 419 | size = vcs_size(inode); |
400 | ret = -EINVAL; | 420 | ret = -EINVAL; |
@@ -436,6 +456,12 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | |||
436 | * Return data written up to now on failure. | 456 | * Return data written up to now on failure. |
437 | */ | 457 | */ |
438 | size = vcs_size(inode); | 458 | size = vcs_size(inode); |
459 | if (size < 0) { | ||
460 | if (written) | ||
461 | break; | ||
462 | ret = size; | ||
463 | goto unlock_out; | ||
464 | } | ||
439 | if (pos >= size) | 465 | if (pos >= size) |
440 | break; | 466 | break; |
441 | if (this_round > size - pos) | 467 | if (this_round > size - pos) |
@@ -543,9 +569,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | |||
543 | 569 | ||
544 | unlock_out: | 570 | unlock_out: |
545 | console_unlock(); | 571 | console_unlock(); |
546 | 572 | free_page((unsigned long) con_buf); | |
547 | mutex_unlock(&con_buf_mtx); | ||
548 | |||
549 | return ret; | 573 | return ret; |
550 | } | 574 | } |
551 | 575 | ||