<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Question about retry logic in usb-skeleton.c skel_read()]]></title><description><![CDATA[<p dir="auto">Hello,</p>
<p dir="auto">I'm a computer science undergraduate student studying Linux kernel USB device drivers.</p>
<p dir="auto">While analyzing the <code>skel_read()</code> function in <code>usb-skeleton.c</code>, I noticed what seems like inconsistent retry logic. I'd appreciate your insights.</p>
<h2>Current Behavior Analysis</h2>
<p dir="auto">The skeleton code operates as follows:</p>
<pre><code class="language-c">retry:
    if (dev-&gt;ongoing_read) {
        // Check O_NONBLOCK and wait
        if (file-&gt;f_flags &amp; O_NONBLOCK)
            return -EAGAIN;
        wait_event_interruptible(dev-&gt;bulk_in_wait, (!dev-&gt;ongoing_read));
    }
    
    // Copy data
    chunk = min(available, count);
    copy_to_user(buffer, dev-&gt;bulk_in_buffer, chunk);
    
    // When data is insufficient
    if (available &lt; count) {
        usb_do_read_io(dev, count - chunk);
        // No goto retry here!
    }
    return chunk;
</code></pre>
<h2>The Inconsistency</h2>
<p dir="auto"><strong>On entry</strong>: Waits for <code>ongoing_read</code> (or returns -EAGAIN if O_NONBLOCK)<br />
<strong>When data &lt; count</strong>: Submits URB but returns immediately without waiting</p>
<p dir="auto">These two behaviors seem inconsistent.</p>
<h2>Proposed Modification</h2>
<pre><code class="language-c">if (available &lt; count) {
    usb_do_read_io(dev, count - chunk);
    goto retry;  // &lt;- Add this
}
</code></pre>
<p dir="auto">This would:</p>
<ul>
<li>Handle O_NONBLOCK consistently at the retry label</li>
<li>Attempt to fulfill the requested count in blocking I/O mode</li>
<li>Allow signal interruption via <code>wait_event_interruptible</code></li>
</ul>
<h2>Questions</h2>
<ol>
<li>Is the current behavior intentional, or is it simplified for educational purposes?</li>
<li>Am I missing any negative side effects of adding <code>goto retry</code>?</li>
<li>Is there a USB Bulk transfer characteristic that requires enforcing Short Reads?</li>
</ol>
<p dir="auto">I appreciate any advice. Thank you!</p>
]]></description><link>https://kernelmeet.com/topic/6/question-about-retry-logic-in-usb-skeleton.c-skel_read</link><generator>RSS for Node</generator><lastBuildDate>Wed, 12 Aug 2026 18:04:18 GMT</lastBuildDate><atom:link href="https://kernelmeet.com/topic/6.rss" rel="self" type="application/rss+xml"/><pubDate>Mon, 29 Dec 2025 12:21:21 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Question about retry logic in usb-skeleton.c skel_read() on Tue, 13 Jan 2026 12:04:54 GMT]]></title><description><![CDATA[<p dir="auto">Hi, The behavior is intentional, not inconsistent.</p>
<p dir="auto">Looking at the actual source code, the driver handles three cases differently:</p>
<ol>
<li>No data at all → goto retry (must wait, can't return 0 which means EOF)</li>
<li>Buffer exhausted → goto retry (same reason)</li>
<li>Some data available → return it immediately, prefetch the rest</li>
</ol>
<p dir="auto">Why no goto retry in case 3?</p>
<ul>
<li>Returning 0 from read() signals EOF to userspace</li>
<li>When there's no data, the driver must wait—otherwise it would falsely indicate EOF</li>
<li>When there is data, returning a short read is standard POSIX behavior</li>
<li>The prefetch (skel_do_read_io) is an optimization for the next read call</li>
</ul>
<p dir="auto">Standard Unix read() semantics:</p>
<ul>
<li>read() may return fewer bytes than requested—this is normal</li>
<li>Userspace is expected to loop if it needs exactly N bytes</li>
<li>This applies to sockets, pipes, and character devices alike</li>
</ul>
<p dir="auto">Adding goto retry would work but would change the driver from "return data as soon as available" to "block until buffer is full"—which increases latency unnecessarily.</p>
<p dir="auto">Because it would need to wait for full buffer.</p>
<pre><code>//Userspace is expected to handle short reads:

  // Standard pattern - userspace loops, not the driver
  ssize_t read_full(int fd, void *buf, size_t count)
  {
      size_t total = 0;
      while (total &lt; count) {
          ssize_t ret = read(fd, buf + total, count - total);
          if (ret &lt; 0)  return ret;   // error
          if (ret == 0) break;        // EOF
          total += ret;
      }
      return total;
  }

</code></pre>
<pre><code>The problem:

 User calls: read(fd, buf, 100)
 Buffer has: 30 bytes

  First iteration:
    - Copy 30 bytes to buf[0..29]
    - rv = 30
    - goto retry...

  Second iteration (after new data arrives):
    - Copy to 'buffer' again (buf[0..??])  ← OVERWRITES first 30 bytes!
    - rv = new_chunk                        ← loses the original 30

  The userspace buffer pointer is never advanced. So goto retry would overwrite data already copied.
 
  copy_to_user(buffer, ...);  // First copy: buf[0]
  goto retry;
  copy_to_user(buffer, ...);  // Second copy: buf[0] again! Data corrupted.
</code></pre>
<p dir="auto">Even if you fixed the buffer pointer issue (by advancing it on each iteration), the modified behavior would still be undesirable because it changes the driver's semantics from "return data as available" to "block until full"</p>
]]></description><link>https://kernelmeet.com/post/19</link><guid isPermaLink="true">https://kernelmeet.com/post/19</guid><dc:creator><![CDATA[zerohexer]]></dc:creator><pubDate>Tue, 13 Jan 2026 12:04:54 GMT</pubDate></item></channel></rss>