﻿<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
>
	<channel>
		<title></title>
		<description>aligned words
</description>
		<sy:updatePeriod>weekly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
		<link>https://kdave.github.io</link>
		<atom:link href="https://kdave.github.io/rss-all.xml" rel="self" type="application/rss+xml" />
		
		<lastBuildDate>Sat, 11 Jan 2025 00:00:00 +0100</lastBuildDate>
		
			<item>
				<title>Escaped snapper snapshots</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;Happened to me, that space on my root partition was going low, no matter what I
removed. I have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;snapper&lt;/code&gt; hourly snapshots enabled, tuned the daily and weekly
settings, so the usual problem of running out of space is prevented. Also
before doing a big update of Tumbleweed (openSUSE rolling distro) I check the
available space to roughly match what &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zypper&lt;/code&gt; says it’d need.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ snapper ls
Type   | #   | Pre # | Date                             | User | Cleanup  | Description  | Userdata
-------+-----+-------+----------------------------------+------+----------+--------------+--------------
single | 0   |       |                                  | root |          | current      |
single | 395 |       | Mon 26 Sep 2016 10:30:01 PM CEST | root | timeline | timeline     |
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So what happened? I was removing some old kernels, manually by rpm. And it
started to report write errors, no space. Indeed, df reported just 64K
available. This is within the margin of accuracy that we’re able to get from
the statfs syscall.  Side note, getting this right is a lot of guesswork, so 64K
is as good as it gets.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ df -h /
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        30G   30G   64K  86% /
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;RPM continued to spew lots of errors, I removed rest of the snapper snapshots,
no improvement. So then I resorted to the bare ‘btrfs’ command and found a stale
snapper snapshot. The snapshot directory itself was there, but the metadata
were lacking (a xml file). After deleting it manually, the free space jumped up
by 6GB!&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# btrfs subvol list /
...
... .snapshots/3721/snapshot
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The theory is that I have once removed all snapshots so the numbering started
from 1 again, as the current series is around ~390, while the number of stale
snapshot is much higher.&lt;/p&gt;

&lt;p&gt;Takeaways:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;synthetic tools may not give our an accurate view: snapper requires some
metadata describing its snapshot, which is obviously OK, given that the user
has the freedom to create snapshots anywhere&lt;/li&gt;
  &lt;li&gt;learn how to use the low-level tools to cross-verify the state of the system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Summary of used tools:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;snapper ls&lt;/code&gt; – show all snapper snapshots (for the first config)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;snapper delete&lt;/code&gt; – delete snapshots by id or range&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;btrfs subvolume list&lt;/code&gt; – list all subvolumes (snapshots included) on a given path&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;btrfs subvolume delete&lt;/code&gt; – delete a subvolume/snapshot by path&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Update 2017-09-05&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Again. There were 2 stale snapper snapshots, age of like 8 months until
discovered. The space got up by 12GiB after deletion. The root partition is
50GiB, I think it survived pretty long given the frequent updates of the rolling
distro. There’s an &lt;a href=&quot;https://github.com/openSUSE/snapper/issues/98&quot;&gt;open issue&lt;/a&gt;.&lt;/p&gt;
</description>
				<pubDate>Sat, 05 Nov 2016 00:00:00 +0100</pubDate>
				<link>https://kdave.github.io/escaped-snapper-snapshots/</link>
				<guid isPermaLink="true">https://kdave.github.io/escaped-snapper-snapshots/</guid>
			</item>
		
			<item>
				<title>errno.h for the masses</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;errno&lt;/code&gt; values, in various formats you may encounter. The standard errno is
a positive number, linux kernel uses the negative values. Besides the sources
(going through like 5 include hops from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/include/errno.h&lt;/code&gt; to
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/include/asm-generic/errno.h&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/include/asm-generic/errno-base.h&lt;/code&gt;)
there’s no direct way to get the symbolic &amp;lt;-&amp;gt; numeric mapping. The hexa values
commonly appear in the stack trace dumps.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;symbolic&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;dec&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;hex&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;neg hex&lt;/th&gt;
      &lt;th&gt;comment&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;EPERM&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;1&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x01&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffff&lt;/td&gt;
      &lt;td&gt;Operation not permitted&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOENT&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;2&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x02&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..fffe&lt;/td&gt;
      &lt;td&gt;No such file or directory&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ESRCH&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;3&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x03&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..fffd&lt;/td&gt;
      &lt;td&gt;No such process&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EINTR&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;4&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x04&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..fffc&lt;/td&gt;
      &lt;td&gt;Interrupted system call&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EIO&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;5&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x05&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..fffb&lt;/td&gt;
      &lt;td&gt;I/O error&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENXIO&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;6&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x06&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..fffa&lt;/td&gt;
      &lt;td&gt;No such device or address&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;E2BIG&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;7&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x07&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..fff9&lt;/td&gt;
      &lt;td&gt;Argument list too long&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOEXEC&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;8&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x08&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..fff8&lt;/td&gt;
      &lt;td&gt;Exec format error&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EBADF&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;9&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x09&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..fff7&lt;/td&gt;
      &lt;td&gt;Bad file number&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ECHILD&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;10&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x0a&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..fff6&lt;/td&gt;
      &lt;td&gt;No child processes&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EAGAIN&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;11&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x0b&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..fff5&lt;/td&gt;
      &lt;td&gt;Try again&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOMEM&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;12&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x0c&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..fff4&lt;/td&gt;
      &lt;td&gt;Out of memory&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EACCES&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;13&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x0d&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..fff3&lt;/td&gt;
      &lt;td&gt;Permission denied&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EFAULT&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;14&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x0e&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..fff2&lt;/td&gt;
      &lt;td&gt;Bad address&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOTBLK&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;15&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x0f&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..fff1&lt;/td&gt;
      &lt;td&gt;Block device required&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EBUSY&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;16&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x10&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..fff0&lt;/td&gt;
      &lt;td&gt;Device or resource busy&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EEXIST&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;17&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x11&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffef&lt;/td&gt;
      &lt;td&gt;File exists&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EXDEV&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;18&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x12&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffee&lt;/td&gt;
      &lt;td&gt;Cross-device link&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENODEV&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;19&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x13&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffed&lt;/td&gt;
      &lt;td&gt;No such device&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOTDIR&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;20&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x14&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffec&lt;/td&gt;
      &lt;td&gt;Not a directory&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EISDIR&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;21&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x15&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffeb&lt;/td&gt;
      &lt;td&gt;Is a directory&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EINVAL&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;22&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x16&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffea&lt;/td&gt;
      &lt;td&gt;Invalid argument&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENFILE&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;23&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x17&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffe9&lt;/td&gt;
      &lt;td&gt;File table overflow&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EMFILE&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;24&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x18&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffe8&lt;/td&gt;
      &lt;td&gt;Too many open files&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOTTY&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;25&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x19&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffe7&lt;/td&gt;
      &lt;td&gt;Not a typewriter&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ETXTBSY&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;26&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x1a&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffe6&lt;/td&gt;
      &lt;td&gt;Text file busy&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EFBIG&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;27&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x1b&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffe5&lt;/td&gt;
      &lt;td&gt;File too large&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOSPC&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;28&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x1c&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffe4&lt;/td&gt;
      &lt;td&gt;No space left on device&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ESPIPE&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;29&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x1d&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffe3&lt;/td&gt;
      &lt;td&gt;Illegal seek&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EROFS&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;30&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x1e&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffe2&lt;/td&gt;
      &lt;td&gt;Read-only file system&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EMLINK&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;31&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x1f&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffe1&lt;/td&gt;
      &lt;td&gt;Too many links&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EPIPE&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;32&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x20&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffe0&lt;/td&gt;
      &lt;td&gt;Broken pipe&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EDOM&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;33&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x21&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffdf&lt;/td&gt;
      &lt;td&gt;Math argument out of domain of func&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ERANGE&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;34&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x22&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffde&lt;/td&gt;
      &lt;td&gt;Math result not representable&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EDEADLK&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;35&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x23&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffdd&lt;/td&gt;
      &lt;td&gt;Resource deadlock would occur&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENAMETOOLONG&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;36&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x24&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffdc&lt;/td&gt;
      &lt;td&gt;File name too long&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOLCK&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;37&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x25&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffdb&lt;/td&gt;
      &lt;td&gt;No record locks available&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOSYS&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;38&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x26&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffda&lt;/td&gt;
      &lt;td&gt;Function not implemented&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOTEMPTY&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;39&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x27&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffd9&lt;/td&gt;
      &lt;td&gt;Directory not empty&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ELOOP&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;40&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x28&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffd8&lt;/td&gt;
      &lt;td&gt;Too many symbolic links encountered&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EWOULDBLOCK&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;EAGAIN&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt; &lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOMSG&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;42&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x2a&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffd6&lt;/td&gt;
      &lt;td&gt;No message of desired type&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EIDRM&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;43&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x2b&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffd5&lt;/td&gt;
      &lt;td&gt;Identifier removed&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ECHRNG&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;44&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x2c&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffd4&lt;/td&gt;
      &lt;td&gt;Channel number out of range&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EL2NSYNC&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;45&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x2d&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffd3&lt;/td&gt;
      &lt;td&gt;Level 2 not synchronized&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EL3HLT&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;46&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x2e&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffd2&lt;/td&gt;
      &lt;td&gt;Level 3 halted&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EL3RST&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;47&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x2f&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffd1&lt;/td&gt;
      &lt;td&gt;Level 3 reset&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ELNRNG&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;48&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x30&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffd0&lt;/td&gt;
      &lt;td&gt;Link number out of range&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EUNATCH&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;49&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x31&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffcf&lt;/td&gt;
      &lt;td&gt;Protocol driver not attached&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOCSI&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;50&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x32&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffce&lt;/td&gt;
      &lt;td&gt;No CSI structure available&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EL2HLT&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;51&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x33&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffcd&lt;/td&gt;
      &lt;td&gt;Level 2 halted&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EBADE&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;52&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x34&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffcc&lt;/td&gt;
      &lt;td&gt;Invalid exchange&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EBADR&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;53&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x35&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffcb&lt;/td&gt;
      &lt;td&gt;Invalid request descriptor&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EXFULL&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;54&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x36&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffca&lt;/td&gt;
      &lt;td&gt;Exchange full&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOANO&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;55&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x37&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffc9&lt;/td&gt;
      &lt;td&gt;No anode&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EBADRQC&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;56&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x38&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffc8&lt;/td&gt;
      &lt;td&gt;Invalid request code&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EBADSLT&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;57&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x39&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffc7&lt;/td&gt;
      &lt;td&gt;Invalid slot&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EDEADLOCK&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;EDEADLK&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt; &lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EBFONT&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;59&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x3b&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffc5&lt;/td&gt;
      &lt;td&gt;Bad font file format&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOSTR&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;60&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x3c&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffc4&lt;/td&gt;
      &lt;td&gt;Device not a stream&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENODATA&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;61&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x3d&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffc3&lt;/td&gt;
      &lt;td&gt;No data available&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ETIME&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;62&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x3e&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffc2&lt;/td&gt;
      &lt;td&gt;Timer expired&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOSR&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;63&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x3f&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffc1&lt;/td&gt;
      &lt;td&gt;Out of streams resources&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENONET&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;64&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x40&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffc0&lt;/td&gt;
      &lt;td&gt;Machine is not on the network&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOPKG&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;65&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x41&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffbf&lt;/td&gt;
      &lt;td&gt;Package not installed&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EREMOTE&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;66&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x42&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffbe&lt;/td&gt;
      &lt;td&gt;Object is remote&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOLINK&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;67&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x43&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffbd&lt;/td&gt;
      &lt;td&gt;Link has been severed&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EADV&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;68&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x44&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffbc&lt;/td&gt;
      &lt;td&gt;Advertise error&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ESRMNT&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;69&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x45&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffbb&lt;/td&gt;
      &lt;td&gt;Srmount error&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ECOMM&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;70&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x46&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffba&lt;/td&gt;
      &lt;td&gt;Communication error on send&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EPROTO&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;71&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x47&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffb9&lt;/td&gt;
      &lt;td&gt;Protocol error&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EMULTIHOP&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;72&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x48&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffb8&lt;/td&gt;
      &lt;td&gt;Multihop attempted&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EDOTDOT&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;73&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x49&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffb7&lt;/td&gt;
      &lt;td&gt;RFS specific error&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EBADMSG&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;74&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x4a&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffb6&lt;/td&gt;
      &lt;td&gt;Not a data message&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EOVERFLOW&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;75&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x4b&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffb5&lt;/td&gt;
      &lt;td&gt;Value too large for defined data type&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOTUNIQ&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;76&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x4c&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffb4&lt;/td&gt;
      &lt;td&gt;Name not unique on network&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EBADFD&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;77&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x4d&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffb3&lt;/td&gt;
      &lt;td&gt;File descriptor in bad state&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EREMCHG&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;78&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x4e&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffb2&lt;/td&gt;
      &lt;td&gt;Remote address changed&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ELIBACC&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;79&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x4f&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffb1&lt;/td&gt;
      &lt;td&gt;Can not access a needed shared library&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ELIBBAD&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;80&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x50&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffb0&lt;/td&gt;
      &lt;td&gt;Accessing a corrupted shared library&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ELIBSCN&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;81&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x51&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffaf&lt;/td&gt;
      &lt;td&gt;.lib section in a.out corrupted&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ELIBMAX&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;82&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x52&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffae&lt;/td&gt;
      &lt;td&gt;Attempting to link in too many shared libraries&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ELIBEXEC&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;83&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x53&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffad&lt;/td&gt;
      &lt;td&gt;Cannot exec a shared library directly&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EILSEQ&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;84&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x54&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffac&lt;/td&gt;
      &lt;td&gt;Illegal byte sequence&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ERESTART&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;85&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x55&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffab&lt;/td&gt;
      &lt;td&gt;Interrupted system call should be restarted&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ESTRPIPE&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;86&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x56&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffaa&lt;/td&gt;
      &lt;td&gt;Streams pipe error&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EUSERS&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;87&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x57&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffa9&lt;/td&gt;
      &lt;td&gt;Too many users&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOTSOCK&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;88&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x58&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffa8&lt;/td&gt;
      &lt;td&gt;Socket operation on non-socket&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EDESTADDRREQ&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;89&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x59&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffa7&lt;/td&gt;
      &lt;td&gt;Destination address required&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EMSGSIZE&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;90&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x5a&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffa6&lt;/td&gt;
      &lt;td&gt;Message too long&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EPROTOTYPE&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;91&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x5b&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffa5&lt;/td&gt;
      &lt;td&gt;Protocol wrong type for socket&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOPROTOOPT&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;92&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x5c&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffa4&lt;/td&gt;
      &lt;td&gt;Protocol not available&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EPROTONOSUPPORT&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;93&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x5d&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffa3&lt;/td&gt;
      &lt;td&gt;Protocol not supported&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ESOCKTNOSUPPORT&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;94&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x5e&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffa2&lt;/td&gt;
      &lt;td&gt;Socket type not supported&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EOPNOTSUPP&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;95&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x5f&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffa1&lt;/td&gt;
      &lt;td&gt;Operation not supported on transport endpoint&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EPFNOSUPPORT&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;96&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x60&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ffa0&lt;/td&gt;
      &lt;td&gt;Protocol family not supported&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EAFNOSUPPORT&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;97&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x61&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff9f&lt;/td&gt;
      &lt;td&gt;Address family not supported by protocol&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EADDRINUSE&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;98&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x62&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff9e&lt;/td&gt;
      &lt;td&gt;Address already in use&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EADDRNOTAVAIL&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;99&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x63&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff9d&lt;/td&gt;
      &lt;td&gt;Cannot assign requested address&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENETDOWN&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;100&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x64&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff9c&lt;/td&gt;
      &lt;td&gt;Network is down&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENETUNREACH&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;101&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x65&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff9b&lt;/td&gt;
      &lt;td&gt;Network is unreachable&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENETRESET&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;102&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x66&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff9a&lt;/td&gt;
      &lt;td&gt;Network dropped connection because of reset&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ECONNABORTED&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;103&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x67&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff99&lt;/td&gt;
      &lt;td&gt;Software caused connection abort&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ECONNRESET&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;104&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x68&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff98&lt;/td&gt;
      &lt;td&gt;Connection reset by peer&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOBUFS&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;105&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x69&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff97&lt;/td&gt;
      &lt;td&gt;No buffer space available&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EISCONN&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;106&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x6a&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff96&lt;/td&gt;
      &lt;td&gt;Transport endpoint is already connected&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOTCONN&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;107&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x6b&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff95&lt;/td&gt;
      &lt;td&gt;Transport endpoint is not connected&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ESHUTDOWN&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;108&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x6c&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff94&lt;/td&gt;
      &lt;td&gt;Cannot send after transport endpoint shutdown&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ETOOMANYREFS&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;109&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x6d&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff93&lt;/td&gt;
      &lt;td&gt;Too many references: cannot splice&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ETIMEDOUT&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;110&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x6e&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff92&lt;/td&gt;
      &lt;td&gt;Connection timed out&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ECONNREFUSED&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;111&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x6f&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff91&lt;/td&gt;
      &lt;td&gt;Connection refused&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EHOSTDOWN&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;112&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x70&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff90&lt;/td&gt;
      &lt;td&gt;Host is down&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EHOSTUNREACH&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;113&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x71&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff8f&lt;/td&gt;
      &lt;td&gt;No route to host&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EALREADY&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;114&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x72&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff8e&lt;/td&gt;
      &lt;td&gt;Operation already in progress&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EINPROGRESS&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;115&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x73&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff8d&lt;/td&gt;
      &lt;td&gt;Operation now in progress&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ESTALE&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;116&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x74&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff8c&lt;/td&gt;
      &lt;td&gt;Stale NFS file handle&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EUCLEAN&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;117&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x75&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff8b&lt;/td&gt;
      &lt;td&gt;Structure needs cleaning&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOTNAM&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;118&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x76&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff8a&lt;/td&gt;
      &lt;td&gt;Not a XENIX named type file&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENAVAIL&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;119&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x77&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff89&lt;/td&gt;
      &lt;td&gt;No XENIX semaphores available&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EISNAM&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;120&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x78&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff88&lt;/td&gt;
      &lt;td&gt;Is a named type file&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EREMOTEIO&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;121&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x79&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff87&lt;/td&gt;
      &lt;td&gt;Remote I/O error&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EDQUOT&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;122&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x7a&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff86&lt;/td&gt;
      &lt;td&gt;Quota exceeded&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOMEDIUM&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;123&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x7b&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff85&lt;/td&gt;
      &lt;td&gt;No medium found&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EMEDIUMTYPE&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;124&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x7c&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff84&lt;/td&gt;
      &lt;td&gt;Wrong medium type&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ECANCELED&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;125&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x7d&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff83&lt;/td&gt;
      &lt;td&gt;Operation Canceled&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOKEY&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;126&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x7e&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff82&lt;/td&gt;
      &lt;td&gt;Required key not available&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EKEYEXPIRED&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;127&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x7f&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff81&lt;/td&gt;
      &lt;td&gt;Key has expired&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EKEYREVOKED&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;128&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x80&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff80&lt;/td&gt;
      &lt;td&gt;Key has been revoked&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EKEYREJECTED&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;129&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x81&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff7f&lt;/td&gt;
      &lt;td&gt;Key was rejected by service&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EOWNERDEAD&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;130&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x82&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff7e&lt;/td&gt;
      &lt;td&gt;Owner died&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOTRECOVERABLE&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;131&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x83&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff7d&lt;/td&gt;
      &lt;td&gt;State not recoverable&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ERFKILL&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;132&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x84&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff7c&lt;/td&gt;
      &lt;td&gt;Operation not possible due to RF-kill&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EHWPOISON&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;133&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x85&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff7b&lt;/td&gt;
      &lt;td&gt;Memory page has hardware error&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ERESTARTSYS&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;512&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x200&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff200&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ERESTARTNOINTR&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;513&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x201&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff1ff&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ERESTARTNOHAND&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;514&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x202&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff1fe&lt;/td&gt;
      &lt;td&gt;restart if no handler..&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOIOCTLCMD&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;515&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x203&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff1fd&lt;/td&gt;
      &lt;td&gt;No ioctl command&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ERESTART_RESTARTBLOCK&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;516&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x204&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff1fc&lt;/td&gt;
      &lt;td&gt;restart by calling sys_restart_syscall&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EBADHANDLE&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;521&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x209&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff1f7&lt;/td&gt;
      &lt;td&gt;Illegal NFS file handle&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOTSYNC&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;522&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x20a&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff1f6&lt;/td&gt;
      &lt;td&gt;Update synchronization mismatch&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EBADCOOKIE&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;523&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x20b&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff1f5&lt;/td&gt;
      &lt;td&gt;Cookie is stale&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ENOTSUPP&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;524&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x20c&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff1f4&lt;/td&gt;
      &lt;td&gt;Operation is not supported&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ETOOSMALL&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;525&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x20d&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff1f3&lt;/td&gt;
      &lt;td&gt;Buffer or request is too small&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ESERVERFAULT&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;526&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x20e&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff1f2&lt;/td&gt;
      &lt;td&gt;An untranslatable error occurred&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EBADTYPE&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;527&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x20f&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff1f1&lt;/td&gt;
      &lt;td&gt;Type not supported by server&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EJUKEBOX&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;528&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x210&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff1f0&lt;/td&gt;
      &lt;td&gt;Request initiated, but will not complete before timeout&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EIOCBQUEUED&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;529&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x211&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff1ef&lt;/td&gt;
      &lt;td&gt;iocb queued, will get completion event&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;EIOCBRETRY&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;530&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x212&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0x..ff1ee&lt;/td&gt;
      &lt;td&gt;iocb queued, will trigger a retry&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
