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.c110
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
54struct vcs_poll_data { 55struct 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 */
139static struct vc_data*
140vcs_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 */
134static int 162static int
135vcs_size(struct inode *inode) 163vcs_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;
356unlock_out: 382unlock_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
544unlock_out: 570unlock_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