Thread (8 messages) 8 messages, 4 authors, 2012-11-06

Tools for checking incorrect usage of locking techniques in k-space

From: Anand Moon <hidden>
Date: 2012-11-05 07:24:40

?
Hi All,
?
While building the new kernel their are many option for kernel debugging 
?
please refer the below link.
?
http://my.safaribooksonline.com/book/operating-systems-and-server-administration/linux/9780137072446/kernel-hacking-config-options/ch11
?
Hope this will help you catch the lock problem.
?
-Anand Moon 

________________________________
 From: Vladimir Murzin [off-list ref]
To: Kumar amit mehta <redacted> 
Cc: Srivatsa Bhat <redacted>; kernelnewbies at kernelnewbies.org 
Sent: Monday, November 5, 2012 11:21 AM
Subject: Re: Tools for checking incorrect usage of locking techniques in k-space
  
On Tue, Oct 30, 2012 at 9:41 AM, Kumar amit mehta [off-list ref] wrote:
On Mon, Oct 29, 2012 at 12:03:08AM +0530, Srivatsa Bhat wrote:
quoted
You'll need CONFIG_LOCKDEP=y as well. An easy way to configure lock debugging
checks is to run 'make menuconfig' and enable the required options under the
"Kernel hacking" section.
quoted
If above configuration is all that I need, then should I be seeing warning/error
messages in kernel logs(/var/log/kern.log) when there is inconsistency in
locking ? To test my hypothesis, I modified my simple kernel module to
deliberately induce locking error (After initializing read-write semaphore, I call
down_write() and do not free this semaphore lock by commenting out up_write()
invocation). But still I don't see any error or warning message trace in kernel
logs, I think, I'm missing something.
Hi Srivatsa,

Thank you for your mail. As per your suggestion, this time I've enabled
CONFIG_LOCKDEP aslo in my running kernel and did the same experiment, but still
I dont't see any warning/error messages in the kernel log. To give you more idea
about what I'm doing, Please see the code below.(This is a simple char driver
based on LDD3 examples)

<echo.c>

#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h> //MAJOR, MINOR
#include <linux/fs.h> //register_chrdev_region, file_operations
#include <linux/moduleparam.h>
#include <linux/kernel.h> //container_of
#include <linux/slab.h> //kmalloc
#include <linux/cdev.h> //struct cdev
#include <linux/version.h>
#include <linux/uaccess.h> //copy_from/to_user()
#include <linux/errno.h> //error code

ssize_t echo_read(struct file *, char __user *, size_t, loff_t *);
ssize_t echo_write(struct file *, const char __user *, size_t, loff_t *);
int echo_open(struct inode *, struct file *);
int echo_release(struct inode *, struct file *);

struct echo_cdev {
? ? ? ?  char *data;
? ? ? ?  unsigned long size; //amount of data stored
? ? ? ?  struct semaphore sem;
? ? ? ?  struct cdev cdev;
};
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("amit");

int nr_major;
module_param(nr_major, int, S_IRUGO);
MODULE_PARM_DESC(nr_major, "major number");

int nr_minor;
char *chrdev_name = "echo";

static dev_t device;
static int echo_dev_count = 1;
struct echo_cdev *echo_dev = NULL;

static struct file_operations echo_fs_ops = {
? ? ? ?  .open = echo_open,
? ? ? ?  .release = echo_release,
? ? ? ?  .read = echo_read,
? ? ? ?  .write = echo_write,
? ? ? ?  .owner = THIS_MODULE,
};

int echo_open(struct inode *inode, struct file *filp)
{
? ? ? ?  struct echo_cdev *dev;
? ? ? ?  pr_debug("%s: f_flags: 0x%x\n",__FUNCTION__,filp->f_flags);
? ? ? ?  //container_of(pointer, container_type, container_field);
? ? ? ?  dev = container_of(inode->i_cdev, struct echo_cdev, cdev);
? ? ? ?  filp->private_data = dev;
? ? ? ?  if ((filp->f_flags & O_ACCMODE) == O_WRONLY) {
? ? ? ? ? ? ? ?  //trim the device size to 0
? ? ? ? ? ? ? ?  dev->size = 0;
? ? ? ?  }
? ? ? ?  return 0;
}

int echo_release(struct inode *inode, struct file *filp)
{
? ? ? ?  return 0;
}