</description>
				<pubDate>Thu, 23 Nov 2017 00:00:00 +0100</pubDate>
				<link>https://kdave.github.io/errno.h/</link>
				<guid isPermaLink="true">https://kdave.github.io/errno.h/</guid>
			</item>
		
			<item>
				<title>gitstats: btrfs-progs for v4.14</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;&lt;a href=&quot;gitstats-index.html&quot;&gt;gitstats&lt;/a&gt;&lt;/p&gt;
</description>
				<pubDate>Wed, 06 Dec 2017 00:00:00 +0100</pubDate>
				<link>https://kdave.github.io/gitstats-btrfs-progs-v4.14/</link>
				<guid isPermaLink="true">https://kdave.github.io/gitstats-btrfs-progs-v4.14/</guid>
			</item>
		
			<item>
				<title>qemu 2.12 does not support if=scsi</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;After update of qemu to version 2.12, my testing vms stopped to just warn
about the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if=scsi&lt;/code&gt; (with a bit more cryptic message), and did not want to
start.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;qemu-system-x86_64: &lt;span class=&quot;nt&quot;&gt;-drive&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;root,if&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;scsi,media&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;disk,cache&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;none,index&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0,format&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;raw: machine &lt;span class=&quot;nb&quot;&gt;type &lt;/span&gt;does not support &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;scsi,bus&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0,unit&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if=scsi&lt;/code&gt; shortcut was handy, the maze of qemu command line options may
take some time to comprehend but then you can do wonders.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://wiki.qemu.org/ChangeLog/2.12#Deprecated_options_and_features&quot;&gt;release notes of version 2.12&lt;/a&gt; do
mention that the support is gone and that other options should be used instead,
also mentions which ones. But it does not tell how exactly. As this should be a
simple syntax transformation from one option to another, an example would save
a lot of time.&lt;/p&gt;

&lt;p&gt;I was not able to find any ready-to-use example in a few minutes so had to
experiment a bit (this saved me documentation reading time).&lt;/p&gt;

&lt;p&gt;The setup I use is a file-backed root image for a virtual machine, nothing
really fancy. The file name is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt;, sparse file, raw ie. no qcow2, no
caching.&lt;/p&gt;

&lt;p&gt;Here you are:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;-device virtio-scsi-pci,id=scsi
-drive file=root,id=root-img,if=none,format=raw,cache=none
-device scsi-hd,drive=root-img
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;First you need to define the bus, otherwise the 3rd line will complain that
there’s no SCSI. Second line is to define the file backed drive and the third
one puts that together.&lt;/p&gt;

&lt;p&gt;Using SCSI might not be the best idea for a qemu VM as the emulated driver is
buggy and crashes, so I’d recommend to use virtio, but for a almost read-only
root image it’s fine. Also the device names are predictable.&lt;/p&gt;
</description>
				<pubDate>Fri, 08 Jun 2018 00:00:00 +0200</pubDate>
				<link>https://kdave.github.io/qemu-2.11-if=scsi/</link>
				<guid isPermaLink="true">https://kdave.github.io/qemu-2.11-if=scsi/</guid>
			</item>
		
			<item>
				<title>Some btrfs benchmarks of changes pending for 4.20</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;Update: enhance the text, still a bit raw, check the numbers&lt;/p&gt;

&lt;p&gt;Example of benchmarks of patches going to 4.20 kernel. The goal was to identify
potential differences between the devleopment branch with and without merge
to the mainline. The factors affecting the difference are usually in other
subsystems like block layer (IO queuing) or memory management (namely page
cache, memory allocator, writeback), core (scheduling, locking primitives).&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;base/misc1: v4.19-rc8&lt;/li&gt;
  &lt;li&gt;misc2: v4.19-rc8 + btrfs pull request&lt;/li&gt;
  &lt;li&gt;misc3: v4.19 with btrfs changes merged&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The numbers are reflected in the results below, referring to comparisons of
the branches. 1-to-2 is the net effect of the patches, 1-to-3 is the same
patches after merge.&lt;/p&gt;

&lt;p&gt;The testsuite used is &lt;a href=&quot;https://github.com/mgorman/mmtests&quot;&gt;MMTests&lt;/a&gt;, that’s
internally used for performance evaluation and provides wide range of workloads&lt;/p&gt;

&lt;p&gt;The expected performance delta should be roughly the same for 2 and 3, the
tables show if the delta is significant (green: positive, red: negative), so it
can be easily observed. Note that the values need to be properly interpreted in
the context of the benchmark and perhaps other values.&lt;/p&gt;

&lt;h2 id=&quot;mmtests-results&quot;&gt;MMTests results&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;blogbench/results-12&quot;&gt;blogbench 1, 2&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;blogbench/results&quot;&gt;blogbench 1, 2, 3&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;dbench4-async/results-12&quot;&gt;dbench4-async 1, 2&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;dbench4-async/results&quot;&gt;dbench4-async 1, 2, 3&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;good: slight improvement in 128 thread latency&lt;/li&gt;
      &lt;li&gt;good: decreased system cpu time&lt;/li&gt;
      &lt;li&gt;bad: longer overall runtime&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;dbench4-fsync/results-12&quot;&gt;dbench4-fsync 1, 2&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;dbench4-fsync/results&quot;&gt;dbench4-fsync 1, 2, 3&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;good: slight improvement in 128 thread latency&lt;/li&gt;
      &lt;li&gt;good: decreased system cpu time&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;filebench-webproxy/results-12&quot;&gt;filebench-webproxy 1, 2&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;filebench-webproxy/results&quot;&gt;filebench-webproxy 1, 2, 3&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;fio-async-randrw/results-12&quot;&gt;fio-async-randrw 1, 2&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;fio-async-randrw/results&quot;&gt;fio-async-randrw 1, 2, 3&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;fio-async-seqw/results-12&quot;&gt;fio-async-seqw 1, 2&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;fio-async-seqw/results&quot;&gt;fio-async-seqw 1, 2, 3&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;fsmark-metadata/results-12&quot;&gt;fsmark-metadata 1, 2&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;fsmark-metadata/results&quot;&gt;fsmark-metadata 1, 2, 3&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;good: overall improvements in transaction counts for 3&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The raw stats are available.&lt;/p&gt;

&lt;h2 id=&quot;test-setup&quot;&gt;Test setup&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;HP ProLiant DL380 G6&lt;/li&gt;
  &lt;li&gt;16 CPUs (Intel(R) Xeon(R), E5520 2.27GHz)&lt;/li&gt;
  &lt;li&gt;16 GiB RAM&lt;/li&gt;
  &lt;li&gt;4x SAS 136 GiB disks, partitioned&lt;/li&gt;
  &lt;li&gt;filesystem:
    &lt;ul&gt;
      &lt;li&gt;btrfs&lt;/li&gt;
      &lt;li&gt;mkfs: data: raid0, metadata: raid1&lt;/li&gt;
      &lt;li&gt;mount: noatime&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
				<pubDate>Thu, 18 Oct 2018 00:00:00 +0200</pubDate>
				<link>https://kdave.github.io/bench-4.20/</link>
				<guid isPermaLink="true">https://kdave.github.io/bench-4.20/</guid>
			</item>
		
			<item>
				<title>Linux crypto: testing blake2s</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;The BLAKE2 algorithm is out for some time, yet there’s no port to linux crypto
API. The recent push of WireGuard would add it to linux kernel, but using a
different API (zinc) than the existing one. I haven’t explored zinc, I assume
there will be a way to use it from inside kernel, but this would need another
layer to switch the APIs according to the algorithm.&lt;/p&gt;

&lt;p&gt;As btrfs is going to use more hashing algos, we are in the process of
selection.  One of the contenders is BLAKE2, though everybody would have a
different suggestion.  In order to test it, a port is needed. Which basically is
a glue code between the linux crypto API and the BLAKE2 implementation.&lt;/p&gt;

&lt;p&gt;I’m not going to reimplement crypto or anything, so the the default
implementation is going to be the reference one found in blake2 git.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: due to the maximum space of 32 bytes available in the btrfs metadata
blocks, the version is BLAKE2s.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-blake2s-sources&quot;&gt;The BLAKE2s sources&lt;/h2&gt;

&lt;p&gt;From the repository &lt;a href=&quot;https://github.com/BLAKE2/BLAKE2&quot;&gt;https://github.com/BLAKE2/BLAKE2&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;ref/blake2s-ref.c&lt;/li&gt;
  &lt;li&gt;ref/blake2.h&lt;/li&gt;
  &lt;li&gt;ref/blake2-impl.h&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Briefly skimming over the sources, there’s nothing that’ll cause trouble.
Standard C code, some definitions. Adapting for linux kernel would need to
replace the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stdint.h&lt;/code&gt; types (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uint8_t&lt;/code&gt; etc) with the uXX (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;u8&lt;/code&gt; etc) and change
path to includes. For simplicity, let’s remove the ifdefs for C++ and MSVC too.&lt;/p&gt;

&lt;h2 id=&quot;add-the-new-algorithm-definition-cra&quot;&gt;Add the new algorithm definition (CRA)&lt;/h2&gt;

&lt;p&gt;Though it’s possible to prepare a module for an out-of-tree build (see below),
let’s do it inside the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;linux.git/crypto/&lt;/code&gt; path for now. There’s also plenty of
sources to copy &amp;amp; paste. I’ve used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;crc32c_generic.c&lt;/code&gt;, and it turned out to be
useful.&lt;/p&gt;

&lt;p&gt;The crypto hash description is defined in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct shash_alg&lt;/code&gt;, contains the
technical description like type of the algorithm, length of the context and
callbacks for various phases of the hash calculation (init, update, final), and
identification of the algorithm and the implementation. The default
implementations are C and use the string “-generic” in the name.&lt;/p&gt;

&lt;p&gt;The crc32c module came with a few stub callbacks (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checksum_init&lt;/code&gt; etc), that
will only call into the blake2 functions and the definition can stay. Simple
search and replace from crc32c to blake2s will do most of the conversion.&lt;/p&gt;

&lt;h2 id=&quot;add-the-glue-code-for-crypto-api&quot;&gt;Add the glue code for crypto API&lt;/h2&gt;

&lt;p&gt;Now we have the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;blake2s.c&lt;/code&gt; with the reference implementation, crypto algorithm
definition. The glue code connects the API with the implementation. We need 2
helper structures that hold the context once the user starts digest calculation.
The private blake2s context is embedded into one of them.  The intermediate
results will be stored there.&lt;/p&gt;

&lt;p&gt;And the rest is quite easy, each callback will call into the respective blake2s
function, passing the context, data and lengths. One thing that I copied from
the examples is the key initialization that’s in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;blake2s_cra_init&lt;/code&gt;, that
appears to be global and copied to the context each time a new one is
initialized.&lt;/p&gt;

&lt;p&gt;Here the choice of using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;crc32c.c&lt;/code&gt; helped as there were the stub callback with
the right parameters, calling the blake2s functions that can retain their
original signature. This makes later updates easier.  All the functions are
static so the compiler will most probably optimize the code that there will be
no unnecessary overhead.&lt;/p&gt;

&lt;p&gt;Well and that’s it. Let’s try to compile it and insert the module:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;linux.git$ make crypto/blake2s.o
...
  CC [M]  crypto/blake2s.o
linux.git$ make crypto/blake2s.ko
...
  CC      crypto/blake2s.mod.o
  LD [M]  crypto/blake2s.ko
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Check that it’s been properly loaded&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;linux.git/crypto$ sudo insmod ./blake2s.ko
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and registered&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;linux.git$ cat /proc/crypto
name         : blake2s
driver       : blake2s-generic
module       : blake2s
priority     : 100
refcnt       : 1
selftest     : passed
internal     : no
type         : shash
blocksize    : 1
digestsize   : 32
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The selftest says it passed, but there no such thing so far. There are test
values provided in blake2 git so it would be nice to have too (tm). But
otherwise it looks good.&lt;/p&gt;

&lt;p&gt;To do actual test, we’d need something inside kernel to utilize the new hash.
One option is to implement a module that will do that or use the userspace
library &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libkcapi&lt;/code&gt; that can forward the requests from userspace to the
available kernel implementations.&lt;/p&gt;

&lt;h2 id=&quot;test-it-with-libkcapi&quot;&gt;Test it with libkcapi&lt;/h2&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libkcapi&lt;/code&gt; project at
&lt;a href=&quot;http://www.chronox.de/libkcapi.html&quot;&gt;http://www.chronox.de/libkcapi.html&lt;/a&gt;
provides an API that uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AF_ALG&lt;/code&gt; socket type to exchange data with
kernel. The library provides a command line tool that we can use right away and
don’t need to code anything.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ kcapi-dgst -c blake2s --hex &amp;lt; /dev/null
48a8997da407876b3d79c0d92325ad3b89cbb754d86ab71aee047ad345fd2c49
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The test vectors provided by blake2 confirm that this is hash of empty string
with the default key (0x000102..1f).&lt;/p&gt;

&lt;h2 id=&quot;out-of-tree-build&quot;&gt;Out-of-tree build&lt;/h2&gt;

&lt;p&gt;Sources in the linux.git require one additional line to Makefile, build it
unconditionally as a module. Proper submission to linux kernel would need the
Kconfig option.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;obj-m += blake2s.o
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The standalone build needs a Makefile with a few targets that use the existing
build of kernel. Note that you’d need a running kernel with the same built
sources. This is usually provided by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kernel-*-devel&lt;/code&gt; packages. Otherwise,
if you build kernels from git, you know what to do, right?&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;KDIR ?= /lib/modules/`uname -r`/build
obj-m := blake2s.o

default:
        $(MAKE) -C $(KDIR) M=$$PWD

clean:
        $(MAKE) -C $(KDIR) M=$$PWD clean

modules_install:
        $(MAKE) -C $(KDIR) M=$$PWD modules_install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt;, the kernel module is ready for use.&lt;/p&gt;

&lt;h2 id=&quot;what-next&quot;&gt;What next?&lt;/h2&gt;

&lt;p&gt;Send it upstream. Well, after some work of course.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;update the coding style of the blake2 sources&lt;/li&gt;
  &lt;li&gt;add Kconfig&lt;/li&gt;
  &lt;li&gt;write self-tests&lt;/li&gt;
  &lt;li&gt;optionally add the optimized implementations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All the files can be found here:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;Makefile&quot;&gt;Makefile&lt;/a&gt;: out-of-tree build&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;blake2.h&quot;&gt;blake2.h&lt;/a&gt;: copied and updated for linux&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;blake2.h&quot;&gt;blake2-impl.h&lt;/a&gt;: copied and updated for linux&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;blake2.h&quot;&gt;blake2s.c&lt;/a&gt;: copied and updated for linux&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://blake2.net&quot;&gt;https://blake2.net&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/BLAKE2/BLAKE2&quot;&gt;https://github.com/BLAKE2/BLAKE2&lt;/a&gt;:&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.chronox.de/libkcapi.html&quot;&gt;http://www.chronox.de/libkcapi.html&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.kernel.org/doc/html/latest/crypto/userspace-if.html&quot;&gt;https://www.kernel.org/doc/html/latest/crypto/userspace-if.html&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.kernel.org/doc/html/latest/crypto/intro.html&quot;&gt;https://www.kernel.org/doc/html/latest/crypto/intro.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
				<pubDate>Sat, 27 Apr 2019 00:00:00 +0200</pubDate>
				<link>https://kdave.github.io/linux-crypto-blake2s/</link>
				<guid isPermaLink="true">https://kdave.github.io/linux-crypto-blake2s/</guid>
			</item>
		
			<item>
				<title>Here, have a pyramid made of BLAKE2 hashes</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;Fun stuff only …&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Hash some bytes with changing digest length from 1 to 64.&lt;/em&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[ 1]                                                                 3b
