aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/vt/vc_screen.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/vt/vc_screen.c')
-rw-r--r--drivers/tty/vt/vc_screen.c111
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
54struct vcs_poll_data { 54struct 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 */
138static struct vc_data*
139vcs_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 */
134static int 161static int
135vcs_size(struct inode *inode) 162vcs_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;
356unlock_out: 381unlock_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
544unlock_out: 569unlock_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