ssize_t echo_read(struct file *filp, char __user *ubuff, size_t count, loff_t *poffset)
{
? ? ? ?  struct echo_cdev *dev = filp->private_data;
? ? ? ?  pr_debug("%s: f_flags: 0x%x\n",__FUNCTION__,filp->f_flags);

? ? ? ?  //user trying to access an offset which is beyond the end of file
? ? ? ?  if (down_interruptible(&dev->sem))
? ? ? ? ? ? ? ?  return -ERESTARTSYS;
? ? ? ?  if (*poffset >= dev->size) {
? ? ? ? ? ? ? ?  up(&dev->sem);
? ? ? ? ? ? ? ?  return 0;
? ? ? ?  }

? ? ? ?  //user trying to access more than eof, return bytes read till the eof
? ? ? ?  if (*poffset + count >= dev->size)
? ? ? ? ? ? ? ?  //count = dev->size - *poffset;
? ? ? ? ? ? ? ?  count = dev->size;
? ? ? ?  //kspace --> uspace
? ? ? ?  if (copy_to_user(ubuff, (dev->data + *poffset), count) < 0) {
? ? ? ? ? ? ? ?  up(&dev->sem);
? ? ? ? ? ? ? ?  return -EFAULT;
? ? ? ?  }
? ? ? ?  //update the offset
? ? ? ?  *poffset += count;
? ? ? ?  up(&dev->sem);
? ? ? ?  return count;
}

//count is the size of requested data transfer
ssize_t echo_write(struct file *filp, const char __user *ubuff, size_t count, loff_t *poffset)
{
? ? ? ?  int ret;
? ? ? ?  struct echo_cdev *dev = filp->private_data;
? ? ? ?  pr_debug("%s: f_flags: 0x%x\n",__FUNCTION__,filp->f_flags);
? ? ? ?  if (down_interruptible(&dev->sem))
? ? ? ? ? ? ? ?  return -ERESTARTSYS;
? ? ? ?  if (dev->data == NULL) {
? ? ? ? ? ? ? ?  dev->data = (char *)kmalloc(count, GFP_KERNEL);
? ? ? ? ? ? ? ?  if (!dev->data) {
? ? ? ? ? ? ? ? ? ? ? ?  up(&dev->sem);
? ? ? ? ? ? ? ? ? ? ? ?  return -ENOMEM;
? ? ? ? ? ? ? ?  } else {
? ? ? ? ? ? ? ? ? ? ? ?  memset(dev->data, 0, sizeof(count));
? ? ? ? ? ? ? ?  }
? ? ? ?  }
? ? ? ?  dev->size = count;
? ? ? ?  //uspace --> kspace
? ? ? ?  if (copy_from_user(dev->data, ubuff, count) < 0) {
? ? ? ? ? ? ? ?  up(&dev->sem);
? ? ? ? ? ? ? ?  return -EFAULT;
? ? ? ?  }

? ? ? ?  *poffset += count;
? ? ? ?  ret = count;

? ? ? ?  if (dev->size < *poffset)
? ? ? ? ? ? ? ?  dev->size = *poffset;
? ? ? ?  //Force lock error
? ? ? ?  //up(&dev->sem);
? ? ? ?  return ret;
}

static int __init echo_init(void)
{
? ? ? ?  int ret;
? ? ? ?  printk(KERN_EMERG "entering %s\n",__FUNCTION__);
? ? ? ?  //let the user provide the major number.
? ? ? ?  if (nr_major) {
? ? ? ? ? ? ? ?  device = MKDEV(nr_major, nr_minor);
? ? ? ? ? ? ? ?  if ((ret = register_chrdev_region(device, echo_dev_count, chrdev_name)) < 0) {
? ? ? ? ? ? ? ? ? ? ? ?  pr_debug("%s: failed to register %s\n",__FUNCTION__,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?  chrdev_name);
? ? ? ? ? ? ? ? ? ? ? ?  return ret;
? ? ? ? ? ? ? ?  }
? ? ? ?  } else {
? ? ? ? ? ? ? ?  ret = alloc_chrdev_region(&device, 0, echo_dev_count, chrdev_name);
? ? ? ? ? ? ? ?  if (ret < 0) {
? ? ? ? ? ? ? ? ? ? ? ?  pr_debug("%s: failed to register %s\n",__FUNCTION__,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?  chrdev_name);
? ? ? ? ? ? ? ? ? ? ? ?  return ret;
? ? ? ? ? ? ? ?  }
? ? ? ?  }
? ? ? ?  nr_major = MAJOR(device);
? ? ? ?  nr_minor = MINOR(device);
? ? ? ?  //print the major and minor numbers
? ? ? ?  pr_debug("%s: major/minor:: %d/%d\n",__FUNCTION__,
? ? ? ? ? ? ? ? ? ? ? ?  nr_major, nr_minor);
? ? ? ?  echo_dev = (struct echo_cdev *)kmalloc(sizeof(struct echo_cdev), GFP_KERNEL);
? ? ? ?  if (!echo_dev) {
? ? ? ? ? ? ? ?  printk(KERN_EMERG "Not enough memory\n");
? ? ? ? ? ? ? ?  unregister_chrdev_region(device, echo_dev_count);
? ? ? ? ? ? ? ?  return -ENOMEM;
? ? ? ?  }
? ? ? ?  memset(echo_dev, 0, sizeof(struct echo_cdev));
? ? ? ?  echo_dev->cdev.owner = THIS_MODULE;
? ? ? ?  echo_dev->cdev.ops = &echo_fs_ops;
? ? ? ?  //initialize the semaphore, before it is presented to the world
? ? ? ?  sema_init(&echo_dev->sem,1);
? ? ? ?  cdev_init(&echo_dev->cdev, &echo_fs_ops);
? ? ? ?  device = MKDEV(nr_major, nr_minor);
? ? ? ?  //tell the kernel about this char device
? ? ? ?  //telling the VFS layer to associate echo driver's fs operation for file r/w etc.
? ? ? ?  ret = cdev_add(&echo_dev->cdev, device, 1);
? ? ? ?  if (ret) {
? ? ? ? ? ? ? ?  kfree(echo_dev);
? ? ? ? ? ? ? ?  unregister_chrdev_region(device, echo_dev_count);
? ? ? ? ? ? ? ?  return ret;
? ? ? ?  }
? ? ? ?  return 0;
}