[ 2]                                                                cf5b
[ 3]                                                               68a2fa
[ 4]                                                              ac6de759
[ 5]                                                             022847e13c
[ 6]                                                            fd2965be0997
[ 7]                                                           d4c93ad6ffbcbb
[ 8]                                                          87c1dcb224fd2a57
[ 9]                                                         6017c4f8c4bcb1d115
[10]                                                        9b3f7b15df8867b8214c
[11]                                                       8087b2861bbdf3d0356ea6
[12]                                                      7a035413d62f0774148a12cc
[13]                                                     697cabcfcade7114a271373039
[14]                                                    784e3578c7b5a031237296225e26
[15]                                                   0102e6aa5ff6bf57071b34f838d3d4
[16]                                                  324f54d0e8f39326145e8e04b00434b4
[17]                                                 45fbfb40756a53305881dc52d7aa6a9025
[18]                                                c1a664957cbc0bbd0e2eb15be3a8e0f10b46
[19]                                               58c84031abff74bba0cab2a3ce8160c955fb92
[20]                                              bad65265d1351746c3fc23816dca6966b42d2e90
[21]                                             c9ed77f178c889cc985aaad89d740831922d7d6253
[22]                                            751673d5516709339176859392a61e45b444a3a4612c
[23]                                           e62b1a6a239571d2a7ebf686f3f1f628f7253fa595debf
[24]                                          3afb48409fa94374bd1819bef5d40f8e90386686ec7212db
[25]                                         139fb5a766ab873fc1747e76253ebddec0da85388261ddcd0c
[26]                                        90b849e8d333229c8942f68faac2870530886c30edf4fe295281
[27]                                       cfefa0767fdd316475e4374dc3b9e1eabdebb0111c88ccdaf6b668
[28]                                      6928e0b74efa9534c84483975ab83b65191d59d69c76880eac794afc
[29]                                     5d825aaaaabff533c36308227ed42982837bf7fa85d5f4457f6d7ebdfe
[30]                                    a14f3dafe99f88dbb119f23cd2d390b3396f2c1c90fc8099514abb95872a
[31]                                   6a62d371a4b6583df5cc9f125e01536338a8e87fd17b1e24468778e00205bc
[32]                                  99b4a09edc99a1a2283f94189d8604ca65aab7aeebc31327b8c4a918341f92b0
[33]                                 1b0728d4ae415dc572ebb7caf18f7b43115ca6b53f6379a6571b4949d2049e6b7f
[34]                                04c6817ba561b6e6aefb2237682aa4171314fc2a7bfa15f604227e239e8a08696153
[35]                               102d84c3e030bd1d413f12128c34caef64c06c364eb13c4eb49549ab278efcd5d0dac1
[36]                              fa4edc42c4fcd5754de080616d09412c3f7baba4a972954e449bfa65fc040ae5556bc63c
[37]                             0728fcf98a665b6a8c9a63ae31c87538d68bca8dc2e2a6b66dba3c1f4a8c5965bb4045a1e2
[38]                            3fd0e5397a0d98eaf56a941e5b7ba7b8aa4b8dbe2a22993809cbb9a4b68834de1341c1412e2f
[39]                           16eee95d5dc56762bc42f59aac2fc0bee5ba3a5fa7d6b2c1acc13af519a1a13cc793d2482685b9
[40]                          74843823a200d423fbead5d40d83dea26638ecf79a768f819b44174a2ce0b51702944ff967597b9f
[41]                         53134460150687f2b993259a048a9b59de7d8c091ffc635b792b33ae9c7970ef6dc47fe6308e47da21
[42]                        174cbb459228b1b5fe302d36dfd69d0c75b8d77398e6eb8440e9449db38ce7387d12095f23531eb5a2bd
[43]                       f550a1d564f073486095bf473a20d135fcba595fd574c124e6a8f3f1451a4cd649b3d3c6c22fd3961dff9e
[44]                      9e25048892b6d367d0e85a75d1f49c6950a9ae3ca02b03165b1308f0aadac093032fbb13556cb9bb85872def
[45]                     d43eb7fa68c34906813c360cd5c50e8d5f62c0de941f1e9520d405104144c30c1eb43c95bad4b850b3dc308141
[46]                    b9e4bc8364d69248c68dfe17a66131de04e6be949663c936fdbe5fec3efb73d4e40c22ad298d8be849de58b0a3a8
[47]                   f81017569d44554c934f6d89723e8997e115def6d66c76ee3c05a7e7626f487cab5659b4e3a7f32c9859dd04c579eb
[48]                  f2a987f00b96fafd25f2d8a19717913674961f234d0f81da5dbb549382ce2f25a5a95c4be917b97341d7c8b8a05aa2d1
[49]                 03602f74fadc251d46a064dcc55a812c37c98960a984782c533bce1db92c514521996c58ff293a3957fd686cd814cbc18e
[50]                bf939f9418697008f5a1c67e16e7f01bf596a7be648069c5bb322ba7207b6af5947912a40773f3c8f48bef03cda925c79eb8
[51]               77cb53241baa7dfd4b73b786b29543ad4f9da15c33d21b7acf0d04bd78c437018f7358357879f06e8fa59832028a851c126fbf
[52]              404a9cdd87d1ff194c45c9dd1995889b5492b22d446f87f8efe0148793bee21a756cfe6ac18f438f2535b35e909678e1f4ddfd92
[53]             38b399db58e9a1d4b3d78e3756b55a7d8bc3fce565a6cd68f66632cb3e201720384487bc314fc960cc7ece0915ab06ab655cb21f95
[54]            341c51088313284bb6efb2ce87116fa0ad86c540b4761ad1a91db8a54faf0ac16ae44de62e02d87d88124cdf7820f939657f30d43401
[55]           4d217c7ba91da2c4503357904f2264117a445fde54a7f25cf85c0b9d4528e1a8ca682ea59586d63755c2dac848716d19afa00f9c2a70e5
[56]          05664a51270f7a9dc309a1e78bddd3ed6a210aecf31f42be0a4231280a9e15ca1af3ec0456760fc2a6b76039a7f041a7623470bd912afc7d
[57]         434c8e7d8357e840f8522c582385fcba6650b7e923a821a185ae4e036de7ed6b931b908ef4bc3838de6864decdff762ac123f6f66a14a2fded
[58]        87fc3385049632e310553cda08b22810b0fa59c92f5559b49d2ffd5e5d0734886ccd269e6866d6412bc06489cba014265767edebcd2c18977c42
[59]       282ca365baaa22317a3c7faadc075e6b132fefee0d98d8823a79ffe87f87f7a38d8fd9e4a7ca10a904fbbcd9952dc12af3e561b884a40b7b2b4288
[60]      a0f9ca58069fe970f2fd36d6c86b38b14ad41418f870ee695aa52395400552c4f583760e01c68c440c5fa6f9c6db25138d85cd6568f0f9a5698db89a
[61]     79b0b42401bb022fdfb71fdd2e6ddd2d0dc20cedcdd4b64e7921a03fd2f71508a195e2d8a4ebeb0ea8cdc6942ccd28cca7eda0fa2126fd884a0b279cd4
[62]    42b704ca2da3386bf00fc511648668af1b9f3bbf69d7972d35dc24365d0b37778fffa624662bd50139430644314367ff855da6bb489227144456007d5f1d
[63]   504a6a52e16b29a0ebe9106ac74931889243ef98aee97bd598502aac9363d99c7c414d39cb1229a3b49e79351f2c0daa3e9221bc7a135ffc41f79a6e416762
[64]  0b944b6bdc6c99e10448a536dea6ea79fd1d78e70307bf6e3c4a889f3876e2ec6a002ec9b4198a27e2b2dcdfcef7a4de4da52791248457a50d97307cdb0b6c80
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Sources:
&lt;a href=&quot;blake2-impl.h&quot;&gt;blake2-impl.h&lt;/a&gt;
&lt;a href=&quot;test-blake2.h&quot;&gt;test-blake2.h&lt;/a&gt;
&lt;a href=&quot;test-blake2b.c&quot;&gt;test-blake2b.c&lt;/a&gt;&lt;/p&gt;
</description>
				<pubDate>Wed, 12 Jun 2019 00:00:00 +0200</pubDate>
				<link>https://kdave.github.io/blake2-pyramid/blake2b-pyramid/</link>
				<guid isPermaLink="true">https://kdave.github.io/blake2-pyramid/blake2b-pyramid/</guid>
			</item>
		
			<item>
				<title>Btrfs hilights in 5.2</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;A bit more detailed overview of a btrfs update that I find interesting, see the
&lt;a href=&quot;https://git.kernel.org/linus/9f2e3a53f7ec9ef55e9d01bc29a6285d291c151e&quot;&gt;pull request&lt;/a&gt;
for the rest.&lt;/p&gt;

&lt;h2 id=&quot;read-time-write-time-corruption-detection&quot;&gt;Read-time, write-time corruption detection&lt;/h2&gt;

&lt;p&gt;The tree-checker is a recent addition to the sanity checks, a functionality
that verifies a subset of metadata structures. The capabilities and strength is
limited by the context and bits of information available at some point, but
still there’s enough to get an additional value.&lt;/p&gt;

&lt;p&gt;The context here means a b-tree leaf that packs several items into a block (ie.
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nodesize&lt;/code&gt;, 16KiB by default). The individual items’ members’ values can be
verified against allowed values, the order of the keys of all items listed in
the leaf header can be checked etc. This is just for a rough idea what happens.&lt;/p&gt;

&lt;p&gt;With that in the works, there are two occasions that can utilize the extended
checking:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;read-time – the first time a block is read fresh from disk&lt;/li&gt;
  &lt;li&gt;write-time – when the final contents of a block is in memory and going to be written to disk&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s clear that the read-time is merely a detector of problems that already
happened, so there’s not much to do besides warning and returning an error
(EUCLEAN). Turning the filesystem to read-only to prevent further problems is
another option and inevitable on some occasions.&lt;/p&gt;

&lt;p&gt;The write side check aims to catch silent errors that could make it to the
permanent storage. The reasons why this happens are two fold, but the main idea
is to catch memory bit flips. You’d be surprised how often this happens, that
would be for a separate article entirely.&lt;/p&gt;

&lt;p&gt;The new checks in 5.2 improve:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;device item &lt;em&gt;(item that describes the physical device of the filesystem)&lt;/em&gt; –
check that items have the right key type, device id is within allowed range
and that usage and total sizes are within limits of the physical device&lt;/li&gt;
  &lt;li&gt;inode item &lt;em&gt;(item for inodes, ie. files, directories or special files)&lt;/em&gt;– the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;objectid&lt;/code&gt; (that would be the inode number) is in the range, generation is
consistent with the global one and the basic sanity of mode, flags/attributes
and link count&lt;/li&gt;
  &lt;li&gt;block group profiles – check that only a single type is set in the bit mask
that represents block group profile type of a chunk (ie.
single/dup/raid1/…)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As mentioned before, the bits to check are inside a single buffer that
represents the tree block and the check is really local to that. As an inode
item can represent more than just files and directories, doing structural
checks like where and how the inode item is linked to is not easy in this
context. This is basically what would &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;btrfs check&lt;/code&gt; do.&lt;/p&gt;

&lt;p&gt;The checks need to be fast because they happen on each metadata block, so no
additional IO is allowed. This still brings some overhead but is (considered)
negligible compared to all other updates to the block. A measurement can be
done by adding tracepoint, but that’s left as an exercise.&lt;/p&gt;
</description>
				<pubDate>Thu, 25 Jul 2019 00:00:00 +0200</pubDate>
				<link>https://kdave.github.io/btrfs-hilights-5.2/</link>
				<guid isPermaLink="true">https://kdave.github.io/btrfs-hilights-5.2/</guid>
			</item>
		
			<item>
				<title>Selecting the next checksum for btrfs</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;The currently used and the only one checksum algorithm that’s implemented in
btrfs is crc32c, with 32bit digest. It has served well for the years but has
some weaknesses so we’re looking for a replacements and also for enhancing the
use cases based on possibly better hash algorithms.&lt;/p&gt;

&lt;p&gt;The advantage of crc32c is it’s simplicity of implementation, various optimized
versions exist and hardware CPU instruction-level support. The error detection
strength is not great though, the collisions are easy to generate. Note that
crc32c has not been used in cryptographically sensitive context (eg.
deduplication).&lt;/p&gt;

&lt;p&gt;Side note: the collision generation weakness is used in the filesystem image
dump tool to preserve hashes of directory entries while obscuring the real
names.&lt;/p&gt;

&lt;h2 id=&quot;future-use-cases&quot;&gt;Future use cases&lt;/h2&gt;

&lt;p&gt;The natural use case is still to provide checksumming for data and metadata
blocks. With strong hashes, the same checksums can be used to aid deduplication
or verification (HMAC instead of plain hash). Due to different requirements,
one hash algorithm cannot possibly satisfy all requirements, namely speed vs.
strength. Or can it?&lt;/p&gt;

&lt;h2 id=&quot;the-criteria&quot;&gt;The criteria&lt;/h2&gt;

&lt;p&gt;The frequency of checksumming is high, every data block needs that, every
metadata block needs that.&lt;/p&gt;

&lt;p&gt;During the discussions in the community, there were several candidate hash
algorithms proposed and as it goes users want different things but we
developers want to keep the number of features sane or at least maintainable. I
think and hope the solution will address that.&lt;/p&gt;

&lt;p&gt;The first hash type is to replace crc32c with focus on &lt;strong&gt;speed&lt;/strong&gt; and not
necessarily strength (ie. collision resistance).&lt;/p&gt;

&lt;p&gt;The second type focus is &lt;strong&gt;strength&lt;/strong&gt;, in the cryptographic sense.&lt;/p&gt;

&lt;p&gt;In addition to the technical aspects of the hashes, there are some requirements
that would allow free distribution and use of the implementations:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;implementation available under a GPL2 compatible license&lt;/li&gt;
  &lt;li&gt;available in the linux kernel, either as a library function or as a module&lt;/li&gt;
  &lt;li&gt;license that allows use in external tools like bootloaders (namely grub2)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Constraints posed by btrfs implementation:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;maximum digest width is 32 bytes&lt;/li&gt;
  &lt;li&gt;blocks of size from 4KiB up to 64KiB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the enhanced use case of data verification (using HMAC), there’s a
requirement that might not interest everybody but still covers a lot of
deployments. And this is standard compliance and certification:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;standardized by FIPS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And maybe last but not least, use something that is in wide use already, proven by time.&lt;/p&gt;

&lt;h3 id=&quot;speed&quot;&gt;Speed&lt;/h3&gt;

&lt;p&gt;Implementation of all algorithms should be performant on common hardware, ie.
64bit architectures and hopefully not terrible on 32bit architectures or older
and weaker hardware.  By hardware I mean the CPU, not specialized hardware
cards.&lt;/p&gt;

&lt;p&gt;The crypto API provided by linux kernel can automatically select the best
implementation of a given algorithm, eg. optimized implementation in assembly
and on multiple architectures.&lt;/p&gt;

&lt;h3 id=&quot;strength&quot;&gt;Strength&lt;/h3&gt;

&lt;p&gt;For the fast hash the collisions could be generated but hopefully not that
easily as for crc32c. For strong hash it’s obvious that finding a collision
would be jackpot.&lt;/p&gt;

&lt;p&gt;In case of the fast hash the quality can be evaluated using the SMHasher suite.&lt;/p&gt;

&lt;h2 id=&quot;the-contenders&quot;&gt;The contenders&lt;/h2&gt;

&lt;p&gt;The following list of hashes has been mentioned and considered or evaluated:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;xxhash&lt;/li&gt;
  &lt;li&gt;XXH3&lt;/li&gt;
  &lt;li&gt;SipHash&lt;/li&gt;
  &lt;li&gt;CRC64&lt;/li&gt;
  &lt;li&gt;SHA256&lt;/li&gt;
  &lt;li&gt;SHA3&lt;/li&gt;
  &lt;li&gt;BLAKE2&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;xxhash&quot;&gt;xxhash&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;criteria&lt;/em&gt;: license OK, implementation OK, digest size OK, not standardized but
in wide use&lt;/p&gt;

&lt;p&gt;The hash is quite fast as it tries to exploit the CPU features that allow
instruction parallelism. The SMHasher score is 10, that’s great. The linux kernel
implementation landed in 5.3.&lt;/p&gt;

&lt;p&gt;Candidate for &lt;em&gt;fast hash&lt;/em&gt;.&lt;/p&gt;

&lt;h3 id=&quot;xxh3&quot;&gt;XXH3&lt;/h3&gt;

&lt;p&gt;Unfortunately the hash is not yet finalized and cannot be in the final round,
but for evaluation of speed it was considered. The hash comes from the same
author as xxhash.&lt;/p&gt;

&lt;h3 id=&quot;siphash&quot;&gt;SipHash&lt;/h3&gt;

&lt;p&gt;This hash is made for hash tables and hashing short strings but we want 4KiB or
larger blocks. Not a candidate.&lt;/p&gt;

&lt;h3 id=&quot;crc64&quot;&gt;CRC64&lt;/h3&gt;

&lt;p&gt;Similar to crc32 and among the contenders only because it was easy to evaluate
but otherwise is not in the final round. It has shown to be slow in the
microbenchmark.&lt;/p&gt;

&lt;h3 id=&quot;sha256&quot;&gt;SHA256&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;criteria&lt;/em&gt;: license OK, implementation OK, digest size OK, standardized in FIPS&lt;/p&gt;

&lt;p&gt;The SHA family of hashes is well known, has decent support in CPU and is
standardized. Specifically, SHA256 is the strongest that still fits into the
available 32 bytes.&lt;/p&gt;

&lt;p&gt;Candidate for &lt;em&gt;strong hash&lt;/em&gt;.&lt;/p&gt;

&lt;h3 id=&quot;sha3&quot;&gt;SHA3&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;criteria&lt;/em&gt;: license OK, implementation OK, digest size OK, standardized in FIPS&lt;/p&gt;

&lt;p&gt;Winner of the 2012 hash contest, we can’t leave it out. From the practical
perspective of checksum, the speed is bad even for the strong hash type. One of
the criteria stated above is performance without special hardware, unlike what
was preferred during the SHA3 contest.&lt;/p&gt;

&lt;p&gt;Candidate for &lt;em&gt;strong hash&lt;/em&gt;.&lt;/p&gt;

&lt;h3 id=&quot;blake2&quot;&gt;BLAKE2&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;criteria&lt;/em&gt;: license OK, implementation OK, digest size OK, not standardized&lt;/p&gt;

&lt;p&gt;From the family of BLAKE that participated in the 2012 SHA contest, the ‘2’
provides a trade-off speed vs. strength. More and more projects adopt it.&lt;/p&gt;

&lt;p&gt;Candidate for &lt;em&gt;strong hash&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id=&quot;final-round&quot;&gt;Final round&lt;/h2&gt;

&lt;p&gt;I don’t blame you if you skipped all the previous paragraphs. The (re)search
for the next hash was quite informative and fun so it would be shame not to
share it, also to document the selection process for some transparency. This is
a committee driven process though.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;fast hash: &lt;strong&gt;xxhash&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;strong hash: &lt;strong&gt;BLAKE2&lt;/strong&gt; and &lt;strong&gt;SHA256&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two hashes selected for the strong type is a compromise to get a
fast-but-strong hash yet also something that’s standardized.&lt;/p&gt;

&lt;p&gt;The specific version of BLAKE2 is going to be the ‘BLAKE2b-256’ variant, ie.
optimized for 64bit (2b) but with 256bit digest.&lt;/p&gt;

&lt;h3 id=&quot;microbenchmark&quot;&gt;Microbenchmark&lt;/h3&gt;

&lt;p&gt;A microbenchmark gives more details about performance of the hashes:&lt;/p&gt;

&lt;p&gt;Block: 4KiB (4096 bytes), 
Iterations: 100000&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;Hash&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;Total cycles&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;Cycles/iteration&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;NULL-NOP&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;56888626&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;568&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;NULL-MEMCPY&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;60644484&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;606&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;CRC64&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;3240483902&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;32404&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;CRC32C&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;174338871&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;1743&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;CRC32C-SW&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;174388920&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;1743&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;XXHASH&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;251802871&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;2518&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;XXH3&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;193287384&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;1932&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;BLAKE2b-256-arch&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;1798517566&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;17985&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;BLAKE2b-256&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;2358400785&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;23584&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;BLAKE2s-arch&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;2593112451&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;25931&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;BLAKE2s&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;3451879891&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;34518&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;SHA256&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;10674261873&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;106742&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;SHA3-256&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;29152193318&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;291521&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Machine: Intel(R) Xeon(R) CPU E5-1620 v3 @ 3.50GHz (AVX2)&lt;/p&gt;

