title: Multiple read a single write causes a deadlock in Linux character driver?
body: <p>I am working on a sample Linux module based on a character device driver (using misc driver for ease of use) and I find some unusual behavior. </p>
  
  <p>I have open, read, write and release function for file operations and my misc device is named as test_device </p>
  
  <p>My device has a ring buffer which can store data from a write system call and a read system call can read the data. If the buffer is full then the process invoking the write system call sleeps and if the buffer is empty then the process invoking the read system call sleeps. </p>
  
  <p>There is a semaphore (with count 1 like mutex) to avoid multiple reads and hence race condition. This works well without any problem for a single read and single write process</p>
  
  <p>Now I open the device as 2 instances of read using the command</p>
  
  <pre><code>cat /dev/test_device 
  </code></pre>
  
  <p>as expected the second cat process sleeps. I have a single process to write </p>
  
  <pre><code>ls &gt; /dev/test_device
  </code></pre>
  
  <p>The ls command even do not call the open system call. Could anybody kindly explain me the reason why open system call fails.</p>
  
  <p>The code is listed below</p>
  
  <pre><code>static int hr_open(struct inode *inode, struct file *file)
  {
      pr_info("process %i (%s) enters open\n", current-&gt;pid, current-&gt;comm);
      if (file-&gt;f_mode &amp; FMODE_READ) down_interruptible(&amp;rd_sem);
  
      pr_info("process %i (%s) leaves open\n", current-&gt;pid, current-&gt;comm);
  
      return 0;
  }
  
  static int hr_release(struct inode *inode, struct file *file)
  {
      pr_info("process %i (%s) enters release\n", current-&gt;pid, current-&gt;comm);
      if (file-&gt;f_mode &amp; FMODE_READ) up(&amp;rd_sem);
  
      pr_info("process %i (%s) leaves release\n", current-&gt;pid, current-&gt;comm);
  
      return 0;
  }
  
  static ssize_t hr_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
  {
      pr_info("process %i (%s) enters read\n", current-&gt;pid, current-&gt;comm);
  
      if (wait_event_interruptible(wq_rd, head != tail))
          return -ERESTARTSYS;    
  
      if (put_user(buff[head], buffer)) 
          return -EFAULT;
  
      head = (head + 1) % BUFF_SIZE;
  
      wake_up_interruptible(&amp;wq_wr);
      pr_info("process %i (%s) leaves read\n", current-&gt;pid, current-&gt;comm);
  
      return 1;
  }
  
  static ssize_t hr_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
  {
      pr_info("process %i (%s) enters write\n", current-&gt;pid, current-&gt;comm);
  
      if (wait_event_interruptible(wq_wr, tail != ((head + 1) % BUFF_SIZE)))
          return -ERESTARTSYS;    
  
      if (get_user(buff[tail], buffer)) 
          return -EFAULT; 
  
      tail = (tail + 1) % BUFF_SIZE;
  
      wake_up_interruptible(&amp;wq_rd);
      pr_info("process %i (%s) leaves write\n", current-&gt;pid, current-&gt;comm);
  
      return 1;
  }
  </code></pre>