<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.osnexus.com/index.php?action=history&amp;feed=atom&amp;title=Multi-protocol_File_Locking</id>
	<title>Multi-protocol File Locking - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.osnexus.com/index.php?action=history&amp;feed=atom&amp;title=Multi-protocol_File_Locking"/>
	<link rel="alternate" type="text/html" href="https://wiki.osnexus.com/index.php?title=Multi-protocol_File_Locking&amp;action=history"/>
	<updated>2026-10-03T04:13:55Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.42.1</generator>
	<entry>
		<id>https://wiki.osnexus.com/index.php?title=Multi-protocol_File_Locking&amp;diff=28118&amp;oldid=prev</id>
		<title>Qadmin: New page: NFS+SMB cross-protocol lock coherence, Disable Oplocks recommendation, verified results, limits and HA failover behaviour</title>
		<link rel="alternate" type="text/html" href="https://wiki.osnexus.com/index.php?title=Multi-protocol_File_Locking&amp;diff=28118&amp;oldid=prev"/>
		<updated>2026-09-24T03:11:56Z</updated>

		<summary type="html">&lt;p&gt;New page: NFS+SMB cross-protocol lock coherence, Disable Oplocks recommendation, verified results, limits and HA failover behaviour&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;[[Category:admin_guide]]&lt;br /&gt;