&lt;p&gt;Hash implementations are the reference ones in C:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;NULL-NOP – stub to measure overhead of the framework&lt;/li&gt;
  &lt;li&gt;NULL-MEMCPY – simple memcpy of the input buffer&lt;/li&gt;
  &lt;li&gt;CRC64 – linux kernel lib/crc64.c&lt;/li&gt;
  &lt;li&gt;CRC32C – hw assisted crc32c, (linux)&lt;/li&gt;
  &lt;li&gt;CRC32C-SW – software implementation, table-based (linux)&lt;/li&gt;
  &lt;li&gt;XXHASH – reference implementation&lt;/li&gt;
  &lt;li&gt;XXH3 – reference implementation&lt;/li&gt;
  &lt;li&gt;BLAKE2b-256-arch – 64bit optimized reference version (for SSE2/SSSE3/SSE41/AVX/AVX2)&lt;/li&gt;
  &lt;li&gt;BLAKE2b-256 – 64bit reference implementation&lt;/li&gt;
  &lt;li&gt;BLAKE2s-arch – 32bit optimized reference version&lt;/li&gt;
  &lt;li&gt;BLAKE2s – 32bit reference implementation&lt;/li&gt;
  &lt;li&gt;SHA256 – RFC 6234 reference implementation&lt;/li&gt;
  &lt;li&gt;SHA3-256 – C, based on canonical implementation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There aren’t optimized versions for all hashes so for fair comparison the
unoptimized reference implementation should be used. As BLAKE2 is my personal
favourite I added the other variants and optimized versions to observe the
relative improvements.&lt;/p&gt;

&lt;h3 id=&quot;evaluation&quot;&gt;Evaluation&lt;/h3&gt;

&lt;p&gt;CRC64 was added by mere curiosity how does it compare to the rest. Well,
curiosity satisfied.&lt;/p&gt;

&lt;p&gt;SHA3 is indeed slow on a CPU.&lt;/p&gt;

&lt;h3 id=&quot;what-isnt-here&quot;&gt;What isn’t here&lt;/h3&gt;

&lt;p&gt;There are non-cryptographic hashes like CityHash, FarmHash, Murmur3 and more,
that were found unsuitable or not meeting some of the basic criteria.  Others
like FNV or Fletcher used in ZFS are of comparable strength of crc32c, so that
won’t be a progress.&lt;/p&gt;

&lt;h2 id=&quot;merging&quot;&gt;Merging&lt;/h2&gt;

&lt;p&gt;All the preparatory work in btrfs landed in version 5.3. Hardcoded assumptions
of crc32c were abstracted, linux crypto API wired in, with additional cleanups
or refactoring. With that in place, adding a new has is a matter of a few lines
of code adding the specifier string for crypto API.&lt;/p&gt;

&lt;p&gt;The work on btrfs-progs is following the same path.&lt;/p&gt;

&lt;p&gt;Right now, the version 5.4 is in development but new features can’t be added,
so the target for the new hashes is &lt;strong&gt;5.5&lt;/strong&gt;. The BLAKE2 algorithm family still
needs to be submitted and merged, hopefully they’ll make it to 5.5 as well.&lt;/p&gt;

&lt;p&gt;One of my merge process requirements was to do a call for public testing, so
we’re going to do that once all the kernel and progs code is ready for testing.
Stay tuned.&lt;/p&gt;
</description>
				<pubDate>Tue, 08 Oct 2019 00:00:00 +0200</pubDate>
				<link>https://kdave.github.io/selecting-hash-for-btrfs/</link>
				<guid isPermaLink="true">https://kdave.github.io/selecting-hash-for-btrfs/</guid>
			</item>
		
			<item>
				<title>Simple asm diff filter</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;One thing you windows guys have is a decent binary diff. I know there’s radare2
on linux, but I’m a noob to set it up and I’d be fine with something less
fancy. Something like 2 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;objdump -dr&lt;/code&gt; files, intelligent filter and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vimdiff&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The tricky part is the intelligent filter. I say &lt;em&gt;intelligent&lt;/em&gt;, but in fact it’s
a 20 line perl script that basically filters out things that are not important
or are likely to change in a slightly modified C source.&lt;/p&gt;

&lt;p&gt;The result is lossy, eg. there are no addresses and thus jumps can’t be
followed, but having that would actually deserve the ‘intelligent’ title.
My use case is simpler, eg. doing small tweaks like reordering lines, adding
annotations (like READ_ONCE/WRITE_ONCE) or reducing argument counts.&lt;/p&gt;

&lt;p&gt;Which takes eg.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;0000000000000000 &amp;lt;btrfs_set_lock_blocking_read&amp;gt;:
       0:       e8 00 00 00 00          callq  5 &amp;lt;btrfs_set_lock_blocking_read+0x5&amp;gt;
                        1: R_X86_64_PLT32       __fentry__-0x4
       5:       55                      push   %rbp
       6:       53                      push   %rbx
       7:       48 89 fb                mov    %rdi,%rbx
       a:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)
       f:       65 8b 05 00 00 00 00    mov    %gs:0x0(%rip),%eax        # 16 &amp;lt;btrfs_set_lock_blocking_read+0x16&amp;gt;
                        12: R_X86_64_PC32       cpu_number-0x4
      16:       89 c0                   mov    %eax,%eax
      18:       48 0f a3 05 00 00 00    bt     %rax,0x0(%rip)        # 20 &amp;lt;btrfs_set_lock_blocking_read+0x20&amp;gt;
      1f:       00
                        1c: R_X86_64_PC32       __cpu_online_mask-0x4
      20:       0f 82 b5 00 00 00       jb     db &amp;lt;btrfs_set_lock_blocking_read+0xdb&amp;gt;
      26:       0f b6 ab 94 00 00 00    movzbl 0x94(%rbx),%ebp
      2d:       40 80 fd 01             cmp    $0x1,%bpl
      31:       0f 87 00 00 00 00       ja     37 &amp;lt;btrfs_set_lock_blocking_read+0x37&amp;gt;
                        33: R_X86_64_PC32       .text.unlikely+0x11
      37:       83 e5 01                and    $0x1,%ebp
      3a:       74 1b                   je     57 &amp;lt;btrfs_set_lock_blocking_read+0x57&amp;gt;
      3c:       8b 8b 88 00 00 00       mov    0x88(%rbx),%ecx
      42:       65 48 8b 04 25 00 00    mov    %gs:0x0,%rax
      49:       00 00
                        47: R_X86_64_32S        current_task
      4b:       39 88 c0 04 00 00       cmp    %ecx,0x4c0(%rax)
      51:       0f 84 bd 00 00 00       je     114 &amp;lt;btrfs_set_lock_blocking_read+0x114&amp;gt;
      57:       8b 83 18 02 00 00       mov    0x218(%rbx),%eax
      5d:       85 c0                   test   %eax,%eax
      5f:       0f 84 b2 00 00 00       je     117 &amp;lt;btrfs_set_lock_blocking_read+0x117&amp;gt;
      65:       f0 ff 83 90 00 00 00    lock incl 0x90(%rbx)
      6c:       8b 83 14 02 00 00       mov    0x214(%rbx),%eax
      72:       85 c0                   test   %eax,%eax
      74:       0f 84 ab 00 00 00       je     125 &amp;lt;btrfs_set_lock_blocking_read+0x125&amp;gt;
      7a:       f0 ff 8b 14 02 00 00    lock decl 0x214(%rbx)
      81:       48 8d bb 98 00 00 00    lea    0x98(%rbx),%rdi
      88:       5b                      pop    %rbx
      89:       5d                      pop    %rbp
      ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and produces&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;0000000000000000 &amp;lt;btrfs_set_lock_blocking_read&amp;gt;:
callq  btrfs_set_lock_blocking_read
TARGET __fentry__
push   %rbp
push   %rbx
mov    %rdi,%rbx
NOP
mov    %gs:0x0(%rip),%eax
mov    %eax,%eax
bt     %rax,0x0(%rip)
jb     btrfs_set_lock_blocking_read
movzbl 0x94(%rbx),%ebp
cmp    $0x1,%bpl
ja     btrfs_set_lock_blocking_read
and    $0x1,%ebp
je     btrfs_set_lock_blocking_read
mov    0x88(%rbx),%ecx
mov    %gs:0x0,%rax
cmp    %ecx,0x4c0(%rax)
je     btrfs_set_lock_blocking_read
mov    0x218(%rbx),%eax
test   %eax,%eax
je     btrfs_set_lock_blocking_read
lock incl 0x90(%rbx)
mov    0x214(%rbx),%eax
test   %eax,%eax
je     btrfs_set_lock_blocking_read
lock decl 0x214(%rbx)
lea    0x98(%rbx),%rdi
pop    %rbx
pop    %rbp
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This looks quite simple and when lined together, the diff is readable.&lt;/p&gt;

&lt;p&gt;So here’s the magic script (pardon my perl skills):&lt;/p&gt;

&lt;div class=&quot;language-perl highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#!/usr/bin/perl&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;@c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;@c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;chomp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;sr&quot;&gt;s/.*R_X86_64_PLT32\s+([^+-]+)[+-].*/TARGET $1/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/R_X86_/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/^\s*[0-9a-f]+:\s*([0-9a-f][0-9a-f]\s)+$/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;sr&quot;&gt;s/^\s*[0-9a-f]+:\s*([0-9a-f][0-9a-f]\s)+\s*//&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;sr&quot;&gt;s/[0-9a-f]+ &amp;lt;([^+]+)\+.*&amp;gt;$/$1/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;sr&quot;&gt;s/\s+#.*$//&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;sr&quot;&gt;s/nopl.*/NOP/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;sr&quot;&gt;s/xchg.*ax.*ax/NOP/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;sr&quot;&gt;s/data16 nop/NOP/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;sr&quot;&gt;s/nop/NOP/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$_&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&quot;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Use like:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;objdump &lt;span class=&quot;nt&quot;&gt;-dr&lt;/span&gt; before/locking.o &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; before
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;objdump &lt;span class=&quot;nt&quot;&gt;-dr&lt;/span&gt; after/locking.o &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; after
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vimdiff before after
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
				<pubDate>Sat, 12 Oct 2019 00:00:00 +0200</pubDate>
				<link>https://kdave.github.io/simple-asm-diff-filter/</link>
				<guid isPermaLink="true">https://kdave.github.io/simple-asm-diff-filter/</guid>
			</item>
		
			<item>
				<title>Btrfs hilights in 5.3</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;A bit more detailed overview of a btrfs update that I find interesting, see the
&lt;a href=&quot;https://git.kernel.org/linus/a18f8775419d3df282dd83efdb51c5a64d092f31&quot;&gt;pull request&lt;/a&gt;
for the rest.&lt;/p&gt;

&lt;h2 id=&quot;crc32c-uses-accelerated-versions-on-other-architectures&quot;&gt;CRC32C uses accelerated versions on other architectures&lt;/h2&gt;

