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