|
@@ -265,6 +265,17 @@ static int check_tty_count(struct tty_struct *tty, const char *routine)
|
|
|
*/
|
|
|
|
|
|
|
|
|
+/**
|
|
|
+ * tty_buffer_free_all - free buffers used by a tty
|
|
|
+ * @tty: tty to free from
|
|
|
+ *
|
|
|
+ * Remove all the buffers pending on a tty whether queued with data
|
|
|
+ * or in the free ring. Must be called when the tty is no longer in use
|
|
|
+ *
|
|
|
+ * Locking: none
|
|
|
+ */
|
|
|
+
|
|
|
+
|
|
|
/**
|
|
|
* tty_buffer_free_all - free buffers used by a tty
|
|
|
* @tty: tty to free from
|
|
@@ -287,19 +298,47 @@ static void tty_buffer_free_all(struct tty_struct *tty)
|
|
|
kfree(thead);
|
|
|
}
|
|
|
tty->buf.tail = NULL;
|
|
|
+ tty->buf.memory_used = 0;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * tty_buffer_init - prepare a tty buffer structure
|
|
|
+ * @tty: tty to initialise
|
|
|
+ *
|
|
|
+ * Set up the initial state of the buffer management for a tty device.
|
|
|
+ * Must be called before the other tty buffer functions are used.
|
|
|
+ *
|
|
|
+ * Locking: none
|
|
|
+ */
|
|
|
+
|
|
|
static void tty_buffer_init(struct tty_struct *tty)
|
|
|
{
|
|
|
spin_lock_init(&tty->buf.lock);
|
|
|
tty->buf.head = NULL;
|
|
|
tty->buf.tail = NULL;
|
|
|
tty->buf.free = NULL;
|
|
|
+ tty->buf.memory_used = 0;
|
|
|
}
|
|
|
|
|
|
-static struct tty_buffer *tty_buffer_alloc(size_t size)
|
|
|
+/**
|
|
|
+ * tty_buffer_alloc - allocate a tty buffer
|
|
|
+ * @tty: tty device
|
|
|
+ * @size: desired size (characters)
|
|
|
+ *
|
|
|
+ * Allocate a new tty buffer to hold the desired number of characters.
|
|
|
+ * Return NULL if out of memory or the allocation would exceed the
|
|
|
+ * per device queue
|
|
|
+ *
|
|
|
+ * Locking: Caller must hold tty->buf.lock
|
|
|
+ */
|
|
|
+
|
|
|
+static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
|
|
|
{
|
|
|
- struct tty_buffer *p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
|
|
|
+ struct tty_buffer *p;
|
|
|
+
|
|
|
+ if (tty->buf.memory_used + size > 65536)
|
|
|
+ return NULL;
|
|
|
+ p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
|
|
|
if(p == NULL)
|
|
|
return NULL;
|
|
|
p->used = 0;
|
|
@@ -309,17 +348,27 @@ static struct tty_buffer *tty_buffer_alloc(size_t size)
|
|
|
p->read = 0;
|
|
|
p->char_buf_ptr = (char *)(p->data);
|
|
|
p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
|
|
|
-/* printk("Flip create %p\n", p); */
|
|
|
+ tty->buf.memory_used += size;
|
|
|
return p;
|
|
|
}
|
|
|
|
|
|
-/* Must be called with the tty_read lock held. This needs to acquire strategy
|
|
|
- code to decide if we should kfree or relink a given expired buffer */
|
|
|
+/**
|
|
|
+ * tty_buffer_free - free a tty buffer
|
|
|
+ * @tty: tty owning the buffer
|
|
|
+ * @b: the buffer to free
|
|
|
+ *
|
|
|
+ * Free a tty buffer, or add it to the free list according to our
|
|
|
+ * internal strategy
|
|
|
+ *
|
|
|
+ * Locking: Caller must hold tty->buf.lock
|
|
|
+ */
|
|
|
|
|
|
static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
|
|
|
{
|
|
|
/* Dumb strategy for now - should keep some stats */
|
|
|
-/* printk("Flip dispose %p\n", b); */
|
|
|
+ tty->buf.memory_used -= b->size;
|
|
|
+ WARN_ON(tty->buf.memory_used < 0);
|
|
|
+
|
|
|
if(b->size >= 512)
|
|
|
kfree(b);
|
|
|
else {
|
|
@@ -328,6 +377,18 @@ static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * tty_buffer_find - find a free tty buffer
|
|
|
+ * @tty: tty owning the buffer
|
|
|
+ * @size: characters wanted
|
|
|
+ *
|
|
|
+ * Locate an existing suitable tty buffer or if we are lacking one then
|
|
|
+ * allocate a new one. We round our buffers off in 256 character chunks
|
|
|
+ * to get better allocation behaviour.
|
|
|
+ *
|
|
|
+ * Locking: Caller must hold tty->buf.lock
|
|
|
+ */
|
|
|
+
|
|
|
static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
|
|
|
{
|
|
|
struct tty_buffer **tbh = &tty->buf.free;
|
|
@@ -339,20 +400,28 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
|
|
|
t->used = 0;
|
|
|
t->commit = 0;
|
|
|
t->read = 0;
|
|
|
- /* DEBUG ONLY */
|
|
|
-/* memset(t->data, '*', size); */
|
|
|
-/* printk("Flip recycle %p\n", t); */
|
|
|
+ tty->buf.memory_used += t->size;
|
|
|
return t;
|
|
|
}
|
|
|
tbh = &((*tbh)->next);
|
|
|
}
|
|
|
/* Round the buffer size out */
|
|
|
size = (size + 0xFF) & ~ 0xFF;
|
|
|
- return tty_buffer_alloc(size);
|
|
|
+ return tty_buffer_alloc(tty, size);
|
|
|
/* Should possibly check if this fails for the largest buffer we
|
|
|
have queued and recycle that ? */
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * tty_buffer_request_room - grow tty buffer if needed
|
|
|
+ * @tty: tty structure
|
|
|
+ * @size: size desired
|
|
|
+ *
|
|
|
+ * Make at least size bytes of linear space available for the tty
|
|
|
+ * buffer. If we fail return the size we managed to find.
|
|
|
+ *
|
|
|
+ * Locking: Takes tty->buf.lock
|
|
|
+ */
|
|
|
int tty_buffer_request_room(struct tty_struct *tty, size_t size)
|
|
|
{
|
|
|
struct tty_buffer *b, *n;
|