&lt;p&gt;… than just Intel-based ones. There was a hard coded check for the intel SSE
feature providing the accelerated instruction, but this totally skipped other
architectures. A brief check in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;linux.git/arch/*/crypto&lt;/code&gt; for files
implementing the accelerated versions revealed that there’s a bunch of them:
ARM, ARM64, MIPS, PowerPC, s390 and SPARC. I don’t have enough hardware to show
the improvements, though.&lt;/p&gt;

&lt;h2 id=&quot;automatically-remove-incompat-bit-for-raid56&quot;&gt;Automatically remove incompat bit for RAID5/6&lt;/h2&gt;

&lt;p&gt;While this is not the fix everybody is waiting on, it’s demonstrating
user-developer-user cycle how things can be improved. A filesystem created
with RAID5 or -6 profiles sets an incompatibility bit. That’s supposed to be
there as long as there’s any chunk using the profiles. User expectation is that
the bit should be removed once the chunks are eg. balanced away. This is what
got implemented and serves as a prior example for any future feature that
might get removed on a given filesystem. (Note from the future: I did that for the
RAID1C34 as well).&lt;/p&gt;

&lt;p&gt;Side note: for the chunk profile it’s easy because the runtime check of
presence is quick and requires only going through a list of chunk profiles
types. Example of the worst case would be dropping the incompat bit for LZO
after there are no compressed files using that algorithm. You can easily see
that this would require either enumerating all extent metadata (one time check)
or keeping track of count since mkfs time. This is IMHO not a typical request
and can be eventually done using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;btrfstune&lt;/code&gt; tool on an unmounted
filesystem.&lt;/p&gt;
</description>
				<pubDate>Wed, 11 Dec 2019 00:00:00 +0100</pubDate>
				<link>https://kdave.github.io/btrfs-hilights-5.3/</link>
				<guid isPermaLink="true">https://kdave.github.io/btrfs-hilights-5.3/</guid>
			</item>
		
			<item>
				<title>BLAKE3 vs BLAKE2 for BTRFS</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;Irony isn’t it. The paint of BLAKE2 as BTRFS checksum algorithm hasn’t dried
yet, 1-2 weeks to go but there’s a successor to it. Faster, yet still supposed to
be strong. For a second or two I considered ripping out all the work and … no
not really but I do admit the excitement.&lt;/p&gt;

&lt;p&gt;Speed and strength are competing goals for a hash algorithm. The speed can be
evaluated by anyone, not so much for the strength. I am no cryptographer and
for that area rely on expertise and opinion of others. That BLAKE was a SHA3
finalist is a good indication, where BLAKE2 is it’s successor, weakened but not
weak. BLAKE3 is yet another step trading off strength and speed.&lt;/p&gt;

&lt;p&gt;Regarding BTRFS, BLAKE2 is going to be the faster of strong hashes for now (the
other one is SHA256). The argument I have for it now is proof of time. It’s
been deployed in many projects (even crypto currencies!), there are optimized
implementations, various language ports.&lt;/p&gt;

&lt;p&gt;The look ahead regarding more checksums is to revisit them in about 5 years.
Hopefully by that time there will be deployments, real workload performance
evaluations and overall user experience that will back future decisions.&lt;/p&gt;

&lt;p&gt;Maybe there are going to be new strong yet fast hashes developed. During my
research I learned about Kangaroo 12 that’s a reduced version of SHA3 (Keccak).
The hash is constructed in a different way, perhaps there might be a Kangaroo 2π
one day on par with BLAKE3. Or something else. Why not EDON-R, it’s #1 in many
of the cr.yp.to/hash benchmarks? Another thing I learned during the research is
that hash algorithms are twelve in a dozen, IOW too many to choose from. That
Kangaroo 12 is internally of a different construction might be a point for
selecting it to have wider range of “building block types”.&lt;/p&gt;

&lt;h2 id=&quot;quick-evaluation&quot;&gt;Quick evaluation&lt;/h2&gt;

&lt;p&gt;For BTRFS I have a micro benchmark, repeatedly hashing a 4 KiB block and using
cycles per block as a metric.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Block size: 4KiB&lt;/li&gt;
  &lt;li&gt;Iterations: 10000000&lt;/li&gt;
  &lt;li&gt;Digest size: 256 bits (32 bytes)&lt;/li&gt;
&lt;/ul&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Hash&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;Total cycles&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;Cycles/iteration&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Perf vs BLAKE3&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Perf vs BLAKE2b&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;BLAKE3  (AVX2)&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;111260245256&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;11126&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1.0&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;0.876 (-13%)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;BLAKE2b (AVX2)&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;127009487092&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;12700&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1.141 (+14%)&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1.0&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;BLAKE2b (AVX)&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;166426785907&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;16642&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1.496 (+50%)&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1.310 (+31%)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;BLAKE2b (ref)&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;225053579540&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;22505&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;2.022 (+102%)&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1.772 (+77%)&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Right now there’s only the reference Rust implementation and a derived C
implementation of BLAKE3, claimed not to be optimized but from my other
experience the compiler can do a good job optimizing programmers ideas away.
There’s only one BLAKE3 entry with the AVX2 implementation, the best hardware
support my testing box provides. As I had the other results of BLAKE2 at hand,
they’re in the table for comparison, but the most interesting pair are the AVX2
versions anyway.&lt;/p&gt;

&lt;p&gt;The improvement is 13-14%. Not much ain’t it, way less that the announced 4+x
faster than BLAKE2b. Well, it’s always important to interpret results of a
benchmark with respect to the environment of measurement and the tested
parameters.&lt;/p&gt;

&lt;p&gt;For BTRFS filesystem the block size is always going to be in kilobytes. I can’t
find what was the size of the official benchmark results, the bench.rs script
iterates over various sizes, so I assume it’s an average. Short input buffers
can skew the results as the setup/output overhead can be significant, while for
long buffers the compression phase is significant. I don’t have explanation for
the difference and won’t draw conclusions about BLAKE3 in general.&lt;/p&gt;

&lt;p&gt;One thing that I dare to claim is that I can sleep well because upon the above
evaluation, BLAKE3 won’t bring a notable improvement if used as a checksum
hash.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://kdave.github.io/selecting-hash-for-BTRFS&quot;&gt;new hash for BTRFS selection&lt;/a&gt;, same testing box for the measurements&lt;/li&gt;
  &lt;li&gt;https://github.com/BLAKE3-team/BLAKE3 – top commit 02250a7b7c80ded, 2020-01-13, upstream version 0.1.1&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://bench.cr.yp.to/primitives-hash.html&quot;&gt;DJB’s hash menu&lt;/a&gt; and &lt;a href=&quot;https://bench.cr.yp.to/results-hash.html&quot;&gt;per-machine results&lt;/a&gt; with numbers&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;personal-addendum&quot;&gt;Personal addendum&lt;/h2&gt;

&lt;p&gt;During the evaluations now and in the past, I’ve found it convenient if there’s
an offer of implementations in various languages. That eg. Keccak project pages
does not point me directly to a C implementation slightly annoyed me, but the
reference implementation in C++ was worse than BLAKE2 I did not take the next
step to compare the C version, wherever I would find it.&lt;/p&gt;

&lt;p&gt;BLAKE3 is fresh and Rust seems to be the only thing that has been improved
since the initial release. A plain C implementation without any
warning-not-optimized labels would be good. I think that C versions will appear
eventually, besides that Rust is now the new language hotness, there are
projects not yet &lt;em&gt;“let’s rewrite it in Rust”&lt;/em&gt;. Please Bear with us.&lt;/p&gt;
</description>
				<pubDate>Tue, 21 Jan 2020 00:00:00 +0100</pubDate>
				<link>https://kdave.github.io/blake3-vs-blake2-in-btrfs/</link>
				<guid isPermaLink="true">https://kdave.github.io/blake3-vs-blake2-in-btrfs/</guid>
			</item>
		
			<item>
				<title>Btrfs hilights in 5.5: 3-copy and 4-copy block groups</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;A bit more detailed overview of a btrfs update that I find interesting, see the
&lt;a href=&quot;https://git.kernel.org/linus/97d0bf96a0d0986f466c3ff59f2ace801e33dc69&quot;&gt;pull
request&lt;/a&gt;
for the rest.&lt;/p&gt;

&lt;h2 id=&quot;new-block-group-profiles-raid1c3-and-raid1c4&quot;&gt;New block group profiles RAID1C3 and RAID1C4&lt;/h2&gt;

&lt;p&gt;There are two new block group profiles enhancing capabilities of the RAID1
types with more copies than 2. Brief overview of the profiles is in the table
below, for table with all profiles see manual page of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mkfs.brtfs&lt;/code&gt;, also
available &lt;a href=&quot;https://btrfs.wiki.kernel.org/index.php/Manpage/mkfs.btrfs#PROFILES&quot;&gt;on
wiki&lt;/a&gt;.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Profile&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;Copies&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;Utilization&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;Min devices&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;RAID1&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;2&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;50%&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;RAID1C3&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;3&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;33%&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;3&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;RAID1C4&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;4&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;25%&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;4&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;The way all the RAID1 types work is that there are 2 / 3 / 4 exact copies over
all available devices. The terminology is different from linux MD RAID, that
can do any number of copies. We decided not to do that in btrfs to keep the
implementation simple. Another point for simplicity is from the users’
perspective. That RAID1C3 provides 3 copies is clear from the type. Even after
adding a new device and not doing balance, the guarantees about redundancy
still hold. Newly written data will use the new device together with 2 devices
from the original set.&lt;/p&gt;

&lt;p&gt;Compare that with a hypothetical RAID1CN, on a filesystem with M devices (N &amp;lt;=
M). When the filesystem starts with 2 devices, equivalent to RAID1, adding a
new one will have mixed redundancy guarantees after writing more data. Old data
with RAID1, new with RAID1C3 – but all accounted under RAID1CN profile. A full
re-balance would be required to make it a reliable 3-copy RAID1. Add another
device, going to RAID1C4, same problem with more data to shuffle around.&lt;/p&gt;

&lt;p&gt;The allocation policy would depend on number of devices, making it hard for the
user to know the redundancy level. This is already the case for
RAID0/RAID5/RAID6. For the striped profile RAID0 it’s not much of a problem,
there’s no redundancy. For the parity profiles it’s been a known problem and
new balance filter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stripe&lt;/code&gt; has been added to support fine grained selection of
block groups.&lt;/p&gt;

&lt;p&gt;Speaking about RAID6, there’s the elephant in the room, trying to cover write
hole. Lack of a resiliency against 2 device damage has been bothering all of us
because of the known write hole problem in the RAID6 implementation. How this
is going to be addressed is for another post, but for now, the newly added
RAID1C3 profile is a reasonable substitute for RAID6.&lt;/p&gt;

&lt;h3 id=&quot;how-to-use-it&quot;&gt;How to use it&lt;/h3&gt;

&lt;p&gt;On a freshly created filesystem it’s simple:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# mkfs.btrfs -d raid1c3 -m raid1c4 /dev/sd[abcd]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The command combines both new profiles for sake of demonstration, you should
always consider the expected use and required guarantees and choose the
appropriate profiles.&lt;/p&gt;

&lt;p&gt;Changing the profile later on an existing filesystem works as usual, you can
use:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# btrfs balance start -mconvert=raid1c3 /mnt/path
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Provided there are enough devices and enough space to do the conversion, this
will go through all metadadata block groups and after it finishes, all of them
will be of the of the desired type.&lt;/p&gt;

&lt;h3 id=&quot;backward-compatibility&quot;&gt;Backward compatibility&lt;/h3&gt;

&lt;p&gt;The new block groups are not understood by old kernels and can’t be mounted,
not even in the read-only mode. To prevent that a new incompatibility bit is
introduced, called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;raid1c34&lt;/code&gt;. Its presence on a device can be checked by
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;btrfs inspect-internal dump-super&lt;/code&gt; in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;incompat_flags&lt;/code&gt;. On a running
system the incompat features are exported in sysfs,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/sys/fs/btrfs/UUID/features/raid1c34&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;outlook&quot;&gt;Outlook&lt;/h3&gt;

&lt;p&gt;There is no demand for RAID1C5 at the moment (I asked more than once). The
space utilization is low already, the RAID1C4 survives 3 dead devices so IMHO
this is enough for most users. Extending resilience to more devices should
perhaps take a different route.&lt;/p&gt;

&lt;p&gt;With more copies there’s potential for parallelization of reads from multiple
devices. Up to now this is not optimal, there’s a decision logic that’s
semi-random based on process ID of the btrfs worker threads or process
submitting the IO. Better load balancing policy is a work in progress and could
appear in 5.7 at the earliest (because 5.6 development is now in fixes-only
mode).&lt;/p&gt;

&lt;h3 id=&quot;look-back&quot;&gt;Look back&lt;/h3&gt;

&lt;p&gt;The history of the patchset is a bit bumpy. There was enough motivation and
requests for the functionality, so I started the analysis what needs to be
done. Several cleanups were necessary to unify code and to make it easily
extendable for more copies while using the same mirroring code. In the end
change a few constants and be done.&lt;/p&gt;

&lt;p&gt;Following with testing, I tried simple mkfs and conversions, that worked well.
Then scrub, overwrite some blocks and let the auto-repair do the work. No
hiccups. The remaining and important part was the device replace, as the
expected use case was to substitute RAID6, replacing a missing or damaged disk.
I wrote the test script, replace 1 missing, replace 2 missing. And it did not
work. While the filesystem was mounted, everything seemed OK. Unmount, check
again and the devices were still missing. Not cool, right.&lt;/p&gt;

&lt;p&gt;Due to lack of time before the upcoming merge window (a code freeze before next
development cycle), I had to declare it not ready and put it aside. This was in
late 2018. For a highly requested feature this was not an easy decision. Should
it be something less important, the development cycle between rc1 and final
release provides enough time to fix things up. But due to the maintainer role
with its demands I was not confident that I could find enough time to debug and
fix the remaining problem. Also nobody offered help to continue the work, but
that’s how it goes.&lt;/p&gt;

&lt;p&gt;At the late 2019 I had some spare time and looked at the pending work again.
Enhanced the test script with more debugging messages and more checks. The code
worked well, the test script was subtly broken. Oh well, what a blunder. That
cost a year, but on the other hand releasing a highly requested feature that
lacks an important part was not an appealing option.&lt;/p&gt;

&lt;p&gt;The patchset was added to 5.5 development queue at about the last time before
freeze, final 5.5 release happened a week ago.&lt;/p&gt;
</description>
				<pubDate>Sun, 02 Feb 2020 00:00:00 +0100</pubDate>
				<link>https://kdave.github.io/btrfs-hilights-5.5-raid1c34/</link>
				<guid isPermaLink="true">https://kdave.github.io/btrfs-hilights-5.5-raid1c34/</guid>
			</item>
		
			<item>
				<title>Btrfs hilights in 5.5: new hashes</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;A bit more detailed overview of a btrfs update that I find interesting, see the
&lt;a href=&quot;https://git.kernel.org/linus/97d0bf96a0d0986f466c3ff59f2ace801e33dc69&quot;&gt;pull request&lt;/a&gt;
for the rest.&lt;/p&gt;

&lt;h2 id=&quot;more-checksum-algorithms&quot;&gt;More checksum algorithms&lt;/h2&gt;

&lt;p&gt;The first request for more checksums is several years old (2014), &lt;a href=&quot;https://lore.kernel.org/linux-btrfs/1416806586-18050-1-git-send-email-bo.li.liu@oracle.com&quot;&gt;it was
SHA256&lt;/a&gt;.
There was no followup of the patch but the discussion in the mail thread
brought the topic into light. Questions about why SHA256 and why not something
else (welcome to the zoo: SpookyHash, BLAKE2, CityHash, MurmurHash3, CRC64),
preferences, use cases etc. Browsing the mail thread again, I don’t see anybody
suggest SHA1 or MD5.  There were some open questions and suggestions and though
it’s an old discussion, most of the points were valid at the time of pre-5.5
evaluation and served as a checklist.  This is what I really like about the
community projects and btrfs users in particular.  Getting useful feedback on
topics out of scope of the filesystem itself.&lt;/p&gt;

&lt;p&gt;Fast forward to now, there are 3 new hashes:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Name&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;Digest size&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Notes&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;CRC32C&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;32bit&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;fast, weak, default, CPU support, backward compatible&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;XXHASH&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;64bit&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;fast, weak, good on modern CPUs&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;SHA256&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;256bit&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;slow, strong, FIPS certified, CPU support&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;BLAKE2B&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;256bit&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;slow, strong, good on 64bit architectures&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;You can find more about the &lt;a href=&quot;https://kdave.github.io/selecting-hash-for-btrfs/&quot;&gt;selection process&lt;/a&gt;
in another post.&lt;/p&gt;

&lt;h2 id=&quot;quick-start&quot;&gt;Quick start&lt;/h2&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# mkfs.btrfs --csum xxhash /dev/sda&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And the output:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;btrfs-progs v5.4.1
See http://btrfs.wiki.kernel.org for more information.

Label:              (null)
UUID:               9774b466-fa5d-4c2e-8b4f-479d0bb5873d
Node size:          16384
Sector size:        4096
Filesystem size:    10.00GiB
Block group profiles:
  Data:             single            8.00MiB
  Metadata:         DUP             256.00MiB
  System:           DUP               8.00MiB
SSD detected:       no
Incompat features:  extref, skinny-metadata
Checksum:           xxhash64
Number of devices:  1
Devices:
   ID        SIZE  PATH
    1    10.00GiB  /dev/sda
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For convenience, the hash names can be specified by aliases so both &lt;em&gt;xxhash&lt;/em&gt;
and &lt;em&gt;xxhash64&lt;/em&gt; are accepted on command line, similarly for &lt;em&gt;blake2&lt;/em&gt; it’s
&lt;em&gt;blake2b&lt;/em&gt;. This is based on a usability pattern, where humans don’t have to
remember the exact specification and copy &amp;amp; paste from the output works as
well.&lt;/p&gt;

&lt;h3 id=&quot;use-cases-and-outlook&quot;&gt;Use cases and outlook&lt;/h3&gt;

&lt;p&gt;For ordinary checksumming, all the hashes are considered good enough. CRC32C is
the weakest but it’s been with us since the beginning and has caught many
random bit flips.&lt;/p&gt;

&lt;p&gt;XXHASH is supposed to add to the strength with a good performance. Increased
digest size reduces collisions, but can’t compete with the crypto-strong
hashes. That can still be of great help for deduplication.&lt;/p&gt;

&lt;p&gt;From my perspective, the number of hashes should stay limited as the support is
needed not just in kernel but for other tooling. For &lt;em&gt;btrfs-progs&lt;/em&gt; it’s
mandatory to support them, but also bootloaders (*cough*in case they verify
checksums*cough*). The kernel support requires the hash implementations and
the modules become a dependency of &lt;em&gt;btrfs.ko&lt;/em&gt;.  This can increase overall size
and build time.&lt;/p&gt;

&lt;p&gt;One of the suggestions was to allow users to choose the hash out of all what
linux crypto API offers, not just the fixed set of hashes selected by
developers. I understand that from the point of view of users who can make the
decisions about trade-offs for their use case this is better, but I argue that
such users are not in majority. Satisfying the common case was the preferred
option, hopefully providing good options also for the knowledgeable users.
Providing and maintaining implementations of seven and one hashes would be
a burden for several projects.&lt;/p&gt;

&lt;p&gt;Yes, I’m aware of &lt;a href=&quot;https://github.com/BLAKE3-team/BLAKE3&quot;&gt;BLAKE3&lt;/a&gt;, but let’s
&lt;a href=&quot;https://kdave.github.io/blake3-vs-blake2-in-btrfs&quot;&gt;wait before adding new hashes&lt;/a&gt;. By
the time we do another round there might be more contenders or improved
versions.  There’s &lt;a href=&quot;https://fastcompression.blogspot.com/2019/03/presenting-xxh3.html&quot;&gt;XXH3&lt;/a&gt;
from the author of XXHASH, producing 128bit digest and is slightly faster.
However it is still not recommended for production use due to fine tuning and
finalization.&lt;/p&gt;

&lt;p&gt;The cryptographic hashes can be a building block for a keyed hash, ie.
checksums that can’t be subverted. There’s a
&lt;a href=&quot;https://lore.kernel.org/linux-btrfs/20191015121405.19066-1-jthumshirn@suse.de/&quot;&gt;patch implementing that&lt;/a&gt;,
currently in an RFC state. While the code is straightforward, adding a new
interface could use a feedback round. Please contact us in case you have
comments.&lt;/p&gt;

&lt;p&gt;Last but not least, strong hashes are a building block for deduplication. At
the moment btrfs supports only the out-of-band way, on demand by calling
an ioctl.  There are tools utilizing that, eg. &lt;a href=&quot;https://github.com/Zygo/bees&quot;&gt;BEES&lt;/a&gt;
or &lt;a href=&quot;https://github.com/markfasheh/duperemove&quot;&gt;duperemove&lt;/a&gt;,
calculating the block checksums by themselves. Exporting the raw checksums
would help to decrease CPU time and also external tracking of the checksums.&lt;/p&gt;

&lt;h3 id=&quot;implementation-notes&quot;&gt;Implementation notes&lt;/h3&gt;

&lt;p&gt;With the single checksum CRC32C, lots of code had hard coded size (4 bytes/32
bits) or functions and identifiers contained ‘crc32c’. This could not remain
once there are more hashes to be added, so a round of cleanups happened in
advance in 5.4.  I’d call it great preparatory work that paid off, because
adding new hashes was a matter of inserting new definition entries to a table.
The rest was behind abstraction of btrfs functions that call to the linux
crypto API.&lt;/p&gt;

&lt;p&gt;In parallel to the btrfs patches, the &lt;em&gt;BLAKE2B&lt;/em&gt; linux implementation was merged,
while &lt;em&gt;XXHASH&lt;/em&gt; was merged in 5.3 and SHA256 was there forever.
All in all, everything was ready in the same target release.&lt;/p&gt;
</description>
				<pubDate>Mon, 10 Feb 2020 00:00:00 +0100</pubDate>
				<link>https://kdave.github.io/btrfs-hilights-5.5-new-hashes/</link>
				<guid isPermaLink="true">https://kdave.github.io/btrfs-hilights-5.5-new-hashes/</guid>
			</item>
		
			<item>
				<title>Btrfs hilights in 5.4: tree checker updates</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;A bit more detailed overview of a btrfs update that I find interesting, see the
&lt;a href=&quot;https://git.kernel.org/linus/7d14df2d280fb7411eba2eb96682da0683ad97f6&quot;&gt;pull request&lt;/a&gt;
for the rest.&lt;/p&gt;

&lt;p&gt;There’s not much to show in this release. Some users find that good too, a boring release. But still there are some changes of interest. The 5.4 is a long-term support stable tree, stability and core improvements are perhaps more appropriate than features that need a release or two to stabilize.&lt;/p&gt;

&lt;p&gt;? stable not known in advance so not pushing half-baked features to stable, possibly requiring more intrusive fixups&lt;/p&gt;

&lt;p&gt;The development cycle happened over summer and this slowed down the pace of patch reviews and update turnarounds.&lt;/p&gt;

&lt;h2 id=&quot;tree-checker-updates&quot;&gt;Tree-checker updates&lt;/h2&gt;

&lt;p&gt;The tree-checker is a sanity checker of metadata that are read from/written to devices. Over time it’s being enhanced by more checks, let’s have a look at two of them.&lt;/p&gt;

&lt;h3 id=&quot;root_item-checks&quot;&gt;ROOT_ITEM checks&lt;/h3&gt;

&lt;p&gt;The item represents root of a b-tree, of the internal or the subvolume trees.&lt;/p&gt;

&lt;p&gt;Let’s take an example from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;btrfs inspect dump-tree&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;       item 0 key (EXTENT_TREE ROOT_ITEM 0) itemoff 15844 itemsize 439
                generation 5 root_dirid 0 bytenr 30523392 level 0 refs 1
                lastsnap 0 byte_limit 0 bytes_used 16384 flags 0x0(none)
                uuid 00000000-0000-0000-0000-000000000000
                drop key (0 UNKNOWN.0 0) level 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Some of the metadata inside the item allow only simple checks, following &lt;a href=&quot;https://git.kernel.org/linus/259ee7754b6793af8bdd77f9ca818bc41cfe9541&quot;&gt;commit 259ee7754b6793&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;key.objectid&lt;/code&gt; must match the tree that’s being read, though the code verifies only if the type is not 0&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;key.offset&lt;/code&gt; must be 0&lt;/li&gt;
  &lt;li&gt;block offset &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytenr&lt;/code&gt; must be aligned to sector size (4KiB in this case)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;itemsize&lt;/code&gt; depends on the item type, but for the root item it’s fixed value&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;level&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;drop_level&lt;/code&gt; is 0 to 7, but it’s not possible to cross check if the tree has really of that level&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;generation&lt;/code&gt; must be lower than the super block generation, same for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lastsnap&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;flags&lt;/code&gt; can be simply compared to the bit mask of allowed flags, right now there are two, one represents a read-only subvolume and another a subvolume that has been marked as deleted but its blocks not yet cleaned&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;refs&lt;/code&gt; is a reference counter and sanity check would require reading all the expected reference holders, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes_used&lt;/code&gt; would need to look up the block that it accounts, etc. The subvolume trees have more data like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctime&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;otime&lt;/code&gt; and real &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uuid&lt;/code&gt;s. If you wonder what’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;byte_limit&lt;/code&gt;, this used to be a mechanism to emulate quotas by setting the limit value, but it has been deprecated and unused for a long time. One day we might to find another purpose for the bytes.&lt;/p&gt;

&lt;p&gt;Many of the tree-checker enhancements are follow ups to fuzz testing and reports, as it was in this case. The &lt;a href=&quot;https://bugzilla.kernel.org/show_bug.cgi?id=203261&quot;&gt;bug report&lt;/a&gt; shows that some of the incorrect data were detected and even triggered auto-repair (as this was on filesystem with DUP metadata) but there was too much damage and it crashed at some point. The crash was not random but a BUG_ON of an unexpected condition, that’s sanity check of last resort. Catching inconsistent data early with a graceful error handling is of course desired and ongoing work.&lt;/p&gt;

&lt;h3 id=&quot;extent-metadata-item-checks&quot;&gt;Extent metadata item checks&lt;/h3&gt;

&lt;p&gt;There are two item types that represent extents and information about sharing. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EXTENT_ITEM&lt;/code&gt; is older and bigger  while &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;METADATA_ITEM&lt;/code&gt; is the building block of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;skinny-metadata&lt;/code&gt; feature, smaller and more compact. Both items contain type of reference(s) and the owner (a tree id). Besides the generic checks that also the root item does (alignment, value ranges, generation), there’s a number of allowed combinations of the reference types and extent types. The &lt;a href=&quot;https://git.kernel.orgl/linus/f82d1c7ca8ae1bf89e8d78c5ecb56b6b228c1a75&quot;&gt;commit f82d1c7ca8ae1bf&lt;/a&gt; implements that, however further explanation is out of scope of the overview as the sharing and references are the fundamental design of btrfs.&lt;/p&gt;

&lt;p&gt;Example of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;METADATA_ITEM&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;        item 170 key (88145920 METADATA_ITEM 0) itemoff 10640 itemsize 33
                refs 1 gen 27 flags TREE_BLOCK
                tree block skinny level 0
                tree block backref root FS_TREE
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EXTENT_ITEM&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;        item 27 key (20967424 EXTENT_ITEM 4096) itemoff 14895 itemsize 53
                refs 1 gen 499706 flags DATA
                extent data backref root FS_TREE objectid 8626071 offset 0 count 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This for a simple case with one reference, tree (for metadata) and ordinary data, so comparing the sizes shows 20 bytes saved. On my 20GiB root partition with about 70 snapshots there are XXX EXTENT and YYY METADATA items.&lt;/p&gt;

&lt;p&gt;Otherwise there can be more references inside one item (eg. many snapshots of a file that is randomly updated over time) so the overhead of the item itself is smaller&lt;/p&gt;
</description>
				<pubDate>Sat, 15 Feb 2020 00:00:00 +0100</pubDate>
				<link>https://kdave.github.io/btrfs-hilights-5.4/</link>
				<guid isPermaLink="true">https://kdave.github.io/btrfs-hilights-5.4/</guid>
			</item>
		
			<item>
				<title>Authenticated hashes for btrfs (part 1)</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;There was a request to provide authenticated hashes in btrfs, natively as one of the btrfs checksum algorithms. Sounds fun but there’s always more to it, even if this sounds easy to implement.&lt;/p&gt;

&lt;p&gt;Johaness T. at that time in SUSE sent the patchset adding the support for SHA256 &lt;a href=&quot;https://lore.kernel.org/linux-fsdevel/20200428105859.4719-1-jth@kernel.org/&quot;&gt;[1]&lt;/a&gt; with a Labs conference paper, summarizing existing solutions and giving details about the proposed implementation and use cases.&lt;/p&gt;

&lt;p&gt;The first version of the patchset posted got some feedback, issues were found and some ideas suggested. Things have stalled a bit, but the feature is still very interesting and really not hard to implement. The support for additional checksums has provided enough support code to just plug in the new algorithm and enhance the existing interfaces to provide the key bytes. So until now I’ve assumed you know what an authenticated hash means, but for clarity and in simple terms: a checksum that depends on a key. The main point is that it’s impossible to generate the same checksum for given data without knowing the key, where &lt;em&gt;impossible&lt;/em&gt; is used in the cryptographic-strength sense, there’s an almost zero probability doing that by chance and brute force attack is not practical.&lt;/p&gt;

&lt;h2 id=&quot;auth-hash-fsverity&quot;&gt;Auth hash, fsverity&lt;/h2&gt;

&lt;p&gt;Notable existing solution for that is &lt;em&gt;fsverity&lt;/em&gt; that works in read-only fashion, where the key is securely hidden and used only to verify that data that are read from media haven’t been tampered with. A typical use case is an OS image in your phone. But that’s not all. Images of OS appear in all sorts of boxed devices, IoT. Nowadays, with explosion of edge computing, assuring integrity of the end devices is a fundamental requirement.&lt;/p&gt;

&lt;p&gt;Where btrfs can add some value is the read AND write support, with an authenticated hash. This brings questions around key handling, and not everybody is OK with a device that could potentially store malicious/invalid data with a proper authenticated checksum. So yeah, use something else, this is not your use case, or maybe there’s another way how to make sure the key won’t be compromised easily. This is beyond the scope of what filesystem can do, though.&lt;/p&gt;

&lt;p&gt;As an example use case of writable filesystem with authenticated hash: detect outside tampering with on-disk data, eg. when the filesystem was unmounted. Filesystem metadata formats are public, interesting data can be located by patterns on the device, so changing a few bytes and updating the checksum(s) is not hard.&lt;/p&gt;

&lt;p&gt;There’s one issue that was brought up and I think it’s not hard to observe anyway: there’s a total dependency on the key to verify a basic integrity of the data. Ie. without the key it’s not possible to say if the data are valid as if a basic checksum was used. This might be still useful for a read-only access to the filesystem, but absence of key makes this impossible.&lt;/p&gt;

&lt;h2 id=&quot;existing-implementations&quot;&gt;Existing implementations&lt;/h2&gt;

&lt;p&gt;As was noted in the LWN discussion &lt;a href=&quot;https://lwn.net/Articles/819143/&quot;&gt;[2]&lt;/a&gt;, what ZFS does, there are two checksums. One is the authenticated and one is not. I point you to the comment stating that, as I was not able to navigate far enough in the ZFS code to verify the claim, but the idea is clear. It’s said that the authenticated hash is eg. SHA512 and the plain hash is SHA256, split half/half in the bytes available for checksum. The way the hash is stored is a simple trim of the first 16 bytes of each checksum and store them consecutively. As both hashes are cryptographically strong, the first 16 bytes &lt;em&gt;should&lt;/em&gt; provide enough strength despite the truncation. Where 16 bytes is 128 bits.&lt;/p&gt;

&lt;p&gt;When I was thinking about that, I had a different idea how to do that. Not that copying the scheme would not work for btrfs, anything that the linux kernel crypto API provides is usable, the same is achievable. I’m not judging the decisions what hashes to use or how to do the split, it works and I don’t see a problem in the strength. Where I see potential for an improvement is performance, without sacrificing strength &lt;em&gt;too much&lt;/em&gt;. Trade-offs.&lt;/p&gt;

&lt;p&gt;The CPU or software implementation of SHA256 is comparably slower to checksums with hardware aids (like CRC32C instructions) or hashes designed to perform well on CPUs. That was the topic of the previous round of new hashes, so we now compete against BLAKE2b and XXHASH. There are CPUs with native instructions to calculate SHA256 and the performance improvement is noticeable, orders of magnitude better. But the support is not as widespread as eg. for CRC32C. Anyway, there’s always choice and hardware improves over time. The number of hashes may seem to explode but as long as it’s manageable inside the filesystem, we take it. And a coffee please.&lt;/p&gt;

&lt;h2 id=&quot;secondary-hash&quot;&gt;Secondary hash&lt;/h2&gt;

&lt;p&gt;The checksum scheme proposed is to use a cryptographic hash and a non-cryptographic one. Given the current support for SHA256 and BLAKE2b, the cryptographic hash is given. There are two of them and that’s fine. I’m not drawing an exact parallel with ZFS, the common point for the cryptographic hash is that there are limited options and the calculation is expensive by design. This is where the non-cryptographic hash can be debated. Also I want to call it &lt;em&gt;secondary&lt;/em&gt; hash, with obvious meaning that it’s not too important by default and comes second when the authenticated hash is available.&lt;/p&gt;

&lt;p&gt;We have CRC32C and XXHASH to choose from. Note that there are already two hashes from the start so supporting both secondary hashes would double the number of final combinations. We’ve added XXHASH to enhance the checksum collision space from 32 bits to 64 bits. What I propose is to use just XXHASH as the secondary hash, resulting in two new hashes for the authenticated and secondary hash. I haven’t found a good reason to also include CRC32C.&lt;/p&gt;

&lt;p&gt;Another design point was where to do the split and truncation. As the XXHASH has fixed length, this could be defined as 192 bits for the cryptographic hash and 64 bits for full XXHASH.&lt;/p&gt;

&lt;p&gt;Here we are, we could have authenticated SHA256 accompanied by XXHASH, or the same with BLAKE2b. The checksum split also splits the decision tree what to do when the checksum partially matches. For a single checksum it’s a simple &lt;em&gt;yes/no&lt;/em&gt; decision. The partial match is the interesting case:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;primary (key available) hash matches, secondary does not – as the authenticated hash is hard to forge, it’s trusted (even if it’s not full length of the digest)&lt;/li&gt;
  &lt;li&gt;primary (key available) does not match, secondary does not – checksum mismatch for the same reason as above&lt;/li&gt;
  &lt;li&gt;primary (key not available) does not match, secondary does – this is the prime time for the secondary hash, the floor is yours&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This leads to 4 outcomes of the checksum verification, compared to 2. A boolean type can simply represent the yes/no outcome but for two hashes it’s not that easy. It depends on the context, though I think it still should be straightforward to decide what to do that in the code. Nevertheless, this has to be updated in all calls to checksum verification and has to reflect the key availability eg. in case where the data are auto-repaired during scrub or when there’s a copy.&lt;/p&gt;

&lt;h2 id=&quot;performance-considerations&quot;&gt;Performance considerations&lt;/h2&gt;

&lt;p&gt;The performance comparison should be now clear: we have the potentially slow SHA256 but fast XXHASH, for each metadata and data block, vs slow SHA512 and slow SHA256. As I reckon it’s possible to also select SHA256/SHA256 split in ZFS, but that can’t beat SHA256/XXHASH.&lt;/p&gt;

&lt;p&gt;The key availability seems to be the key point in all that, puns notwithstanding. The initial implementation assumed for simplicity to provide the raw key bytes to kernel and to the userspace utilities. This is maybe OK for a prototype but under any circumstances can’t survive until a final release. There’s key management wired deep into linux kernel, there’s a library for the whole API and command line tools. We ought to use that. Pass the key by name, not the raw bytes.&lt;/p&gt;

&lt;p&gt;Key management has it’s own culprits and surprises (key owned vs possessed), but let’s assume that there’s a standardized way how to obtain the key bytes from the key name. In kernel its “READ_USER_KEY_BYTES”, in userspace it’s either &lt;em&gt;keyctl_read&lt;/em&gt; from &lt;em&gt;libkeyutils&lt;/em&gt; or a raw syscall to &lt;em&gt;keyctl&lt;/em&gt;. Problem solved, on the low-level. But, well, don’t try that over &lt;em&gt;ssh&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Accessing a btrfs image for various reasons (check, image, restore) now needs the key to verify data or even the key itself to perform modifications (check + repair). The command line interface has to be extended for all commands that interact with the filesystem offline, ie. the image and not the mounted filesystem.&lt;/p&gt;

&lt;p&gt;This results to a global option, like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;btrfs --auth-key 1234 ispect-internal dump-tree&lt;/code&gt;, compared to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;btrfs inspect-internal dump-tree --auth-key 1234&lt;/code&gt;. This is not finalized, but a global option is now the preferred choice.&lt;/p&gt;

&lt;h2 id=&quot;final-words&quot;&gt;Final words&lt;/h2&gt;

&lt;p&gt;I have a prototype, that does not work in all cases but at least passes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mkfs&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mount&lt;/code&gt;. The number of checksum verification cases got above what I was able to fix by the time of writing this. I think this has enough matter on itself so I’m pushing it out out as part 1. There are open questions regarding the command line interface and also a some kind of proof or discussion regarding attacks. Stay tuned.&lt;/p&gt;

&lt;p&gt;References:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;[1] &lt;a href=&quot;https://lore.kernel.org/linux-fsdevel/20200428105859.4719-1-jth@kernel.org/&quot;&gt;https://lore.kernel.org/linux-fsdevel/20200428105859.4719-1-jth@kernel.org/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;[2] &lt;a href=&quot;https://lwn.net/Articles/819143/&quot;&gt;https://lwn.net/Articles/819143/&lt;/a&gt; LWN discussion under &lt;a href=&quot;https://lwn.net/Articles/818842/&quot;&gt;Authenticated Btrfs (2020)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
				<pubDate>Mon, 24 May 2021 00:00:00 +0200</pubDate>
				<link>https://kdave.github.io/authenticated-hashes-for-btrfs-part1/</link>
				<guid isPermaLink="true">https://kdave.github.io/authenticated-hashes-for-btrfs-part1/</guid>
			</item>
		
			<item>
				<title>CUDA not initialized after resume (unknown error)</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tl;dr&lt;/code&gt; &lt;em&gt;CUDA returning an &lt;strong&gt;unknown error&lt;/strong&gt; upon initialization after resume on
linux can be solved by reloading kernel module nvidia_uvm.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There are some problems reported where with CUDA returns an unknown error upon
initialization, while there’s no clear cause nor a clear way how to fix it.
I’ve found
&lt;a href=&quot;https://victorwyee.com/engineering/failed-call-to-cuinit-cuda-error-unknown/&quot;&gt;https://victorwyee.com/engineering/failed-call-to-cuinit-cuda-error-unknown/&lt;/a&gt;
listing various solutions from rebooting to tweaking environment variables.&lt;/p&gt;

&lt;p&gt;I’ve hit another problem that does not seem to be explicitly mentioned as the
cause or it could have been misdiagnosed. After switching the built in Intel
graphic card to be primary and NVIDIA card only for computations, it was not
possible to run any application using CUDA. All it reported back were &lt;em&gt;unknown
error&lt;/em&gt;s.&lt;/p&gt;

&lt;p&gt;The Leela chess &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lc0&lt;/code&gt; reported CUDA version 0.0.0 with message like:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   $ ./lc0
      _
   |   _ | |
   |_ |_ |_| v0.28.2 built Dec 13 2021
   ucinewgame
   Found pb network file: ./192x15-2021_1212_2050_25_709.pb.gz
   Creating backend [cuda-auto]...
   Switching to [cuda]...
   CUDA Runtime version: 0.0.0
   WARNING: CUDA Runtime version mismatch, was compiled with version 11.4.0
   Latest version of CUDA supported by the driver: 11.4.0
   error CUDA error: unknown error (../../src/neural/cuda/network_cuda.cc:134)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The line in source file is simply reporting errors:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   134     ReportCUDAErrors(cudaGetDeviceCount(&amp;amp;total_gpus));
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is the first place where the errors are checked, a quick trivial CUDA
program fails on the first memory allocation, with the same unkown error.&lt;/p&gt;

&lt;p&gt;I guess this stresses out the importance of error checking, namely when some
piece of hardware is involved. Though this fails on the first attempt to use the
API, there are possibly more cases during a long computation and many tasks using
the GPU in parallel.&lt;/p&gt;

&lt;p&gt;A reboot fixed the problem, until the next suspend, which is impractical and
setting up the work environment gets annoying. I have tried to look for some
utility/command that is supposed to be run after resume. There’s a script called
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nvidia-sleep.sh&lt;/code&gt; that is the callback script for suspend and resume. Running
that with parameter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;suspend&lt;/code&gt; manually while the system was up was not a good
idea as it switched me out of the graphical desktop to some virtual terminal
without any way to undo that. Also running that with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resume&lt;/code&gt; did not help
eiter (and does not even make sense after the first proper resume).&lt;/p&gt;

&lt;p&gt;There are no obvious signs that something could be wrong after resume, nothing
in the logs and running games utilizing acceleration works (judging by FPS).
One advice recommends to run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nvidia-modprobe&lt;/code&gt;, in case some of the 4 modules is
not loaded (nvidia_uvm, nvidia_drm, nvidia_modeset, nvidia). Besides the UVM
module, all are unused.&lt;/p&gt;

&lt;p&gt;Right after resume the modules look like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; nvidia_drm             69632  2
 nvidia_modeset       1204224  3 nvidia_drm
 nvidia_uvm           2531328  0
 nvidia              35373056  90 nvidia_uvm,nvidia_modeset
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That there’s 0 (usage by other modules) brought some suspicion, because
according to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nvidia-smi&lt;/code&gt;, there’s a least Xorg keeping a few megabytes of
allocated memory (which may or may not be related though).&lt;/p&gt;

&lt;p&gt;I’ve reloaded the nvidia_uvm module, because it was the only thing possible to
do with the modules:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; # modprobe -r nvidia_uvm
 # modprobe nvidia_uvm
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And it started to work. Then quick check, lc0, works again. Now the module list is:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; nvidia_uvm           2531328  2
 nvidia_drm             69632  2
 nvidia_modeset       1204224  3 nvidia_drm
 nvidia              35373056  204 nvidia_uvm,nvidia_modeset
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;While this is still a workaround, it’s much better than rebooting and a
post-resume hook should be able to make it work automatically.&lt;/p&gt;

&lt;p&gt;The suspend script is in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/lib/systemd/system-sleep/&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;     &lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;
     &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in
	 &lt;/span&gt;post&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		     &lt;span class=&quot;nb&quot;&gt;sleep &lt;/span&gt;4
		     modprobe &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; nvidia_uvm
		     &lt;span class=&quot;nb&quot;&gt;sleep &lt;/span&gt;1
		     modprobe nvidia_uvm
	     &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
     &lt;span class=&quot;k&quot;&gt;esac&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
				<pubDate>Wed, 12 Jan 2022 00:00:00 +0100</pubDate>
				<link>https://kdave.github.io/cuda-unknown-error/</link>
				<guid isPermaLink="true">https://kdave.github.io/cuda-unknown-error/</guid>
			</item>
		
			<item>
				<title>JSON format dumper (a C API)</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;We’ve had users asking for a machine readable output of btrfs-progs commands,
suggesting to add an alternative way to dump the data in a structured format
e.g.  json. And nowadays this is very common in many if not all commands
provided by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;util-linux&lt;/code&gt;. Try &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lscpu --json&lt;/code&gt;, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lsblk --json&lt;/code&gt;. Feeding such
output to python or a shell-friendly json parser is going to make life easier.
So that’s the background motivation.&lt;/p&gt;

&lt;p&gt;Adding that to btrfs-progs is a task for long winter evenings, but the first
step has been made. I wrote yet another json dumper. Of course this was
preceded by a research about the state of existing libraries or files to copy.
But why not have some fun writing one nevertheless.&lt;/p&gt;

&lt;p&gt;The requirements:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;produce valid json (validators exist)&lt;/li&gt;
  &lt;li&gt;allow nesting of compound structures&lt;/li&gt;
  &lt;li&gt;hashes (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{key=value}&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;arrays (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[value, value, value]&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;simple values (integer, string, uuid, time, …)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The nesting was one of the things I have not found in the existing libraries, or not
implemented properly. The output must be a valid json and the single most
difficult thing was the placement of continuation comma “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;,&lt;/code&gt;”. There must be none
after the last object in the sequence. When the dump is done incrementally, the
next object is often not known while printing the current one. So the comma
cannot be printed unconditionally and previous state needs to be stored
until the last object is dumped.&lt;/p&gt;

&lt;p&gt;But, it’s not sufficient to keep track of the last object only, simply nest
some hashes and arrays. Like this:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;first&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;       &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;nested&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;             &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;             &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;value2&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;       &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;last&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Last objects in sequences are on lines 6, 7, 8 and 10, so this needs a stack
for tracking that. The main building blocks for correct syntax:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;track depth of structured types&lt;/li&gt;
  &lt;li&gt;print delayed “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;,&lt;/code&gt;” when there’s next object in sequence&lt;/li&gt;
  &lt;li&gt;quoting or escaping&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rest is for readable output, indentation is simply derived from the nesting
level.&lt;/p&gt;

&lt;p&gt;The code representation of the json object should be straightforward, basically
translating the objects into API calls, for compound object there’s the start
and end element. Element nesting must be proper. On the lower level, there
should be some nice specification of the key/value formatting.&lt;/p&gt;

&lt;p&gt;I’ve ended up with a static declaration of the value formatting specifiers in a
list, the actual structure of the json objects will be defined by API calls
referring back to the spec structure.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rowspec&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out_text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out_json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;key&lt;/code&gt; refers to the key (name), the rest of the structure is relevant for
the value formatting. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;out_text&lt;/code&gt; can be ignored for now, it’s a
generalization of the output formatting so the same code is used for plain text
and json output, the switch is done from the outside (e.g. by a command line
option).&lt;/p&gt;

&lt;p&gt;Basic value types are a string and number. For the purposes of btrfs-progs
there are more and so far built in the formatter, but it’s extensible (on the
source level, not dynamically). Additional custom types are UUID, qgroupid (a
u64 split into 16 and 48 bits), size (human friendly formatting of byte suffix
values), and time. Another example of customization is that there are actually
two byte size formatters, one that prints “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-&lt;/code&gt;” instead of zero value.&lt;/p&gt;

&lt;p&gt;The structural API is simple:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;start/end the whole json document &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fmt_start&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fmt_end&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;start/end optionally named group,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fmt_print_start_group&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fmt_print_end_group&lt;/code&gt;, when the name is defined it
means it’s a map/hash &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;key&quot;: &quot;value&quot;&lt;/code&gt;, or a plain array made of “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[ value,
... ]&lt;/code&gt;”&lt;/li&gt;
  &lt;li&gt;for list values there’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fmt_start_value&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fmt_end_value&lt;/code&gt; so there can be not
just a simple value but also a compound one&lt;/li&gt;
  &lt;li&gt;and remaining is a simple value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fmt_start_value&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fmt_end_value&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most of them take a reference to the rowspec, this is convenient that at the
time we’d like to print the value we summon it by its name, the rest is in the
table. All the API calls take a context structure that stores the nesting level
(for indentation and sanity checks) and some internal data.&lt;/p&gt;

&lt;p&gt;Now the above example would not be the best one to demonstrate the API but
let’s try:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rowspec&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;first&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;map&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out_json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;first&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;nested&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;map&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out_json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;nested&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;list&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out_json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;key&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;str&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out_json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;format_ctx&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;fmt_start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;fmt_print_start_group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;first&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JSON_TYPE_MAP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;fmt_print_start_group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;nested&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JSON_TYPE_MAP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;fmt_print_start_group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JSON_TYPE_ARRAY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;fmt_print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;fmt_print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;value2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;fmt_print_end_group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;fmt_print_end_group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;fmt_print_end_group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;fmt_print_start_group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;last&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JSON_TYPE_MAP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;fmt_print_end_group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fmt_end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That should demonstrate it. There might be some slight tweaks needed as I took
it from a specialized use but would like to present it as a generic API. So far
it’s not generic, it might become one. With sources available it’s available for
further reuse, I don’t plan to make it a standalone library but if there’s
interest then, well, why not.&lt;/p&gt;

&lt;h1 id=&quot;examples&quot;&gt;Examples&lt;/h1&gt;

&lt;p&gt;The simple values can be formatted in multiple ways, e.g. size values with
suffixes or raw numbers, though it’s defined as multiple keys:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;size&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%llu&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out_json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;size&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;size-si&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;size&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out_json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;size&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;size-si-not-zero&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;size-or-none&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out_json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;size&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Raw formats starting with “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%&lt;/code&gt;” are passed to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;printf&lt;/code&gt;, this lets it do all the
heavy work. The special formatters may need additional parameters, in this case
it’s the pretty printer mode for size.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RAW&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;fmt_print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;size&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;fmt_print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;size-si&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SI_NO_ZERO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;fmt_print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;size-si-not-zero&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;size-or-none&lt;/code&gt; format prints “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-&lt;/code&gt;” instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt;. As can be seen here,
not all the row specifiers need to be used at once.&lt;/p&gt;

&lt;h1 id=&quot;references&quot;&gt;References&lt;/h1&gt;

&lt;p&gt;Source links point to the most recent release so there might be an update since
the time I write this but I’m not expecting significant changes.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/kdave/btrfs-progs/blob/master/common/format-output.h&quot;&gt;https://github.com/kdave/btrfs-progs/blob/master/common/format-output.h&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/kdave/btrfs-progs/blob/master/common/format-output.c&quot;&gt;https://github.com/kdave/btrfs-progs/blob/master/common/format-output.c&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/kdave/btrfs-progs/blob/master/tests/json-formatter-test.c&quot;&gt;https://github.com/kdave/btrfs-progs/blob/master/tests/json-formatter-test.c&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/wireshark/wireshark/blob/master/wsutil/json_dumper.c&quot;&gt;https://github.com/wireshark/wireshark/blob/master/wsutil/json_dumper.c&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
				<pubDate>Wed, 09 Aug 2023 00:00:00 +0200</pubDate>
				<link>https://kdave.github.io/json-dumper/</link>
				<guid isPermaLink="true">https://kdave.github.io/json-dumper/</guid>
			</item>
		
			<item>
				<title>VIM tip: split file to 2 panes, lines continued</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;blockquote&gt;
  &lt;p&gt;Vim has the excellent feature to split the window to multiple panes, but can it
open one file in two vertical tabs and let the contents of left pane continue
in the one next to it?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;From&lt;/p&gt;

&lt;table&gt;
&lt;tr&gt;&lt;td width=&quot;400px&quot;&gt;1 ...&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2 ...&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;3 ...&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;4 ...&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;5 ...&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;6 ...&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;to&lt;/p&gt;

&lt;table&gt;
&lt;tr&gt;&lt;td width=&quot;195px&quot;&gt;1 ...&lt;/td&gt;&lt;td width=&quot;195px&quot;&gt;7 ...&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2 ...&lt;/td&gt;&lt;td&gt;8 ...&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;3 ...&lt;/td&gt;&lt;td&gt;9 ...&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;4 ...&lt;/td&gt;&lt;td&gt;10 ...&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;5 ...&lt;/td&gt;&lt;td&gt;11 ...&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;6 ...&lt;/td&gt;&lt;td&gt;12 ...&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;Not by default, certainly with some scripting or by a set of a few commands
entered manually. We also want to preserve the line continuation while
scrolling. Maybe all of that is implemented somewhere for vim, I don’t know.
First time I saw this was many years ago in computer lab, somebody using &lt;em&gt;emacs&lt;/em&gt;.
What I’m going show dates back to 2011, it works and I think there must be an
easier way or some vim fork can do it natively.&lt;/p&gt;

&lt;p&gt;The idea is to split the panel, move the lines by the screen height and enable
scrollbind.&lt;/p&gt;

&lt;div class=&quot;language-vim highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; SplitAndJoin&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;vsplit&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;wincmd&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;l&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;normal L
	&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;normal z&lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;wincmd&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;h&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;windo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;scrollbind&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;wincmd&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;h&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;endfunction&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Moving the lines is really emulated by navigating to the bottom, resetting the
position so the next line is the first one displayed. This is obviously not
resistant to resizing the terminal, the line offset between the windows is
fixed. This can be manually adjusted by disabling scrollbind, syncing the lines
and enabling scrollbind again. I think I never needed that so urgently to
implement it, reopening the buffer is faster.&lt;/p&gt;

&lt;p&gt;The function can be invoked from command line mode by&lt;/p&gt;

&lt;div class=&quot;language-vim highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; SplitAndJoin&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;splitandjoin2.png&quot;&gt;&lt;img src=&quot;splitandjoin2-small.png&quot; alt=&quot;linux Makefile split into 2 panes&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;-or-3-panes-lines-continued&quot;&gt;… or 3 panes, lines continued&lt;/h1&gt;

&lt;p&gt;If we can do 2 panes by a few simple commands, we can do more, any number of
splits that still fit the screen. This repeats the split and bind step from
the last opened pane before moving back to the first one. The scrollbind is
temporarily disabled when moving the lines for the split.&lt;/p&gt;

&lt;div class=&quot;language-vim highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; SplitAndJoin3&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;vsplit&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;wincmd&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;l&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;normal L
	&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;windo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;noscrollbind&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;normal z&lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;wincmd&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;h&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;windo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;scrollbind&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;vsplit&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;wincmd&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;l&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;normal L
	&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;windo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;noscrollbind&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;normal z&lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;wincmd&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;h&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;windo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;scrollbind&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;wincmd&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;h&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;wincmd&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;h&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;endfunction&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Which can look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;splitandjoin3.png&quot;&gt;&lt;img src=&quot;splitandjoin3-small.png&quot; alt=&quot;linux Makefile split into 3 panes&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;problems&quot;&gt;Problems&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;resize - the line offsets are fixed from the time the window is split,
resizing terminal window will get that out of sync&lt;/li&gt;
  &lt;li&gt;randomly not refreshed - sometimes the right pane does not show the right
lines, but Ctrl-L fixes that, so it’s just a visual glitch&lt;/li&gt;
  &lt;li&gt;unsynced text during and after typing - when writing new lines to the left
pane, the right pane shifts only the line numbers, not the text itself, ESC
and Ctrl-L does not fix it, only scrolling gets it back in sync with visual
appearance&lt;/li&gt;
  &lt;li&gt;wrap - with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set wrap on&lt;/code&gt; and some lines actually wrapped in the left pane,
the line offset is derived from that and once the wrapped line(s) scroll away
from the screen the lines and text get out of sync&lt;/li&gt;
  &lt;li&gt;switching files in the right pane will inherit the scrollbind, so movement
will also apply to the left window (not desired e.g. when using tags/cscope/…)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s not a short list, might be a bug somewhere like a missing refresh
after an action or it’s working as expected individually but not when
combined like that. A native support in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vim&lt;/code&gt; is needed. But, it is still
usable to some extent.&lt;/p&gt;
</description>
				<pubDate>Wed, 16 Aug 2023 00:00:00 +0200</pubDate>
				<link>https://kdave.github.io/vim-tip-split-file-lines-cont/</link>
				<guid isPermaLink="true">https://kdave.github.io/vim-tip-split-file-lines-cont/</guid>
			</item>
		
			<item>
				<title>Interactive sleep</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sleep&lt;/code&gt; utility is something I’d hardly consider worth enhancing by
features, the task is simple to sleep for a given time. Nothing else is needed
when it’s used from scripts. However, it can be also used from manually typed
command line, e.g. to let some command start later to offset initial IO load or
not to overload network.&lt;/p&gt;

&lt;p&gt;Let’s say for example that we’d like to download a big data set, but rather let
it start in 20 minutes.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sleep &lt;/span&gt;20m &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; wget https://URL
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once this command starts we don’t know how much time is remaining and
interrupting it by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctrl-C&lt;/code&gt; would not start the download. Additionally, what if
the time is too short and we’d like to increase it. So let’s implement it. For
more compatibility it’s done in shell and using only widely available utilities
(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;date&lt;/code&gt;). And btw, it does not even use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sleep&lt;/code&gt; for the sleeping but the builtin
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read&lt;/code&gt; with the timeout option as it allows to read input while waiting.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:-&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;ts&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$t&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$t&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;s&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;tm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;%*s&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$tm&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;m&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;tm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;%*m&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$tm&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;h&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;tm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;%*h&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$tm&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;d&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;tm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;%*d&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$tm&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;0-9]&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; : &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ERROR: unknown timestamp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;1&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;esac&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; :&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$t&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-le&lt;/span&gt; 0 &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;break
	read&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; 1 &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; 1 ch
	&lt;span class=&quot;nv&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$?&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 142 &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
		&lt;span class=&quot;c&quot;&gt;# timeout&lt;/span&gt;
		:
	&lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0 &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
		&lt;span class=&quot;c&quot;&gt;# keypress&lt;/span&gt;
		&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;sleep for &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$ts&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;, remaining&quot;&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TZ&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;utc &lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--date&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;@&lt;span class=&quot;nv&quot;&gt;$t&lt;/span&gt; +%H:%M:%S&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$t&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;)&quot;&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$ch&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;q&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
			&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;quit&quot;&lt;/span&gt;
			&lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;0
		&lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$ch&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;+&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
			&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;increase by 10s&quot;&lt;/span&gt;
			&lt;span class=&quot;nv&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$ch&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;-&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
			&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;decrease by 10s&quot;&lt;/span&gt;
			&lt;span class=&quot;nv&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;fi
		&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;fi
	&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The time passed on command line needs to be parsed and it does not support
fractional times, otherwise it’s straightforward. The interesting part is
that it reacts to key presses:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;q&lt;/code&gt; stop waiting, with exit code 0 so the next command could continue,
otherwise &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctrl-C&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; increase waiting time by 10 seconds and print it&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-&lt;/code&gt; decrease waiting time by 10 seconds and print it&lt;/li&gt;
  &lt;li&gt;anything else prints remaining time (and slightly increases the
waiting time due to processing)&lt;/li&gt;
&lt;/ul&gt;
</description>
				<pubDate>Thu, 24 Aug 2023 00:00:00 +0200</pubDate>
				<link>https://kdave.github.io/interactive-sleep/</link>
				<guid isPermaLink="true">https://kdave.github.io/interactive-sleep/</guid>
			</item>
		
			<item>
				<title>Linux kernel tip: build with custom CFLAGS</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;Build linux kernel, either whole or a selected directory with compiler flags,
without editing any Makefiles or such.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;linux.git
    make ccflags-y&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;-Wundef&apos;&lt;/span&gt; kernel/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Any change to flags will be detected and leads to full rebuild of all affected files.
Building whole directory must have the trailing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt;. Whole modules can be built
with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M=fs/btrfs&lt;/code&gt;, where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M=&lt;/code&gt; does not require the trailing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What to use it for&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Build test the code with different warnings&lt;/em&gt; that are not on by default.
Inspiration is in &lt;a href=&quot;https://www.man7.org/linux/man-pages/man1/gcc.1.html&quot;&gt;gcc(1) manual page&lt;/a&gt;
or in the
&lt;a href=&quot;https://gcc.gnu.org/onlinedocs/gcc/Option-Summary.html&quot;&gt;GCC Option Summary&lt;/a&gt;. 
Linux provides sets of predefined warning level with increasing verbosity and
decreasing usefulness, see file &lt;a href=&quot;https://elixir.bootlin.com/linux/latest/source/scripts/Makefile.extrawarn&quot;&gt;scripts/Makefile.extrawarn&lt;/a&gt;.
The levels can be enabled on command line like&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    make &lt;span class=&quot;nv&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1 kernel/
    make &lt;span class=&quot;nv&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;12 kernel/
    make &lt;span class=&quot;nv&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;2 kernel/
    make &lt;span class=&quot;nv&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;3 kernel/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This could be quite noisy so it’s better to capture that to a file and postprocess.&lt;/p&gt;

&lt;p&gt;Capture other information during build, like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-fstack-usage&lt;/code&gt; (consumption of
stack by functions, in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.su&lt;/code&gt;) or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-save-temps=obj&lt;/code&gt; (save generated assembly &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.s&lt;/code&gt; and
preprocessed sources &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.i&lt;/code&gt;).&lt;/p&gt;
</description>
				<pubDate>Wed, 20 Nov 2024 00:00:00 +0100</pubDate>
				<link>https://kdave.github.io/lkt-build-with-flags/</link>
				<guid isPermaLink="true">https://kdave.github.io/lkt-build-with-flags/</guid>
			</item>
		
			<item>
				<title>Atomic cross-rename of two paths</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;Since version v3.15 linux supports a file operation that will exchange any two
directory entries atomically. This needs support of the filesystem so it’s not
universal, but the commonly used filesystems can do it.&lt;/p&gt;

&lt;p&gt;The underlying syscall is &lt;a href=&quot;https://www.man7.org/linux/man-pages/man2/rename.2.html&quot;&gt;renameat2&lt;/a&gt;.
Obligatory &lt;a href=&quot;https://lwn.net/Articles/569134/&quot;&gt;LWN article&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#define _GNU_SOURCE
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;fcntl.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;renameat2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;olddirfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;oldpath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newdirfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;newpath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The magic is in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;flags&lt;/code&gt; being set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RENAME_EXCHANGE&lt;/code&gt;, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oldpath&lt;/code&gt; and
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;newpath&lt;/code&gt; are simply the names (can be relative or full path), with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AT_FDCWD&lt;/code&gt;
for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oldfddir&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;newfddir&lt;/code&gt; unless you need to something fancy. See below for
standalone working implementations in several languages. The minimal and
stripped down example:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#define _GNU_SOURCE
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;fcntl.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;renameat2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AT_FDCWD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ATD_FDCWD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RENAME_EXCHANGE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The full example below does proper checking of arguments and existence of the files
but the syscall does that by itself too. Obviously both directory entries need
to exist at the time the rename action is performed, otherwise it would be
&lt;a href=&quot;https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use&quot;&gt;TOCTOU&lt;/a&gt; bug.&lt;/p&gt;

&lt;p&gt;What is a directory entry and where it works:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;regular file&lt;/li&gt;
  &lt;li&gt;special file (socket, named pipe, …)&lt;/li&gt;
  &lt;li&gt;directory&lt;/li&gt;
  &lt;li&gt;symlink (the path is not resolved, so the target remains the same)&lt;/li&gt;
  &lt;li&gt;hardlink (it’s just another name of a file)&lt;/li&gt;
  &lt;li&gt;subvolume (on Btrfs)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each type can be the source and target, in any combination:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;touch &lt;/span&gt;file
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkfifo &lt;/span&gt;fifo
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir dir&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; file symlink
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ln &lt;/span&gt;file hardlink
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;btrfs subvol create subvol
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-lis&lt;/span&gt;
total 16
123323316 0 drwxr-xr-x 1 user &lt;span class=&quot;nb&quot;&gt;users    &lt;/span&gt;0 Nov 21 14:35 &lt;span class=&quot;nb&quot;&gt;dir
&lt;/span&gt;123323315 0 prw-r--r-- 1 user &lt;span class=&quot;nb&quot;&gt;users    &lt;/span&gt;0 Nov 21 14:35 fifo
123323314 0 &lt;span class=&quot;nt&quot;&gt;-rw-r--r--&lt;/span&gt; 2 user &lt;span class=&quot;nb&quot;&gt;users    &lt;/span&gt;0 Nov 21 14:35 file
123323314 0 &lt;span class=&quot;nt&quot;&gt;-rw-r--r--&lt;/span&gt; 2 user &lt;span class=&quot;nb&quot;&gt;users    &lt;/span&gt;0 Nov 21 14:35 hardlink
      256 0 drwxr-xr-x 1 user &lt;span class=&quot;nb&quot;&gt;users    &lt;/span&gt;0 Nov 21 14:35 subvol
123323317 4 lrwxrwxrwx 1 user &lt;span class=&quot;nb&quot;&gt;users    &lt;/span&gt;4 Nov 21 14:35 symlink -&amp;gt; file

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mvx &lt;span class=&quot;nb&quot;&gt;dir &lt;/span&gt;file
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mvx fifo subvol
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mvx symlink hardlink
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-lis&lt;/span&gt;
123323314 0 &lt;span class=&quot;nt&quot;&gt;-rw-r--r--&lt;/span&gt; 2 user &lt;span class=&quot;nb&quot;&gt;users    &lt;/span&gt;0 Nov 21 14:35 &lt;span class=&quot;nb&quot;&gt;dir
      &lt;/span&gt;256 0 drwxr-xr-x 1 user &lt;span class=&quot;nb&quot;&gt;users    &lt;/span&gt;0 Nov 21 14:35 fifo
123323316 0 drwxr-xr-x 1 user &lt;span class=&quot;nb&quot;&gt;users    &lt;/span&gt;0 Nov 21 14:35 file
123323317 4 lrwxrwxrwx 1 user &lt;span class=&quot;nb&quot;&gt;users    &lt;/span&gt;4 Nov 21 14:35 hardlink -&amp;gt; file
123323315 0 prw-r--r-- 1 user &lt;span class=&quot;nb&quot;&gt;users    &lt;/span&gt;0 Nov 21 14:35 subvol
123323314 0 &lt;span class=&quot;nt&quot;&gt;-rw-r--r--&lt;/span&gt; 2 user &lt;span class=&quot;nb&quot;&gt;users    &lt;/span&gt;0 Nov 21 14:35 symlink
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Below are implementations in some other languages using direct interfaces to
the syscalls, I haven’t found standard libraries providing the extended syntax.
Same as there’s missing support in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mv&lt;/code&gt; utility. Welp, after 10 years.&lt;/p&gt;

&lt;h1 id=&quot;c&quot;&gt;C&lt;/h1&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#define _GNU_SOURCE
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;fcntl.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;sys/stat.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/*
 * Cross-rename of two paths: file, directory, symlink (not the target),
 * also subvolumes (on btrfs)
 *
 * Example:
 *
 *    file - a file
 *    dir  - a directory
 *
 *    $ mvx file dir
 *
 *    file - a directory named &apos;file&apos;
 *    dir  - a file named &apos;dir&apos;
 *
 * Q: Should this be implemented by mv?
 * A: Yes.
 */&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stat&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;st&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;fprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stderr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Usage: mvx path1 path2&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;st&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;fprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stderr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;stat: failed for %s: %m&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;st&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;fprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stderr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;stat: failed for %s: %m&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;renameat2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AT_FDCWD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AT_FDCWD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RENAME_EXCHANGE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;fprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stderr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;renameat2: failed with %m&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;python&quot;&gt;Python&lt;/h1&gt;

