From 5ddf83912c8b49a24ab0841f6d77f33781dcf10f Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Thu, 19 Aug 2010 14:13:28 -0700 Subject: kfifo: add kfifo_skip() testcase Add a testcase for kfifo_skip() to the byte stream fifo example. Signed-off-by: Andrea Righi Cc: Greg KH Acked-by: Stefani Seibold Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- samples/kfifo/bytestream-example.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'samples/kfifo') diff --git a/samples/kfifo/bytestream-example.c b/samples/kfifo/bytestream-example.c index 642eef3f6336..2e3a7a8128a2 100644 --- a/samples/kfifo/bytestream-example.c +++ b/samples/kfifo/bytestream-example.c @@ -73,6 +73,10 @@ static int __init testfunc(void) ret = kfifo_in(&test, buf, ret); printk(KERN_INFO "ret: %d\n", ret); + /* skip first element of the fifo */ + printk(KERN_INFO "skip 1st element\n"); + kfifo_skip(&test); + /* put values into the fifo until is full */ for (i = 20; kfifo_put(&test, &i); i++) ; -- cgit v1.2.3 From 2aaf2092c168fc02df0645415f524b357ee7ec2e Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Thu, 19 Aug 2010 14:13:29 -0700 Subject: kfifo: add explicit error checking in byte stream example Provide a static array of expected items that kfifo should contain at the end of the test to validate it. Signed-off-by: Andrea Righi Cc: Stefani Seibold Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- samples/kfifo/bytestream-example.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) (limited to 'samples/kfifo') diff --git a/samples/kfifo/bytestream-example.c b/samples/kfifo/bytestream-example.c index 2e3a7a8128a2..a94e6948b30d 100644 --- a/samples/kfifo/bytestream-example.c +++ b/samples/kfifo/bytestream-example.c @@ -44,10 +44,17 @@ static struct kfifo test; static DECLARE_KFIFO(test, unsigned char, FIFO_SIZE); #endif +static unsigned char expected_result[FIFO_SIZE] = { + 3, 4, 5, 6, 7, 8, 9, 0, + 1, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, +}; + static int __init testfunc(void) { unsigned char buf[6]; - unsigned char i; + unsigned char i, j; unsigned int ret; printk(KERN_INFO "byte stream fifo test start\n"); @@ -83,10 +90,19 @@ static int __init testfunc(void) printk(KERN_INFO "queue len: %u\n", kfifo_len(&test)); - /* print out all values in the fifo */ - while (kfifo_get(&test, &i)) - printk("%d ", i); - printk("\n"); + /* check the correctness of all values in the fifo */ + j = 0; + while (kfifo_get(&test, &i)) { + if (i != expected_result[j++]) { + printk(KERN_WARNING "value mismatch: test failed\n"); + return -EIO; + } + } + if (j != ARRAY_SIZE(expected_result)) { + printk(KERN_WARNING "size mismatch: test failed\n"); + return -EIO; + } + printk(KERN_INFO "test passed\n"); return 0; } @@ -142,7 +158,12 @@ static int __init example_init(void) #else INIT_KFIFO(test); #endif - testfunc(); + if (testfunc() < 0) { +#ifdef DYNAMIC + kfifo_free(&test); +#endif + return -EIO; + } if (proc_create(PROC_FIFO, 0, NULL, &fifo_fops) == NULL) { #ifdef DYNAMIC -- cgit v1.2.3 From 7b34d5257a90c419d67c1c3b52f87a679845ef1e Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Thu, 19 Aug 2010 14:13:29 -0700 Subject: kfifo: fix kernel BUG in dma example The scatterlist is used uninitialized in kfifo_dma_in_prepare(). This triggers the following bug if CONFIG_DEBUG_SG=y: ------------[ cut here ]------------ kernel BUG at include/linux/scatterlist.h:65! invalid opcode: 0000 [#1] PREEMPT SMP ... Call Trace: [] setup_sgl+0x6b/0xe0 [] ? example_init+0x0/0x265 [dma_example] [] __kfifo_dma_in_prepare+0x21/0x30 [] example_init+0x124/0x265 [dma_example] [] ? trace_module_notify+0x25/0x370 [] ? free_pages_prepare+0x11e/0x1e0 [] ? get_parent_ip+0x11/0x50 [] ? trace_module_notify+0x25/0x370 [] ? trace_hardirqs_on+0xd/0x10 [] ? mutex_unlock+0xe/0x10 [] ? trace_module_notify+0x41/0x370 [] ? __blocking_notifier_call_chain+0x45/0x80 [] ? vfree+0x2a/0x30 [] ? up_read+0x23/0x40 [] ? __blocking_notifier_call_chain+0x65/0x80 [] do_one_initcall+0x43/0x180 [] sys_init_module+0xba/0x200 [] system_call_fastpath+0x16/0x1b RIP [] setup_sgl_buf+0x1a1/0x1b0 RSP ---[ end trace a72b979fd3c1d3a5 ]--- Add the proper initialization to avoid the bug. Signed-off-by: Andrea Righi Acked-by: Stefani Seibold Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- samples/kfifo/dma-example.c | 1 + 1 file changed, 1 insertion(+) (limited to 'samples/kfifo') diff --git a/samples/kfifo/dma-example.c b/samples/kfifo/dma-example.c index b9482c28b41a..03433ca5bdad 100644 --- a/samples/kfifo/dma-example.c +++ b/samples/kfifo/dma-example.c @@ -45,6 +45,7 @@ static int __init example_init(void) printk(KERN_INFO "queue len: %u\n", kfifo_len(&fifo)); + sg_init_table(sg, ARRAY_SIZE(sg)); ret = kfifo_dma_in_prepare(&fifo, sg, ARRAY_SIZE(sg), FIFO_SIZE); printk(KERN_INFO "DMA sgl entries: %d\n", ret); -- cgit v1.2.3 From d83a71c4219191a9a881318ae5ca9b39aa1d0540 Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Thu, 19 Aug 2010 14:13:30 -0700 Subject: kfifo: fix a memory leak in dma example We use a dynamically allocated kfifo in the dma example, so we need to free it when unloading the module. Signed-off-by: Andrea Righi Acked-by: Stefani Seibold Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- samples/kfifo/dma-example.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'samples/kfifo') diff --git a/samples/kfifo/dma-example.c b/samples/kfifo/dma-example.c index 03433ca5bdad..3682278785f7 100644 --- a/samples/kfifo/dma-example.c +++ b/samples/kfifo/dma-example.c @@ -105,9 +105,7 @@ static int __init example_init(void) static void __exit example_exit(void) { -#ifdef DYNAMIC - kfifo_free(&test); -#endif + kfifo_free(&fifo); } module_init(example_init); -- cgit v1.2.3 From a25effa4d265eb5028c7d4a92a0ddd9267c3c43d Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Thu, 19 Aug 2010 14:13:30 -0700 Subject: kfifo: add explicit error checking in all the examples Provide a check in all the kfifo examples to validate the correct execution of each testcase. Signed-off-by: Andrea Righi Acked-by: Stefani Seibold Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- samples/kfifo/bytestream-example.c | 7 ++- samples/kfifo/dma-example.c | 106 +++++++++++++++++++++++-------------- samples/kfifo/inttype-example.c | 43 ++++++++++++--- samples/kfifo/record-example.c | 39 ++++++++++++-- 4 files changed, 144 insertions(+), 51 deletions(-) (limited to 'samples/kfifo') diff --git a/samples/kfifo/bytestream-example.c b/samples/kfifo/bytestream-example.c index a94e6948b30d..178061e87ffe 100644 --- a/samples/kfifo/bytestream-example.c +++ b/samples/kfifo/bytestream-example.c @@ -44,7 +44,7 @@ static struct kfifo test; static DECLARE_KFIFO(test, unsigned char, FIFO_SIZE); #endif -static unsigned char expected_result[FIFO_SIZE] = { +static const unsigned char expected_result[FIFO_SIZE] = { 3, 4, 5, 6, 7, 8, 9, 0, 1, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, @@ -90,9 +90,14 @@ static int __init testfunc(void) printk(KERN_INFO "queue len: %u\n", kfifo_len(&test)); + /* show the first value without removing from the fifo */ + if (kfifo_peek(&test, &i)) + printk(KERN_INFO "%d\n", i); + /* check the correctness of all values in the fifo */ j = 0; while (kfifo_get(&test, &i)) { + printk(KERN_INFO "item = %d\n", i); if (i != expected_result[j++]) { printk(KERN_WARNING "value mismatch: test failed\n"); return -EIO; diff --git a/samples/kfifo/dma-example.c b/samples/kfifo/dma-example.c index 3682278785f7..ee03a4f0b64f 100644 --- a/samples/kfifo/dma-example.c +++ b/samples/kfifo/dma-example.c @@ -29,8 +29,8 @@ static int __init example_init(void) printk(KERN_INFO "DMA fifo test start\n"); if (kfifo_alloc(&fifo, FIFO_SIZE, GFP_KERNEL)) { - printk(KERN_ERR "error kfifo_alloc\n"); - return 1; + printk(KERN_WARNING "error kfifo_alloc\n"); + return -ENOMEM; } printk(KERN_INFO "queue size: %u\n", kfifo_size(&fifo)); @@ -41,65 +41,93 @@ static int __init example_init(void) kfifo_put(&fifo, &i); /* kick away first byte */ - ret = kfifo_get(&fifo, &i); + kfifo_skip(&fifo); printk(KERN_INFO "queue len: %u\n", kfifo_len(&fifo)); + /* + * Configure the kfifo buffer to receive data from DMA input. + * + * .--------------------------------------. + * | 0 | 1 | 2 | ... | 12 | 13 | ... | 31 | + * |---|------------------|---------------| + * \_/ \________________/ \_____________/ + * \ \ \ + * \ \_allocated data \ + * \_*free space* \_*free space* + * + * We need two different SG entries: one for the free space area at the + * end of the kfifo buffer (19 bytes) and another for the first free + * byte at the beginning, after the kfifo_skip(). + */ sg_init_table(sg, ARRAY_SIZE(sg)); ret = kfifo_dma_in_prepare(&fifo, sg, ARRAY_SIZE(sg), FIFO_SIZE); printk(KERN_INFO "DMA sgl entries: %d\n", ret); + if (!ret) { + /* fifo is full and no sgl was created */ + printk(KERN_WARNING "error kfifo_dma_in_prepare\n"); + return -EIO; + } - /* if 0 was returned, fifo is full and no sgl was created */ - if (ret) { - printk(KERN_INFO "scatterlist for receive:\n"); - for (i = 0; i < ARRAY_SIZE(sg); i++) { - printk(KERN_INFO - "sg[%d] -> " - "page_link 0x%.8lx offset 0x%.8x length 0x%.8x\n", - i, sg[i].page_link, sg[i].offset, sg[i].length); + /* receive data */ + printk(KERN_INFO "scatterlist for receive:\n"); + for (i = 0; i < ARRAY_SIZE(sg); i++) { + printk(KERN_INFO + "sg[%d] -> " + "page_link 0x%.8lx offset 0x%.8x length 0x%.8x\n", + i, sg[i].page_link, sg[i].offset, sg[i].length); - if (sg_is_last(&sg[i])) - break; - } + if (sg_is_last(&sg[i])) + break; + } - /* but here your code to setup and exectute the dma operation */ - /* ... */ + /* put here your code to setup and exectute the dma operation */ + /* ... */ - /* example: zero bytes received */ - ret = 0; + /* example: zero bytes received */ + ret = 0; - /* finish the dma operation and update the received data */ - kfifo_dma_in_finish(&fifo, ret); - } + /* finish the dma operation and update the received data */ + kfifo_dma_in_finish(&fifo, ret); + /* Prepare to transmit data, example: 8 bytes */ ret = kfifo_dma_out_prepare(&fifo, sg, ARRAY_SIZE(sg), 8); printk(KERN_INFO "DMA sgl entries: %d\n", ret); + if (!ret) { + /* no data was available and no sgl was created */ + printk(KERN_WARNING "error kfifo_dma_out_prepare\n"); + return -EIO; + } - /* if 0 was returned, no data was available and no sgl was created */ - if (ret) { - printk(KERN_INFO "scatterlist for transmit:\n"); - for (i = 0; i < ARRAY_SIZE(sg); i++) { - printk(KERN_INFO - "sg[%d] -> " - "page_link 0x%.8lx offset 0x%.8x length 0x%.8x\n", - i, sg[i].page_link, sg[i].offset, sg[i].length); + printk(KERN_INFO "scatterlist for transmit:\n"); + for (i = 0; i < ARRAY_SIZE(sg); i++) { + printk(KERN_INFO + "sg[%d] -> " + "page_link 0x%.8lx offset 0x%.8x length 0x%.8x\n", + i, sg[i].page_link, sg[i].offset, sg[i].length); - if (sg_is_last(&sg[i])) - break; - } + if (sg_is_last(&sg[i])) + break; + } - /* but here your code to setup and exectute the dma operation */ - /* ... */ + /* put here your code to setup and exectute the dma operation */ + /* ... */ - /* example: 5 bytes transmitted */ - ret = 5; + /* example: 5 bytes transmitted */ + ret = 5; - /* finish the dma operation and update the transmitted data */ - kfifo_dma_out_finish(&fifo, ret); - } + /* finish the dma operation and update the transmitted data */ + kfifo_dma_out_finish(&fifo, ret); + ret = kfifo_len(&fifo); printk(KERN_INFO "queue len: %u\n", kfifo_len(&fifo)); + if (ret != 7) { + printk(KERN_WARNING "size mismatch: test failed"); + return -EIO; + } + printk(KERN_INFO "test passed\n"); + return 0; } diff --git a/samples/kfifo/inttype-example.c b/samples/kfifo/inttype-example.c index d6c5b7d9df64..71b2aabca96a 100644 --- a/samples/kfifo/inttype-example.c +++ b/samples/kfifo/inttype-example.c @@ -44,10 +44,17 @@ static DECLARE_KFIFO_PTR(test, int); static DEFINE_KFIFO(test, int, FIFO_SIZE); #endif +static const int expected_result[FIFO_SIZE] = { + 3, 4, 5, 6, 7, 8, 9, 0, + 1, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, +}; + static int __init testfunc(void) { int buf[6]; - int i; + int i, j; unsigned int ret; printk(KERN_INFO "int fifo test start\n"); @@ -66,8 +73,13 @@ static int __init testfunc(void) ret = kfifo_in(&test, buf, ret); printk(KERN_INFO "ret: %d\n", ret); - for (i = 20; i != 30; i++) - kfifo_put(&test, &i); + /* skip first element of the fifo */ + printk(KERN_INFO "skip 1st element\n"); + kfifo_skip(&test); + + /* put values into the fifo until is full */ + for (i = 20; kfifo_put(&test, &i); i++) + ; printk(KERN_INFO "queue len: %u\n", kfifo_len(&test)); @@ -75,10 +87,20 @@ static int __init testfunc(void) if (kfifo_peek(&test, &i)) printk(KERN_INFO "%d\n", i); - /* print out all values in the fifo */ - while (kfifo_get(&test, &i)) - printk("%d ", i); - printk("\n"); + /* check the correctness of all values in the fifo */ + j = 0; + while (kfifo_get(&test, &i)) { + printk(KERN_INFO "item = %d\n", i); + if (i != expected_result[j++]) { + printk(KERN_WARNING "value mismatch: test failed\n"); + return -EIO; + } + } + if (j != ARRAY_SIZE(expected_result)) { + printk(KERN_WARNING "size mismatch: test failed\n"); + return -EIO; + } + printk(KERN_INFO "test passed\n"); return 0; } @@ -132,7 +154,12 @@ static int __init example_init(void) return ret; } #endif - testfunc(); + if (testfunc() < 0) { +#ifdef DYNAMIC + kfifo_free(&test); +#endif + return -EIO; + } if (proc_create(PROC_FIFO, 0, NULL, &fifo_fops) == NULL) { #ifdef DYNAMIC diff --git a/samples/kfifo/record-example.c b/samples/kfifo/record-example.c index 32c6e0bda744..e68bd16a5da4 100644 --- a/samples/kfifo/record-example.c +++ b/samples/kfifo/record-example.c @@ -55,6 +55,19 @@ typedef STRUCT_KFIFO_REC_1(FIFO_SIZE) mytest; static mytest test; #endif +static const char *expected_result[] = { + "a", + "bb", + "ccc", + "dddd", + "eeeee", + "ffffff", + "ggggggg", + "hhhhhhhh", + "iiiiiiiii", + "jjjjjjjjjj", +}; + static int __init testfunc(void) { char buf[100]; @@ -75,6 +88,10 @@ static int __init testfunc(void) kfifo_in(&test, buf, i + 1); } + /* skip first element of the fifo */ + printk(KERN_INFO "skip 1st element\n"); + kfifo_skip(&test); + printk(KERN_INFO "fifo len: %u\n", kfifo_len(&test)); /* show the first record without removing from the fifo */ @@ -82,11 +99,22 @@ static int __init testfunc(void) if (ret) printk(KERN_INFO "%.*s\n", ret, buf); - /* print out all records in the fifo */ + /* check the correctness of all values in the fifo */ + i = 0; while (!kfifo_is_empty(&test)) { ret = kfifo_out(&test, buf, sizeof(buf)); - printk(KERN_INFO "%.*s\n", ret, buf); + buf[ret] = '\0'; + printk(KERN_INFO "item = %.*s\n", ret, buf); + if (strcmp(buf, expected_result[i++])) { + printk(KERN_WARNING "value mismatch: test failed\n"); + return -EIO; + } + } + if (i != ARRAY_SIZE(expected_result)) { + printk(KERN_WARNING "size mismatch: test failed\n"); + return -EIO; } + printk(KERN_INFO "test passed\n"); return 0; } @@ -142,7 +170,12 @@ static int __init example_init(void) #else INIT_KFIFO(test); #endif - testfunc(); + if (testfunc() < 0) { +#ifdef DYNAMIC + kfifo_free(&test); +#endif + return -EIO; + } if (proc_create(PROC_FIFO, 0, NULL, &fifo_fops) == NULL) { #ifdef DYNAMIC -- cgit v1.2.3