<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Crush on inetshell</title><link>https://inet.sh/en/tags/crush/</link><description>Recent content in Crush on inetshell</description><generator>Hugo</generator><language>en</language><lastBuildDate>Fri, 25 Sep 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://inet.sh/en/tags/crush/index.xml" rel="self" type="application/rss+xml"/><item><title>Ceph on Proxmox: device classes and CRUSH rules to keep SAS, SSD and NVMe apart</title><link>https://inet.sh/en/posts/proxmox/ceph-device-classes-crush-rules/</link><pubDate>Fri, 25 Sep 2026 00:00:00 +0000</pubDate><guid>https://inet.sh/en/posts/proxmox/ceph-device-classes-crush-rules/</guid><description>How to make a Ceph pool on Proxmox VE use only one kind of disk: assign device classes to OSDs (set-device-class, with rm-device-class first if they already had one), create a replicated CRUSH rule per class and point the pool at that rule with pveceph or ceph osd pool set. Includes custom classes such as sas.</description><content:encoded><![CDATA[<h2 id="tldr">TL;DR</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># 1. OSD class. If it already has one (automatic hdd/ssd/nvme), remove it first: Ceph will not overwrite it</span>
</span></span><span class="line"><span class="cl">ceph osd crush rm-device-class osd.5
</span></span><span class="line"><span class="cl">ceph osd crush set-device-class sas osd.5
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 2. Rule that only places data on that class (root &#34;default&#34;, failure domain &#34;host&#34;)</span>
</span></span><span class="line"><span class="cl">ceph osd crush rule create-replicated replicated_sas default host sas
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 3. New pool on the rule, registered as Proxmox storage</span>
</span></span><span class="line"><span class="cl">pveceph pool create vm-sas --crush_rule replicated_sas --add_storages <span class="m">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ...or move an existing pool (rebalances all of its data)</span>
</span></span><span class="line"><span class="cl">pveceph pool <span class="nb">set</span> vm-fast --crush_rule replicated_sas
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="why">Why</h2>
<p>Ceph&rsquo;s default rule (<code>replicated_rule</code>) spreads objects across <strong>all</strong> OSDs without looking at the disk underneath. In a mixed cluster that means the &ldquo;fast&rdquo; pool also lands on the slow disks and performs like the worst of them.</p>
<p>Since Luminous every OSD carries a <strong>device class</strong>. Ceph detects it on its own at startup (<code>hdd</code>, <code>ssd</code>, or <code>nvme</code>) and a CRUSH rule can be restricted to one class: internally it builds a shadow hierarchy (<code>default~sas</code>) with only those OSDs and places the whole pool there. The class is a free label: besides the automatic ones you can use <code>sas</code>, <code>sata</code>, <code>archive</code>, or whatever helps you separate.</p>
<h2 id="checking-the-state">Checking the state</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">ceph osd tree                        <span class="c1"># CLASS column per OSD</span>
</span></span><span class="line"><span class="cl">ceph osd crush class ls              <span class="c1"># existing classes</span>
</span></span><span class="line"><span class="cl">ceph osd crush class ls-osd sas      <span class="c1"># OSDs in a class</span>
</span></span><span class="line"><span class="cl">ceph osd crush tree --show-shadow    <span class="c1"># the default~&lt;class&gt; shadow hierarchies</span>
</span></span><span class="line"><span class="cl">ceph osd crush rule ls
</span></span><span class="line"><span class="cl">ceph osd crush rule dump replicated_sas
</span></span><span class="line"><span class="cl">ceph osd pool ls detail              <span class="c1"># crush_rule &lt;id&gt; of each pool</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="changing-an-osds-class">Changing an OSD&rsquo;s class</h2>
<p>If the OSD already has a class, <code>set-device-class</code> does not overwrite it:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Error EBUSY: osd.5 has already bound to class &#39;hdd&#39;, can not reset class to &#39;sas&#39;;
</span></span><span class="line"><span class="cl">use &#39;ceph osd crush rm-device-class &lt;id&gt;&#39; to remove old class first
</span></span></code></pre></td></tr></table>
</div>
</div><p>Hence the <code>rm-device-class</code> first. Several OSDs at once:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">ceph osd crush rm-device-class osd.5 osd.6 osd.7
</span></span><span class="line"><span class="cl">ceph osd crush set-device-class sas osd.5 osd.6 osd.7
</span></span></code></pre></td></tr></table>
</div>
</div><p>There is no &ldquo;create the class&rdquo; step: the <code>ceph osd crush class create</code> from the early Luminous builds was removed, and the class appears with the first OSD that gets it. To rename it cluster-wide, <code>ceph osd crush class rename sas sas-10k</code>.</p>
<p>A manually assigned class <strong>survives OSD restarts</strong>: on startup the OSD tries to set its automatic class and gets the same <code>EBUSY</code>. If you would rather have new OSDs come up with no class so you assign it yourself, <code>ceph config set osd osd_class_update_on_start false</code>; the price is that no new OSD gets an automatic class.</p>
<h2 id="the-rule">The rule</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">ceph osd crush rule create-replicated &lt;name&gt; &lt;root&gt; &lt;failure-domain&gt; &lt;class&gt;
</span></span><span class="line"><span class="cl">ceph osd crush rule create-replicated replicated_sas default host sas
</span></span><span class="line"><span class="cl">ceph osd crush rule create-replicated replicated_nvme default host nvme
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li><code>root</code> is <code>default</code> unless you built your own CRUSH tree.</li>
<li><code>host</code> as the failure domain puts each replica on a different node. With <code>size 3</code> you need <strong>at least three nodes</strong> with OSDs of that class, or the PGs stay <code>undersized</code>.</li>
<li>For erasure-coded pools the class goes into the profile: <code>pveceph pool create ec-sas --erasure-coding k=4,m=2,device-class=sas</code>.</li>
</ul>
<h2 id="the-pool">The pool</h2>
<p>New, with the Proxmox storage included:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">pveceph pool create vm-sas --crush_rule replicated_sas --size <span class="m">3</span> --min_size <span class="m">2</span> --add_storages <span class="m">1</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Existing: <code>pveceph pool set vm-fast --crush_rule replicated_sas</code>, or in the GUI <strong>Ceph → Pools → Edit → Crush Rule</strong>. It is the same as <code>ceph osd pool set vm-fast crush_rule replicated_sas</code>. The change triggers a <strong>backfill of the whole pool</strong> onto the class&rsquo;s OSDs; do it in a maintenance window and follow it with <code>ceph -s</code>.</p>
<h2 id="traps">Traps</h2>
<ul>
<li><strong>Count the OSDs before the rule.</strong> Three nodes, <code>size 3</code>, and only two with <code>sas</code> disks: the pool never reaches <code>active+clean</code>.</li>
<li><strong>Automatic classes get it wrong</strong> with RAID/HBA controllers that present SSDs as rotational. Check <code>ceph osd tree</code> after adding disks and correct with <code>rm-device-class</code> + <code>set-device-class</code>.</li>
<li><strong>Moving a big pool to another rule moves all of its data.</strong> Raise <code>osd_max_backfills</code> only if you know what you are doing; it is slow by default on purpose.</li>
<li><strong>Deleting a pool that refuses to go</strong>: <code>pveceph pool destroy &lt;pool&gt; --force --remove_storages</code> (the data goes with it).</li>
</ul>
<h2 id="see-also">See also</h2>
<ul>
<li><a href="/en/posts/proxmox/ceph-crash-archive-orphaned-rbd/">Ceph on Proxmox: crashes and orphaned disks</a></li>
<li><a href="/en/posts/proxmox/no-subscription-repos/">No-subscription repositories</a> — includes the Ceph repo</li>
<li>Ceph documentation: <a href="https://docs.ceph.com/en/latest/rados/operations/crush-map/#device-classes">CRUSH Maps — Device classes</a></li>
</ul>
]]></content:encoded></item></channel></rss>