&lt;br /&gt;
This page covers file locking on a [[Network Shares|Network Share]] that NFS and SMB clients use at the same time: what each protocol provides, why the default share configuration does not keep NFS and SMB locks coherent with each other, the one setting that does, the limits measured on a scale-up pool, and what happens to locks during an HA failover.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Section !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| [[#Summary|Summary]] || What is coherent in each configuration, at a glance&lt;br /&gt;
|-&lt;br /&gt;
| [[#How each protocol locks|How each protocol locks]] || NFS and SMB locking, and where each one keeps its state&lt;br /&gt;
|-&lt;br /&gt;
| [[#Why the default configuration is not coherent across protocols|Why the default configuration is not coherent across protocols]] || SMB leases, client-side lock caching, and what goes wrong&lt;br /&gt;
|-&lt;br /&gt;
| [[#Configuring a share for NFS and SMB access|Configuring a share for NFS and SMB access]] || The Disable Oplocks setting, from the WUI and the CLI&lt;br /&gt;
|-&lt;br /&gt;
| [[#Verified behaviour|Verified behaviour]] || The lock conflict matrix and the concurrent-writer results&lt;br /&gt;
|-&lt;br /&gt;
| [[#Limits|Limits]] || Lock rates and lock counts measured on a scale-up pool&lt;br /&gt;
|-&lt;br /&gt;
| [[#Locks and HA failover|Locks and HA failover]] || Why held locks do not survive a pool failover&lt;br /&gt;
|-&lt;br /&gt;
| [[#Checking lock state on the appliance|Checking lock state on the appliance]] || Seeing which locks and leases the server actually holds&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
Byte-range locking works within each protocol on every share: an NFS client&amp;#039;s lock blocks other NFS clients, and an SMB client&amp;#039;s lock blocks other SMB clients. Locking &amp;#039;&amp;#039;&amp;#039;across&amp;#039;&amp;#039;&amp;#039; the two protocols -- an NFS client and an SMB client locking the same file -- is only coherent when oplocks are disabled on the share.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Share configuration !! NFS vs NFS !! SMB vs SMB !! NFS vs SMB !! SMB reads see NFS writes !! Locks survive HA failover&lt;br /&gt;
|-&lt;br /&gt;
| Default (oplocks on) || Yes || Yes || &amp;#039;&amp;#039;&amp;#039;No&amp;#039;&amp;#039;&amp;#039; || &amp;#039;&amp;#039;&amp;#039;No&amp;#039;&amp;#039;&amp;#039; -- an SMB client can keep serving cached data || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;#039;&amp;#039;&amp;#039;Disable Oplocks&amp;#039;&amp;#039;&amp;#039; ticked || Yes || Yes || Yes || Yes || No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;If a share is accessed over both NFS and SMB, and any application relies on locking or on seeing the other protocol&amp;#039;s writes promptly, tick Disable Oplocks on that share.&amp;#039;&amp;#039;&amp;#039; Shares used by one protocol only do not need it and are faster without it.&lt;br /&gt;
&lt;br /&gt;
== How each protocol locks ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Protocol !! Locking mechanism !! Where the server keeps it&lt;br /&gt;
|-&lt;br /&gt;
| NFSv3 || Byte-range locks through the separate NLM protocol (&amp;lt;code&amp;gt;lockd&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;statd&amp;lt;/code&amp;gt;) || Kernel POSIX locks on the pool&amp;#039;s file system&lt;br /&gt;
|-&lt;br /&gt;
| NFSv4.x || Byte-range locks as part of the protocol, plus delegations that let a client cache a file || Kernel POSIX locks, with client state tracked by &amp;lt;code&amp;gt;nfsdcld&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| SMB2/SMB3 || Byte-range locks, share modes, and oplocks/leases that let a client cache a file || Samba&amp;#039;s lock database, mirrored to kernel locks on the file system (&amp;lt;code&amp;gt;posix locking = yes&amp;lt;/code&amp;gt;)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
All of these are advisory to a POSIX application: they protect data only when every writer takes a lock. SMB byte-range locks are enforced against other SMB clients&amp;#039; reads and writes by Samba, but not against NFS I/O.&lt;br /&gt;
&lt;br /&gt;
Because Samba mirrors each SMB byte-range lock into a kernel lock, and the kernel NFS server takes kernel locks too, the two protocols see each other&amp;#039;s locks -- &amp;#039;&amp;#039;&amp;#039;provided the SMB lock actually reaches the server.&amp;#039;&amp;#039;&amp;#039; That condition is what the default configuration breaks.&lt;br /&gt;
&lt;br /&gt;
== Why the default configuration is not coherent across protocols ==&lt;br /&gt;
&lt;br /&gt;
By default a share has oplocks on and Samba grants SMB2/SMB3 &amp;#039;&amp;#039;&amp;#039;leases&amp;#039;&amp;#039;&amp;#039;. A client holding a write-caching lease is allowed to process byte-range locks locally, without sending them to the server, because it believes no one else has the file open. Samba grants that lease when it sees no other SMB opens, and Samba cannot see NFS opens: its &amp;lt;code&amp;gt;kernel oplocks&amp;lt;/code&amp;gt; setting is off by default, so an NFS client opening or locking the file does not break the lease.&lt;br /&gt;
&lt;br /&gt;
The result, measured on a scale-up pool with Linux NFSv4.2 and SMB 3.1.1 clients:&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;An SMB lock is invisible to NFS.&amp;#039;&amp;#039;&amp;#039; While an SMB client held a write lock on a range, the server recorded no lock at all -- neither in Samba&amp;#039;s lock table nor in the kernel -- and an NFS client locked the same range successfully.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;An NFS lock is invisible to SMB.&amp;#039;&amp;#039;&amp;#039; The NFS lock was a real kernel lock on the server, but the SMB client granted its own conflicting lock locally and never asked.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Updates are lost silently.&amp;#039;&amp;#039;&amp;#039; One NFS writer and one SMB writer each incremented a shared counter 500 times, both taking a proper lock around every update. The file ended at 926 instead of 1000, and neither application saw an error.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Reads go stale.&amp;#039;&amp;#039;&amp;#039; An SMB client that had read a file kept returning the old contents after an NFS client rewrote it, even on a fresh open.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Clients fail when the lease finally breaks.&amp;#039;&amp;#039;&amp;#039; With several writers on each protocol, the SMB client tried to push its locally held locks to the server when a lease was broken, and the server refused them because an NFS client held the same range. Applications then saw &amp;lt;code&amp;gt;EIO&amp;lt;/code&amp;gt; on unlock, or hung waiting on a lock.&lt;br /&gt;
&lt;br /&gt;
The SMB protocol allows any client holding a write-caching lease to handle byte-range locks locally, Windows clients included. Only Linux clients were tested, but nothing in this behaviour is specific to them.&lt;br /&gt;
&lt;br /&gt;
== Configuring a share for NFS and SMB access ==&lt;br /&gt;
&lt;br /&gt;
With oplocks disabled, Samba grants no oplock or lease, so every SMB lock goes to the server, Samba mirrors it into a kernel lock, and NFS and SMB clients block each other correctly. SMB clients also stop caching file data, so they read what an NFS client wrote.&lt;br /&gt;
&lt;br /&gt;
=== From the web interface ===&lt;br /&gt;
&lt;br /&gt;
{{Navigation|Storage Management &amp;amp;rarr; Network Shares &amp;amp;rarr; &amp;#039;&amp;#039;select a Network Share&amp;#039;&amp;#039; &amp;amp;rarr; Network Share &amp;amp;rarr; Modify &amp;#039;&amp;#039;(toolbar)&amp;#039;&amp;#039; &amp;amp;rarr; CIFS/SMB Settings &amp;#039;&amp;#039;(tab)&amp;#039;&amp;#039;}}&lt;br /&gt;
&lt;br /&gt;
Under &amp;#039;&amp;#039;&amp;#039;CIFS/SMB Advanced Options&amp;#039;&amp;#039;&amp;#039;, tick &amp;#039;&amp;#039;&amp;#039;Disable Oplocks&amp;#039;&amp;#039;&amp;#039; and click &amp;#039;&amp;#039;&amp;#039;OK&amp;#039;&amp;#039;&amp;#039;. The same checkbox is on the CIFS/SMB Settings tab of the Create Network Share dialog. See [[Network Shares#CIFS/SMB Settings tab|Network Shares]] for the other options on that tab.&lt;br /&gt;
&lt;br /&gt;
A lease granted before the change is not revoked by it. In testing, SMB clients were reconnected after changing the setting; do the same -- or make the change in a quiet period -- before relying on it.&lt;br /&gt;
&lt;br /&gt;
=== From the CLI ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[[QuantaStor CLI Command Reference#share-modify|qs share-modify]] --share=&amp;amp;lt;share&amp;amp;gt; --cifs-options=oplocks=no&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To return the share to the default, remove the option with a leading tilde: &amp;lt;code&amp;gt;--cifs-options=~oplocks&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Disabling oplocks also stops Samba granting SMB2/SMB3 leases, so no separate lease setting is needed.&lt;br /&gt;
&lt;br /&gt;
=== The cost ===&lt;br /&gt;
&lt;br /&gt;
Disabling oplocks removes SMB client-side caching, so SMB I/O on the share makes more round trips to the server. In the concurrent-writer test above, 500 locked updates from the SMB client took 4.7 seconds with oplocks disabled against 3.4 seconds with the default -- the default being faster precisely because it was not sending its locks to the server. The effect on large sequential transfers is smaller than on small, lock-heavy or metadata-heavy workloads. NFS performance is unaffected.&lt;br /&gt;
&lt;br /&gt;
This is why the setting is per share rather than system-wide: keep oplocks on for shares that only SMB clients use.&lt;br /&gt;
&lt;br /&gt;
== Verified behaviour ==&lt;br /&gt;
&lt;br /&gt;
The results below were measured on an HA pair of scale-up nodes with a ZFS pool on a shared JBOD, using two Linux clients, each mounting the share over NFSv4.2 and SMB 3.1.1. One client held a lock on bytes 100-149 of a file while the other attempted a conflicting lock.&lt;br /&gt;
&lt;br /&gt;
=== Lock conflict matrix, with Disable Oplocks ticked ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Held by !! Attempted by !! Overlapping write lock !! Read lock vs read lock !! Write lock vs held read lock !! Last held byte (149) !! Adjacent byte (150)&lt;br /&gt;
|-&lt;br /&gt;
| NFS || NFS || Refused || Granted || Refused || Refused || Granted&lt;br /&gt;
|-&lt;br /&gt;
| NFS || SMB || Refused || Granted || Refused || Refused || Granted&lt;br /&gt;
|-&lt;br /&gt;
| SMB || NFS || Refused || Granted || Refused || Refused || Granted&lt;br /&gt;
|-&lt;br /&gt;
| SMB || SMB || Refused || Granted || Refused || Refused || Granted&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Every result is the correct one. With the default configuration, the NFS/NFS and SMB/SMB rows are identical, but both cross-protocol rows grant every conflicting lock.&lt;br /&gt;
&lt;br /&gt;
=== Concurrent writers ===&lt;br /&gt;
&lt;br /&gt;
Each writer repeatedly locks an 8-byte counter at the start of a shared file, reads it, writes back the value plus one, flushes, and unlocks. Any lost update means two writers held the lock at once.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Share configuration !! Writers !! Updates expected !! Final value !! Lost&lt;br /&gt;
|-&lt;br /&gt;
| Default || 1 NFS + 1 SMB || 1,000 || 926 || &amp;#039;&amp;#039;&amp;#039;74&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
|-&lt;br /&gt;
| Disable Oplocks || 1 NFS + 1 SMB || 1,000 || 1,000 || 0&lt;br /&gt;
|-&lt;br /&gt;
| Disable Oplocks || 4 NFS + 4 SMB, across two client hosts || 2,400 || 2,400 || 0&lt;br /&gt;
|-&lt;br /&gt;
| &amp;#039;&amp;#039;Control: no locking at all&amp;#039;&amp;#039; || 4 NFS + 4 SMB || 2,400 || 1,569 || 831&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The control row shows that the test does detect concurrent updates when locking is absent.&lt;br /&gt;
&lt;br /&gt;
=== Share modes are not enforced against NFS ===&lt;br /&gt;
&lt;br /&gt;
SMB share modes -- a Windows application opening a file with deny-write or deny-read -- are enforced by Samba among SMB clients only. The share&amp;#039;s &amp;lt;code&amp;gt;kernel share modes&amp;lt;/code&amp;gt; setting is off, so Samba does not pass share modes to the kernel, and an NFS client is not blocked by an SMB client&amp;#039;s deny mode. This follows from the setting and was not separately tested. Applications that coordinate through share modes rather than byte-range locks should not rely on them across protocols.&lt;br /&gt;
&lt;br /&gt;
== Limits ==&lt;br /&gt;
&lt;br /&gt;
These figures come from the lab system above -- six-vCPU virtual machines on a single network segment -- and show scaling behaviour rather than a ceiling for production hardware. All were measured with Disable Oplocks ticked, so every lock went to the server.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Measurement !! NFS !! SMB !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| Lock + unlock pairs per second, one process || about 790 || about 850 || Bound by the network round trip, not the server&lt;br /&gt;
|-&lt;br /&gt;
| Lock + unlock pairs per second, 16 processes on two hosts sharing one file || colspan=&amp;quot;2&amp;quot; | about 2,660 combined || The server was not saturated; throughput scales with the number of clients&lt;br /&gt;
|-&lt;br /&gt;
| Time for one process to take N locks on one file, all held at once || 10,000 in 13 s; 50,000 in 322 s || 10,000 in 36 s; 50,000 did not complete in 10 minutes || See below&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Keep the number of locks held on a single file to around 10,000 or fewer.&amp;#039;&amp;#039;&amp;#039; On both protocols the cost of adding a lock grows with the number already held on that file, so acquisition slows sharply beyond that point. SMB is affected more: Samba processes a file&amp;#039;s lock list on one CPU core, which was fully busy during the 50,000-lock run. The limit applies per file, not per share, so spreading locks across files avoids it.&lt;br /&gt;
&lt;br /&gt;
An NFS client that holds a file open with no other client using it may be given a delegation and process its locks locally at a far higher rate. That is safe, because the server recalls the delegation when another client opens the file. It does mean single-client lock benchmarks over NFS overstate the rate that contended access achieves.&lt;br /&gt;
&lt;br /&gt;
== Locks and HA failover ==&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Byte-range locks, NFS and SMB alike, do not survive an HA pool failover.&amp;#039;&amp;#039;&amp;#039; After the pool moves to the other node, another client can immediately take a lock that the previous holder still believes it owns, and the previous holder is not told.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;NFS.&amp;#039;&amp;#039;&amp;#039; The node taking over the pool does not start an NFSv4 grace period for it, and has no record of the clients that held locks on the other node, so a client&amp;#039;s attempt to reclaim its locks is refused. A Linux client logs &amp;lt;code&amp;gt;NFS: &amp;amp;lt;server&amp;amp;gt;: lost N locks&amp;lt;/code&amp;gt; in its kernel log; the application itself is not told. [[NFS Configuration#NFS over an HA storage pool|NFS over an HA storage pool]] describes the NFS side of a failover in full.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SMB.&amp;#039;&amp;#039;&amp;#039; SMB sessions and open files are re-established after the failover, but byte-range locks are not carried over, and the client&amp;#039;s attempt to re-take them can fail. The application is not notified.&lt;br /&gt;
&lt;br /&gt;
Client I/O resumes on its own after the move: in testing, both NFS and SMB writers stalled for about 53 seconds during a manual failover and then continued without errors. Applications that use locks for correctness -- databases on file shares, shared project files, lock-file schemes -- need to handle a failover by reopening files and re-acquiring their locks, or be stopped before a planned failover. See [[HA Cluster Setup (JBODs)]] for configuring and triggering failover.&lt;br /&gt;
&lt;br /&gt;
== Checking lock state on the appliance ==&lt;br /&gt;
&lt;br /&gt;
To see what the server actually holds -- the quickest way to tell whether SMB locks are reaching it -- run these on the node that currently owns the pool:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;font-size: smaller&amp;quot;&amp;gt;&lt;br /&gt;
smbstatus -L                 # SMB open files, with their oplock or lease level&lt;br /&gt;
smbstatus -B                 # SMB byte-range locks&lt;br /&gt;
stat -c %i &amp;lt;file&amp;gt;            # the file&amp;#039;s inode number&lt;br /&gt;
grep &amp;quot;:&amp;lt;inode&amp;gt; &amp;quot; /proc/locks  # kernel locks on that file, from NFS and from Samba&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With Disable Oplocks ticked, &amp;lt;code&amp;gt;smbstatus -L&amp;lt;/code&amp;gt; shows &amp;lt;code&amp;gt;NONE&amp;lt;/code&amp;gt; in the Oplock column and an SMB client&amp;#039;s lock appears in &amp;lt;code&amp;gt;/proc/locks&amp;lt;/code&amp;gt; as an &amp;lt;code&amp;gt;OFDLCK&amp;lt;/code&amp;gt; entry beside any NFS &amp;lt;code&amp;gt;POSIX&amp;lt;/code&amp;gt; locks. With the default configuration an SMB client shows &amp;lt;code&amp;gt;LEASE(RWH)&amp;lt;/code&amp;gt; and its locks appear nowhere on the server.&lt;br /&gt;
&lt;br /&gt;
To confirm the setting Samba is using for a share:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;font-size: smaller&amp;quot;&amp;gt;&lt;br /&gt;
testparm -s --section-name=&amp;lt;share&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A share with Disable Oplocks ticked lists &amp;lt;code&amp;gt;oplocks = No&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Related pages ==&lt;br /&gt;
&lt;br /&gt;
* [[Network Shares]] -- creating shares and every option on the CIFS/SMB Settings tab&lt;br /&gt;
* [[NFS Configuration]] -- the NFS server, protocol versions, and NFS over an HA storage pool&lt;br /&gt;
* [[HA Cluster Setup (JBODs)]] -- HA storage pools and failover&lt;br /&gt;
* [[Scale-up HA Storage Pool Troubleshooting]] -- diagnosing failover problems&lt;br /&gt;
* [[QuantaStor CLI Command Reference#share-modify|QuantaStor CLI Command Reference]] -- &amp;lt;code&amp;gt;share-modify&amp;lt;/code&amp;gt; and its &amp;lt;code&amp;gt;--cifs-options&amp;lt;/code&amp;gt; argument&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;small&amp;gt;&amp;#039;&amp;#039;Verified against QuantaStor 6.9.0.&amp;#039;&amp;#039;&amp;lt;/small&amp;gt;&lt;/div&gt;</summary>
		<author><name>Qadmin</name></author>
	</entry>
</feed>