&lt;p&gt;I found project &lt;a href=&quot;https://github.com/jordemort/python-renameat2&quot;&gt;python-renameat2&lt;/a&gt; implementing
that as a proper module
(&lt;a href=&quot;https://python-renameat2.readthedocs.io/en/latest/examples.html#atomically-swap-two-files&quot;&gt;example&lt;/a&gt;).
Otherwise you can use this:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctypes&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;libc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctypes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;CDLL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;libc.so.6&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;libc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;renameat2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argtypes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctypes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctypes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_char_p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctypes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctypes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_char_p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctypes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_uint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;libc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;renameat2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;restype&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctypes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_int&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;AT_FDCWD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;RENAME_EXCHANGE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;path1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;path2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;libc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;renameat2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AT_FDCWD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AT_FDCWD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RENAME_EXCHANGE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;perl&quot;&gt;Perl&lt;/h1&gt;

&lt;div class=&quot;language-perl highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;strict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;warnings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;syscall.ph&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&quot;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$path1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$path2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;@ARGV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$AT_FDCWD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$RENAME_EXCHANGE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;syscall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;&amp;amp;SYS_renameat2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$AT_FDCWD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$path1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$AT_FDCWD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$path2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$RENAME_EXCHANGE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
				<pubDate>Wed, 27 Nov 2024 00:00:00 +0100</pubDate>
				<link>https://kdave.github.io/atomic-cross-rename/</link>
				<guid isPermaLink="true">https://kdave.github.io/atomic-cross-rename/</guid>
			</item>
		
			<item>
				<title>Self Makefile and C source</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;I’ve seen this trick long time ago, one file that’s a C source and also usable as
it’s own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt;, also known as
&lt;a href=&quot;https://en.wikipedia.org/wiki/Polyglot_%28computing%29&quot;&gt;polyglot code&lt;/a&gt;.
While the polyglot has probably little use in practice, the combination with
build system can be handy, to distribute a single file. Build instructions can
be of course in a comment in the file.&lt;/p&gt;

&lt;p&gt;Let’s see a minimal example:&lt;/p&gt;

&lt;p&gt;Source:&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hello world!&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Makefile:&lt;/p&gt;
&lt;div class=&quot;language-make highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;CFLAGS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-Wall&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;hello.c&lt;/span&gt;
	gcc &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$&amp;lt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;$(&lt;/span&gt;CFLAGS&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Combined (syntax highlighting for C):&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#if 0
CFLAGS=-Wall
hello: hello.c
	gcc -o $@ $&amp;lt; $(CFLAGS)
ifdef false
#else&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hello world!&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#endif
&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;#if 0
endif
#endif
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Combined (syntax highlighting for Makefile):&lt;/p&gt;
&lt;div class=&quot;language-make highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#if 0
&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CFLAGS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-Wall&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;hello.c&lt;/span&gt;
	gcc &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$&amp;lt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;$(&lt;/span&gt;CFLAGS&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#else
#include &amp;lt;stdio.h&amp;gt;
&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;main()&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;err&quot;&gt;printf(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Hello world!\n&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;err&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;0;&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#endif
#if 0
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;endif&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#endif
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There’s still a problem that the embedded C code in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ifdef false&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;endif&lt;/code&gt; is
parsed by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt;, a standalone &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ifdef&lt;/code&gt; in the middle of the C code will
terminate the supposedly skipped part. I’ve tried to confuse make more but it
seems to be quite tolerant to various syntax hacks, like defining a C function
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$&lt;/code&gt; and emulating some built-in function calls.&lt;/p&gt;

&lt;p&gt;How it all works is straightforward and depends on source level compatibility
of comments and code. The C preprocessor directives are comments for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt; so
they hide the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt; directives from compiler.&lt;/p&gt;
</description>
				<pubDate>Wed, 04 Dec 2024 00:00:00 +0100</pubDate>
				<link>https://kdave.github.io/self-makefile/</link>
				<guid isPermaLink="true">https://kdave.github.io/self-makefile/</guid>
			</item>
		
			<item>
				<title>Python auto increment variables</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;Although everybody knows the python language does not provide the unary
increment/decrement operators, I’d still like to use that for some specific
cases. Let’s explore an unconventional way how to do that.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.python.org/3/library/operator.html&quot;&gt;Python operator overview&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://stackoverflow.com/questions/1485841/behaviour-of-increment-and-decrement-operators-in-python&quot;&gt;Stackoverflow &lt;em&gt;Increment and decrement operator question&lt;/em&gt;&lt;/a&gt;
provides some insights why &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;++x&lt;/code&gt; works but does not do what one expects.
This is parsed as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+(+(x))&lt;/code&gt;. The question is now 15 years old and everybody
moved on. The unary &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; operator is an identity.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Side quest: what does unary &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; do in C?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s start with a quiz: &lt;em&gt;what could be the following class useful for?&lt;/em&gt;&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__call__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__int__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__str__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__pos__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__neg__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Auto sequence is sometimes useful. Why? I’ve used this in GUI programming, when
dumping tabular data with custom formatting. If you write your software
correctly on the first time, congratulations. I may not and resort to
incremental development that requires lots of editing. An example in pseudo
code for Tcl/Tk application that fills rows of a grid layout in a sequence.&lt;/p&gt;

&lt;div class=&quot;language-tcl highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;widget1.grid&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;row=0, column=0&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
widget2.grid&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;row=1, column=0&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
widget3.grid&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;row=2, column=0&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
widget4.grid&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;row=3, column=0&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
widget5.grid&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;row=4, column=0&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The layout many need to be tuned so lines are swapped, reordered, then save,
run, check and repeat until satisfied. In C++ and using e.g. Qt I’d do
something like:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;widget3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;grid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;widget2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;grid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;widget5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;grid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;widget1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;grid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;widget4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;grid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In any way I swap the lines, they’ll be always in the order as they’re in the
source file and I don’t have to renumber the rows each time I need to save and
run it. I could turn it to a fixed number sequence once I’m done with the
tuning. Expecting future changes I would leave it as is, extending that in the
future would be much easier.&lt;/p&gt;

&lt;p&gt;But python religiously does not offer the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;++&lt;/code&gt; operators, neither pre-increment
nor post-increment. OTOH python offers other tuning methods that could be
hidden on the class level and &lt;del&gt;abused&lt;/del&gt;utilized as pure syntax repurposing.&lt;/p&gt;

&lt;p&gt;Using the class from above, the python version can be rewritten like this, with
the reordered lines:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;widget3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;grid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;column&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;widget2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;grid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;column&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;widget5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;grid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;column&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;widget1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;grid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;column&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;widget4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;grid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;column&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; operator &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pos&lt;/code&gt;, unary and returning the positive size of the value.
Overloading that to increment the value is at least a bit intuitive even for a
casual reader not familiar with the class &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As a discouragement the following works (python code):&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and (as implemented) increments &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt;, just once. But no surprise or magic
here, standard python accepts this for any integer value. This will be first
evaluated as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+x&lt;/code&gt; and then the unary &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; applied on the result, as said before
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+(+x)&lt;/code&gt; so the leading &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; does not involve &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt;. We can go crazy:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;+++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;++++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;+++++++++++++++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;All of them do single post-increment. In standard python this works for
integer-like objects too:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;+++&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;++++&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is evaluated as 1. Actually we can go crazy even more, because the unary
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; can be mixed freely:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;-+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;+-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;-+-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;+-+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;-+-+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;+-+-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And so on. I’ll leave that as an exercise what the final value of each line
is.  This also works in C, but I digress.&lt;/p&gt;

&lt;p&gt;What I find really bad is that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;++x&lt;/code&gt; does not match the pre-increment semantics
but given the limitations of the operator overloading we can’t do anything
about that.&lt;/p&gt;

&lt;p&gt;With a minor update the class &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X&lt;/code&gt;, the bare value of such object instance
can be used in expressions like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x+1&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x-1&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__add__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__sub__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and similar for the remaining integer operators. This is non-standard
extension best to be used within limited scope.&lt;/p&gt;

&lt;p&gt;Heresy.&lt;/p&gt;
</description>
				<pubDate>Tue, 10 Dec 2024 00:00:00 +0100</pubDate>
				<link>https://kdave.github.io/python-auto-increment/</link>
				<guid isPermaLink="true">https://kdave.github.io/python-auto-increment/</guid>
			</item>
		
			<item>
				<title>Case study: link C++ standalone executable to another C executable (ntfs2btrfs to btrfs-convert)</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;&lt;em&gt;Problem statement&lt;/em&gt;: there’s a tool written in C, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;btrfs-convert&lt;/code&gt;, that
implements conversion from one filesystem to btrfs. For ext2/3/4 and reiserfs
this is done using existing C libraries. There’s a standalone project
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ntfs2btrfs&lt;/code&gt; written in C++, not providing a library interface at all, but the
equivalent functionality.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The question&lt;/em&gt;: can the functionality of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ntfs2btrfs&lt;/code&gt; be provided by
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;btrfs-convert&lt;/code&gt; while minimizing the difficulty of the integration? Ideally
automated with only a few necessary fix-ups.&lt;/p&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#inputs&quot; id=&quot;markdown-toc-inputs&quot;&gt;Inputs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#initial-problems&quot; id=&quot;markdown-toc-initial-problems&quot;&gt;Initial problems&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#solution-outline&quot; id=&quot;markdown-toc-solution-outline&quot;&gt;Solution outline&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#create-the-entry-point&quot; id=&quot;markdown-toc-create-the-entry-point&quot;&gt;Create the entry point&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#what-about-the-two-mains&quot; id=&quot;markdown-toc-what-about-the-two-mains&quot;&gt;What about the two main()s&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#final-link&quot; id=&quot;markdown-toc-final-link&quot;&gt;Final link&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;inputs&quot;&gt;Inputs&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/kdave/btrfs-progs.git&quot;&gt;&lt;strong&gt;btrfs-progs.git&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;primary build system and target&lt;/li&gt;
  &lt;li&gt;C sources&lt;/li&gt;
  &lt;li&gt;autoconf, make&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/maharmstone/ntfs2btrfs&quot;&gt;&lt;strong&gt;ntfs2btrfs.git&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;C++ sources&lt;/li&gt;
  &lt;li&gt;cmake&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What can certainly be done is to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git clone&lt;/code&gt; the sources, run their respective
configure and build steps and get lots of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.o&lt;/code&gt; files.&lt;/p&gt;

&lt;h1 id=&quot;initial-problems&quot;&gt;Initial problems&lt;/h1&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ntfs2btrfs&lt;/code&gt; conversion tool is in a different repository, git submodules
are not an option so this needs to be cloned and pulled at the time
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;btrfs-convert&lt;/code&gt; is built.&lt;/p&gt;

&lt;p&gt;The other build system should be ideally run without any additional hurdles,
so we can assume it’s in a known separate directory and produces the object files
we’ll use later. But this also builds a standalone executable, so there’s
a symbol &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; defined, which will collide with the one defined by the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;btrfs-convert&lt;/code&gt; sources.&lt;/p&gt;

&lt;p&gt;The language difference is not that significant but in the glue interface
we need to handle potential name mangling or other symbol duplication.&lt;/p&gt;

&lt;p&gt;There are duplicate implementations of low-level functions like checksumming.
The estimated size is tens of kilobytes, so we won’t mind that as long as
the linker is able to resolve everything.&lt;/p&gt;

&lt;h1 id=&quot;solution-outline&quot;&gt;Solution outline&lt;/h1&gt;

&lt;p&gt;To integrate the projects the steps will be in a script that will basically:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;clone the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ntfs2btrfs.git&lt;/code&gt; repository&lt;/li&gt;
  &lt;li&gt;configure it and build with some sane options (preferring maximum compatibility)&lt;/li&gt;
  &lt;li&gt;grab the resulting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.o&lt;/code&gt; files&lt;/li&gt;
  &lt;li&gt;link &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;btrfs-convert&lt;/code&gt; and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.o&lt;/code&gt; files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last point can be tricky and the missing part is how to hand over
the functionality.&lt;/p&gt;

&lt;h1 id=&quot;create-the-entry-point&quot;&gt;Create the entry point&lt;/h1&gt;

&lt;p&gt;The entry point of the standalone &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ntfs2btrfs&lt;/code&gt; utility is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; so we need
to inject a public function that will not be a mangled as symbol, export
it in a header and use it from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;btrfs-convert&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Also we may need to translate the user options set as command line options.
They’ll be parsed in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ntfs2btrfs&lt;/code&gt; project and passed as parameters to the
glue function and mapped to the conversion options if possible. There’s some
feature mismatch so this is not 1:1.&lt;/p&gt;

&lt;p&gt;Minimal glue function (:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;C&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;convert_entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fn_c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;btrfs_compression&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;btrfs_csum_type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;csum_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nocsum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

                &lt;span class=&quot;n&quot;&gt;csum_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;btrfs_csum_type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;crc32c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;compression&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;btrfs_compression&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;none&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

                &lt;span class=&quot;n&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fn_c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;ntfs&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dev&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

                &lt;span class=&quot;n&quot;&gt;convert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dev&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;csum_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nocsum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This can be appended/included to the main file so it lives in the scope of the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ntfs2btrfs&lt;/code&gt; where its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main()&lt;/code&gt; is, so we have access to the translation unit
static and global variables (that can store the representation of the command
line options).&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;#include &quot;convert-entry.c&quot;&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ntfs2btrfs.git/src/ntfs2btrfs.cpp&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Symbol name mangling is avoided by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extern &quot;C&quot;&lt;/code&gt;, otherwise the parameters are
set to defaults for simplicity. The path of the file/device must be translated
to a C++ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string&lt;/code&gt; but this happens inside the glue function, no
interoperability problems. After creation of the filesystem object &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ntfs&lt;/code&gt; we
can finally hand control to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;convert()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There are some assumptions. The conversion detects the NTFS signature and does
other validation of the image as we’ll call that from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;btrfs-convert&lt;/code&gt;
unconditionally.&lt;/p&gt;

&lt;h1 id=&quot;what-about-the-two-mains&quot;&gt;What about the two main()s&lt;/h1&gt;

&lt;p&gt;Actually this is not hard at all. Linkage is done by comparing plain string
representations, so we’ll just edit it as needed. The colliding symbol name is
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; so let’s rename it to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MAIN&lt;/code&gt;. This is a standard symbol in C++ that’s not
mangled so we can simply find in the right &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.o&lt;/code&gt; file and change it. We can
use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sed&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;nm build/.../ntfs2btrfs.o | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;main
00000000000140ed T main
...
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;s/main/MAIN/&apos;&lt;/span&gt; build/.../ntfs2btrfs.o
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;nm build/.../ntfs2btrfs.o | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;MAIN
00000000000140ed T MAIN
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is crude and renames several other symbols like lambdas and templates of
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::basic_string&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;00000000000174c9 t
std::__cxx11::basic_string&amp;lt;MAIN::{lambda()#1}::operator()()
const::FMT_COMPILE_STRING::char_type, ...&lt;/code&gt;). I haven’t found a standard utility
to that so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sed&lt;/code&gt; it is, fortunately there’s no other string &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; in the
binary e.g. in an error message.&lt;/p&gt;

&lt;h1 id=&quot;final-link&quot;&gt;Final link&lt;/h1&gt;

&lt;p&gt;No remaining problems, we have a bunch of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.o&lt;/code&gt; files, no conflicting symbol
names, one executable entry point &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; and one final binary. So we now can
link &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;btrfs-convert&lt;/code&gt; with all the other objects. This is basic makefile
integration, not that interesting, also some conditional build support in the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;btrfs-convert&lt;/code&gt; sources. With everything in place&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./btrfs-convert &lt;span class=&quot;nt&quot;&gt;--help&lt;/span&gt;
...
    Supported filesystems:
        ext2/3/4: &lt;span class=&quot;nb&quot;&gt;yes
        &lt;/span&gt;reiserfs: no
        ntfs: &lt;span class=&quot;nb&quot;&gt;yes&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mkfs.ntfs /dev/sdx
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./btrfs-convert /dev/sdx
btrfs-convert from btrfs-progs v6.12
...
Using CRC32C &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;checksums.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And the last question: &lt;em&gt;does anybody what that?&lt;/em&gt;&lt;/p&gt;
</description>
				<pubDate>Wed, 18 Dec 2024 00:00:00 +0100</pubDate>
				<link>https://kdave.github.io/ntfs-btrfs-progs-link-integration/</link>
				<guid isPermaLink="true">https://kdave.github.io/ntfs-btrfs-progs-link-integration/</guid>
			</item>
		
			<item>
				<title>Update: Atomic cross-rename of two paths (mv --exchange, exch)</title>
				<dc:creator>kdave</dc:creator>
				<description>&lt;p&gt;I did not notice that the cross rename already existed &lt;a href=&quot;/atomic-cross-rename/&quot;&gt;when I was writing about
it&lt;/a&gt; but it’s been there since &lt;a href=&quot;https://lists.gnu.org/archive/html/info-gnu/2024-03/msg00006.html&quot;&gt;coreutils v9.5&lt;/a&gt;
released in Mar 2024.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mv&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--exchange&lt;/span&gt; file1 file2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And it also landed in &lt;a href=&quot;https://github.com/util-linux/util-linux/blob/master/Documentation/releases/v2.40-ReleaseNotes&quot;&gt;util-linux v2.40&lt;/a&gt;
at about the same time as utility &lt;a href=&quot;https://www.man7.org/linux/man-pages/man1/exch.1.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exch&lt;/code&gt;&lt;/a&gt;
(added in &lt;a href=&quot;https://github.com/util-linux/util-linux/commit/cd094a05880cf1132762c5f9724c0945557c7638&quot;&gt;commit cd094a05880c&lt;/a&gt;):&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;exch file1 file2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The two projects have an overlap in what they provide so the journey of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mv
--exchange&lt;/code&gt; took a few turns:&lt;/p&gt;

&lt;p&gt;From &lt;a href=&quot;https://github.com/coreutils/coreutils&quot;&gt;coreutils git&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;2024-02-29 &lt;a href=&quot;https://github.com/coreutils/coreutils/commit/6cd2d5e5335b5c286ff39e154e9dd38ba6923775&quot;&gt;6cd2d5e5335b &lt;em&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mv: add --swap (-x) option to atomically swap 2 paths&lt;/code&gt;&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;2024-03-05 &lt;a href=&quot;https://github.com/coreutils/coreutils/commit/9d8890d87231d477ca78269a4fce9242ec0624f1&quot;&gt;9d8890d87231 &lt;em&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mv: revert add --swap (-x) option&lt;/code&gt;&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;2024-03-20 &lt;a href=&quot;https://github.com/coreutils/coreutils/commit/5d3fd24f4286d422482dd1697c9fe1bfa30f608e&quot;&gt;5d3fd24f4286 &lt;em&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mv: new option --exchange&lt;/code&gt;&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Good that the feature is provided in standard tools but unfortunately none of
them comes with a decent description of the capabilities and limitations.  All
types of files, directories (including subvolumes) could be exchanged but only
on the same filesystem, otherwise it returns the error &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EXDEV&lt;/code&gt; &lt;em&gt;Invalid cross-device link&lt;/em&gt;.&lt;/p&gt;
</description>
				<pubDate>Sat, 11 Jan 2025 00:00:00 +0100</pubDate>
				<link>https://kdave.github.io/atomic-cross-rename-update/</link>
				<guid isPermaLink="true">https://kdave.github.io/atomic-cross-rename-update/</guid>
			</item>
		
	</channel>
</rs