tty,vcs removing con_buf/conf_buf_mtx
seems there's no longer need for using con_buf/conf_buf_mtx as vcs_read/vcs_write buffer for user's data. The do_con_write function, that was the other user of this, is currently using its own kmalloc-ed buffer. Not sure when this got changed, as I was able to find this code in 2.6.9, but it's already gone as far as current git history goes - 2.6.12-rc2. AFAICS there's a behaviour change with the current change. The lseek is not completely mutually exclusive with the vcs_read/vcs_write - the file->f_pos might get updated via lseek callback during the vcs_read/vcs_write processing. I tried to find out if the prefered behaviour is to keep this in sync within read/write/lseek functions, but I did not find any pattern on different places. I guess if user end up calling write/lseek from different threads she should know what she's doing. If needed we could use dedicated fd mutex/buffer. Signed-off-by: Jiri Olsa <jolsa@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
dc1892c4bc
commit
fcdba07ee3
@ -28,7 +28,6 @@
|
|||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/mutex.h>
|
|
||||||
#include <linux/vt_kern.h>
|
#include <linux/vt_kern.h>
|
||||||
#include <linux/selection.h>
|
#include <linux/selection.h>
|
||||||
#include <linux/kbd_kern.h>
|
#include <linux/kbd_kern.h>
|
||||||
@ -51,6 +50,8 @@
|
|||||||
#undef addr
|
#undef addr
|
||||||
#define HEADER_SIZE 4
|
#define HEADER_SIZE 4
|
||||||
|
|
||||||
|
#define CON_BUF_SIZE (CONFIG_BASE_SMALL ? 256 : PAGE_SIZE)
|
||||||
|
|
||||||
struct vcs_poll_data {
|
struct vcs_poll_data {
|
||||||
struct notifier_block notifier;
|
struct notifier_block notifier;
|
||||||
unsigned int cons_num;
|
unsigned int cons_num;
|
||||||
@ -131,21 +132,45 @@ vcs_poll_data_get(struct file *file)
|
|||||||
return poll;
|
return poll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns VC for inode.
|
||||||
|
* Must be called with console_lock.
|
||||||
|
*/
|
||||||
|
static struct vc_data*
|
||||||
|
vcs_vc(struct inode *inode, int *viewed)
|
||||||
|
{
|
||||||
|
unsigned int currcons = iminor(inode) & 127;
|
||||||
|
|
||||||
|
WARN_CONSOLE_UNLOCKED();
|
||||||
|
|
||||||
|
if (currcons == 0) {
|
||||||
|
currcons = fg_console;
|
||||||
|
if (viewed)
|
||||||
|
*viewed = 1;
|
||||||
|
} else {
|
||||||
|
currcons--;
|
||||||
|
if (viewed)
|
||||||
|
*viewed = 0;
|
||||||
|
}
|
||||||
|
return vc_cons[currcons].d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns size for VC carried by inode.
|
||||||
|
* Must be called with console_lock.
|
||||||
|
*/
|
||||||
static int
|
static int
|
||||||
vcs_size(struct inode *inode)
|
vcs_size(struct inode *inode)
|
||||||
{
|
{
|
||||||
int size;
|
int size;
|
||||||
int minor = iminor(inode);
|
int minor = iminor(inode);
|
||||||
int currcons = minor & 127;
|
|
||||||
struct vc_data *vc;
|
struct vc_data *vc;
|
||||||
|
|
||||||
if (currcons == 0)
|
WARN_CONSOLE_UNLOCKED();
|
||||||
currcons = fg_console;
|
|
||||||
else
|
vc = vcs_vc(inode, NULL);
|
||||||
currcons--;
|
if (!vc)
|
||||||
if (!vc_cons_allocated(currcons))
|
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
vc = vc_cons[currcons].d;
|
|
||||||
|
|
||||||
size = vc->vc_rows * vc->vc_cols;
|
size = vc->vc_rows * vc->vc_cols;
|
||||||
|
|
||||||
@ -158,17 +183,13 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
|
|||||||
{
|
{
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
mutex_lock(&con_buf_mtx);
|
|
||||||
console_lock();
|
console_lock();
|
||||||
size = vcs_size(file->f_path.dentry->d_inode);
|
size = vcs_size(file->f_path.dentry->d_inode);
|
||||||
console_unlock();
|
console_unlock();
|
||||||
if (size < 0) {
|
if (size < 0)
|
||||||
mutex_unlock(&con_buf_mtx);
|
|
||||||
return size;
|
return size;
|
||||||
}
|
|
||||||
switch (orig) {
|
switch (orig) {
|
||||||
default:
|
default:
|
||||||
mutex_unlock(&con_buf_mtx);
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
case 2:
|
case 2:
|
||||||
offset += size;
|
offset += size;
|
||||||
@ -179,11 +200,9 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (offset < 0 || offset > size) {
|
if (offset < 0 || offset > size) {
|
||||||
mutex_unlock(&con_buf_mtx);
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
file->f_pos = offset;
|
file->f_pos = offset;
|
||||||
mutex_unlock(&con_buf_mtx);
|
|
||||||
return file->f_pos;
|
return file->f_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,12 +215,15 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
|
|||||||
struct vc_data *vc;
|
struct vc_data *vc;
|
||||||
struct vcs_poll_data *poll;
|
struct vcs_poll_data *poll;
|
||||||
long pos;
|
long pos;
|
||||||
long viewed, attr, read;
|
long attr, read;
|
||||||
int col, maxcol;
|
int col, maxcol, viewed;
|
||||||
unsigned short *org = NULL;
|
unsigned short *org = NULL;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
char *con_buf;
|
||||||
|
|
||||||
mutex_lock(&con_buf_mtx);
|
con_buf = (char *) __get_free_page(GFP_KERNEL);
|
||||||
|
if (!con_buf)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
pos = *ppos;
|
pos = *ppos;
|
||||||
|
|
||||||
@ -211,18 +233,10 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
|
|||||||
console_lock();
|
console_lock();
|
||||||
|
|
||||||
attr = (currcons & 128);
|
attr = (currcons & 128);
|
||||||
currcons = (currcons & 127);
|
|
||||||
if (currcons == 0) {
|
|
||||||
currcons = fg_console;
|
|
||||||
viewed = 1;
|
|
||||||
} else {
|
|
||||||
currcons--;
|
|
||||||
viewed = 0;
|
|
||||||
}
|
|
||||||
ret = -ENXIO;
|
ret = -ENXIO;
|
||||||
if (!vc_cons_allocated(currcons))
|
vc = vcs_vc(inode, &viewed);
|
||||||
|
if (!vc)
|
||||||
goto unlock_out;
|
goto unlock_out;
|
||||||
vc = vc_cons[currcons].d;
|
|
||||||
|
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
if (pos < 0)
|
if (pos < 0)
|
||||||
@ -367,7 +381,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
|
|||||||
ret = read;
|
ret = read;
|
||||||
unlock_out:
|
unlock_out:
|
||||||
console_unlock();
|
console_unlock();
|
||||||
mutex_unlock(&con_buf_mtx);
|
free_page((unsigned long) con_buf);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,13 +392,16 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
|
|||||||
unsigned int currcons = iminor(inode);
|
unsigned int currcons = iminor(inode);
|
||||||
struct vc_data *vc;
|
struct vc_data *vc;
|
||||||
long pos;
|
long pos;
|
||||||
long viewed, attr, size, written;
|
long attr, size, written;
|
||||||
char *con_buf0;
|
char *con_buf0;
|
||||||
int col, maxcol;
|
int col, maxcol, viewed;
|
||||||
u16 *org0 = NULL, *org = NULL;
|
u16 *org0 = NULL, *org = NULL;
|
||||||
size_t ret;
|
size_t ret;
|
||||||
|
char *con_buf;
|
||||||
|
|
||||||
mutex_lock(&con_buf_mtx);
|
con_buf = (char *) __get_free_page(GFP_KERNEL);
|
||||||
|
if (!con_buf)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
pos = *ppos;
|
pos = *ppos;
|
||||||
|
|
||||||
@ -394,19 +411,10 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
|
|||||||
console_lock();
|
console_lock();
|
||||||
|
|
||||||
attr = (currcons & 128);
|
attr = (currcons & 128);
|
||||||
currcons = (currcons & 127);
|
|
||||||
|
|
||||||
if (currcons == 0) {
|
|
||||||
currcons = fg_console;
|
|
||||||
viewed = 1;
|
|
||||||
} else {
|
|
||||||
currcons--;
|
|
||||||
viewed = 0;
|
|
||||||
}
|
|
||||||
ret = -ENXIO;
|
ret = -ENXIO;
|
||||||
if (!vc_cons_allocated(currcons))
|
vc = vcs_vc(inode, &viewed);
|
||||||
|
if (!vc)
|
||||||
goto unlock_out;
|
goto unlock_out;
|
||||||
vc = vc_cons[currcons].d;
|
|
||||||
|
|
||||||
size = vcs_size(inode);
|
size = vcs_size(inode);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
@ -561,9 +569,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
|
|||||||
|
|
||||||
unlock_out:
|
unlock_out:
|
||||||
console_unlock();
|
console_unlock();
|
||||||
|
free_page((unsigned long) con_buf);
|
||||||
mutex_unlock(&con_buf_mtx);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2068,18 +2068,6 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is a temporary buffer used to prepare a tty console write
|
|
||||||
* so that we can easily avoid touching user space while holding the
|
|
||||||
* console spinlock. It is allocated in con_init and is shared by
|
|
||||||
* this code and the vc_screen read/write tty calls.
|
|
||||||
*
|
|
||||||
* We have to allocate this statically in the kernel data section
|
|
||||||
* since console_init (and thus con_init) are called before any
|
|
||||||
* kernel memory allocation is available.
|
|
||||||
*/
|
|
||||||
char con_buf[CON_BUF_SIZE];
|
|
||||||
DEFINE_MUTEX(con_buf_mtx);
|
|
||||||
|
|
||||||
/* is_double_width() is based on the wcwidth() implementation by
|
/* is_double_width() is based on the wcwidth() implementation by
|
||||||
* Markus Kuhn -- 2007-05-26 (Unicode 5.0)
|
* Markus Kuhn -- 2007-05-26 (Unicode 5.0)
|
||||||
* Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
|
* Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
|
||||||
|
@ -142,14 +142,6 @@ static inline bool vt_force_oops_output(struct vc_data *vc)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* vc_screen.c shares this temporary buffer with the console write code so that
|
|
||||||
* we can easily avoid touching user space while holding the console spinlock.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define CON_BUF_SIZE (CONFIG_BASE_SMALL ? 256 : PAGE_SIZE)
|
|
||||||
extern char con_buf[CON_BUF_SIZE];
|
|
||||||
extern struct mutex con_buf_mtx;
|
|
||||||
extern char vt_dont_switch;
|
extern char vt_dont_switch;
|
||||||
extern int default_utf8;
|
extern int default_utf8;
|
||||||
extern int global_cursor_default;
|
extern int global_cursor_default;
|
||||||
|
Loading…
Reference in New Issue
Block a user