static void __exit echo_exit(void)
{
? ? ? ?  printk(KERN_EMERG "entering %s\n",__FUNCTION__);
? ? ? ?  if (echo_dev->data) {
? ? ? ? ? ? ? ?  printk("Inside %s: kfree()\n",__FUNCTION__);
? ? ? ? ? ? ? ?  kfree(echo_dev->data);
? ? ? ?  }
? ? ? ?  cdev_del(&echo_dev->cdev);
? ? ? ?  kfree(echo_dev);
? ? ? ?  unregister_chrdev_region(device, echo_dev_count);
}

module_init(echo_init);
module_exit(echo_exit);

<echo.c>

<Makefile>
obj-m := echo.o
CFLAGS_echo.o := -DDEBUG -Wall -Werror -Wmissing-prototypes \
? ? ? ?  -Wstrict-prototypes -Wunused-variable -O2 \
? ? ? ?  -Wunused-function -g

modules:
? ? ? ?  make -C /lib/modules/`uname -r`/build M=`pwd`
clean:
? ? ? ?  make -C /lib/modules/`uname -r`/build M=`pwd` clean
<Makefile>

Logs:
root at ubuntu:/boot# egrep -i "debug_kernel|lockdep"
config-3.7.0-rc3-next-20121029
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_DEBUG_KERNEL=y
CONFIG_LOCKDEP=y
# CONFIG_DEBUG_LOCKDEP is not set

root at ubuntu:/home/amit/ldd3/misc-modules/echo# uname -a
Linux ubuntu 3.7.0-rc3-next-20121029 #1 SMP Mon Oct 29 21:42:20 PDT 2012 i686
i686 i386 GNU/Linux

root at ubuntu:/home/amit/ldd3/misc-modules/echo# dmesg

root at ubuntu:/home/amit/ldd3/misc-modules/echo# insmod echo.ko

root at ubuntu:/home/amit/ldd3/misc-modules/echo# dmesg
[ 1156.704072] entering echo_init
[ 1156.704914] echo_init: major/minor:: 249/0

root at ubuntu:/home/amit/ldd3/misc-modules/echo# mknod /dev/echo c 249 0

root at ubuntu:/home/amit/ldd3/misc-modules/echo# ll /dev/echo
crw-r--r-- 1 root root 249, 0 Oct 29 22:29 /dev/echo

root at ubuntu:/home/amit/ldd3/misc-modules/echo# echo "kernel newbiee" >/dev/echo

root at ubuntu:/home/amit/ldd3/misc-modules/echo# dmesg
[ 1156.704072] entering echo_init
[ 1156.704914] echo_init: major/minor:: 249/0
[ 1237.377205] echo_open: f_flags: 0x8241
[ 1237.377392] echo_write: f_flags: 0x8001

root at ubuntu:/home/amit/ldd3/misc-modules/echo# cat /dev/echo
--> Here the driver read routine gets stuck as I've not reliquished the
semaphore lock

root at ubuntu:/home/amit/ldd3/misc-modules/echo# cat /dev/echo
^C <-- killing the user process

root at ubuntu:/home/amit/ldd3/misc-modules/echo# rmmod echo

root at ubuntu:/home/amit/ldd3/misc-modules/echo# dmesg
[ 1156.704072] entering echo_init
[ 1156.704914] echo_init: major/minor:: 249/0
[ 1237.377205] echo_open: f_flags: 0x8241
[ 1237.377392] echo_write: f_flags: 0x8001
[ 1270.622337] echo_open: f_flags: 0x8000
[ 1270.622477] echo_read: f_flags: 0x8000
[ 1394.180962] entering echo_exit
[ 1394.180996] Inside echo_exit: kfree()

As you can see, no warning/error messages reported by kernel.
-Amit

_______________________________________________
Kernelnewbies mailing list
Kernelnewbies at kernelnewbies.org
http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies
Hi

I've not tried your module, but I suppose that you should get warning
as soon as you try to take write semaphore once again.

Best wishes
Vladimir Murzin

_______________________________________________
Kernelnewbies mailing list
Kernelnewbies at kernelnewbies.org
http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.kernelnewbies.org/pipermail/kernelnewbies/attachments/20121104/1fe4d7dd/attachment-0001.html 
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help