From: Thadeu Lima de Souza Cascardo Date: Fri, 21 May 2010 18:14:45 +0000 (-0400) Subject: Use a circular buffer. X-Git-Url: http://git.cascardo.eti.br/?p=cascardo%2Fkernel%2Fsamples%2Fchar2%2F.git;a=commitdiff_plain;h=91e474b7d6c004d5c0d3c5c1ff94721ad64d442d Use a circular buffer. --- diff --git a/hellochar.c b/hellochar.c index 1b0c9f2..de99828 100644 --- a/hellochar.c +++ b/hellochar.c @@ -22,32 +22,21 @@ #include #include #include +#include MODULE_LICENSE("GPL"); -#define MAXLEN 4000 +#define MAXLEN 4096 static dev_t devnum; static struct cdev *dev; static const char default_greeting[] = "Hello, World!\n"; -struct hello_buffer { - size_t len; - char buffer[0]; -}; -static struct hello_buffer *hello; +static struct circ_buf *hello; +static struct circ_buf hello_instance; static DEFINE_MUTEX(hello_mtx); static int hello_open(struct inode *ino, struct file *fp) { - if (mutex_lock_interruptible(&hello_mtx)) - return -ERESTARTSYS; - if (fp->f_flags & O_TRUNC) { - memset(hello->buffer, 0, MAXLEN); - hello->len = 0; - } - if (fp->f_flags & O_APPEND) - fp->f_pos = hello->len; - mutex_unlock(&hello_mtx); return 0; } @@ -55,15 +44,25 @@ static ssize_t hello_read(struct file *fp, char __user *buf, size_t sz, loff_t *pos) { int r; + size_t fsz; + size_t ssz; + size_t len; if (mutex_lock_interruptible(&hello_mtx)) return -ERESTARTSYS; - if (sz + *pos > hello->len) - sz = hello->len - *pos; - r = copy_to_user(buf, hello->buffer + *pos, sz); + len = CIRC_CNT(hello->head, hello->tail, MAXLEN); + if (sz > len) + sz = len; + /* First, copy at most until the limit of the buffer */ + fsz = min(sz, CIRC_CNT_TO_END(hello->head, hello->tail, MAXLEN)); + r = copy_to_user(buf, hello->buf + hello->tail, fsz); + ssz = sz - fsz; + if (!r && !ssz) + r = copy_to_user(buf + fsz, hello->buf, ssz); + if (!r) + hello->tail = (hello->tail + sz) & ~MAXLEN; mutex_unlock(&hello_mtx); if (r) return -EFAULT; - *pos += sz; return sz; } @@ -71,19 +70,24 @@ static ssize_t hello_write(struct file *fp, const char __user *buf, size_t sz, loff_t *pos) { int r; + size_t fsz; + size_t ssz; + size_t len; if (mutex_lock_interruptible(&hello_mtx)) return -ERESTARTSYS; - if (sz + *pos > MAXLEN) - sz = MAXLEN - *pos; - r = copy_from_user(hello->buffer + *pos, buf, sz); - if (r) { - mutex_unlock(&hello_mtx); - return -EFAULT; - } - *pos += sz; - if (hello->len < *pos) - hello->len = *pos; + len = CIRC_SPACE(hello->head, hello->tail, MAXLEN); + if (sz > len) + sz = len; + fsz = min(sz, CIRC_SPACE_TO_END(hello->head, hello->tail, MAXLEN)); + r = copy_from_user(hello->buf + hello->head, buf, fsz); + ssz = sz - fsz; + if (!r && !ssz) + r = copy_from_user(hello->buf, buf + fsz, ssz); + if (!r) + hello->head = (hello->head + sz) & ~MAXLEN; mutex_unlock(&hello_mtx); + if (r) + return -EFAULT; return sz; } @@ -103,13 +107,14 @@ static const struct file_operations hello_fops = { static int __init ch_init(void) { int r = 0; - hello = kzalloc(sizeof(*hello) + MAXLEN, GFP_KERNEL); + hello = &hello_instance; + hello->buf = kzalloc(sizeof(*hello) + MAXLEN, GFP_KERNEL); if (!hello) { r = -ENOMEM; goto out; } - memcpy(hello->buffer, default_greeting, sizeof(default_greeting)); - hello->len = sizeof(default_greeting); + memcpy(hello->buf, default_greeting, sizeof(default_greeting)); + hello->head = sizeof(default_greeting); r = alloc_chrdev_region(&devnum, 0, 256, "hello"); if (r) goto reg_out; @@ -122,7 +127,6 @@ static int __init ch_init(void) r = cdev_add(dev, devnum, 256); if (r) goto add_out; - printk(KERN_DEBUG "Allocate major %d\n", MAJOR(devnum)); return 0; add_out: kfree(dev);