When managing Windows XP profiles on a Debian Samba server, one particularly frustrating issue occurs when clients disconnect improperly - stale file locks remain in place. These locks, often created by applications like Thunderbird and Firefox, persist in Samba's locking table even after the client connection terminates.
# smbstatus -L | grep DENY_ALL
Pid Uid DenyMode Access R/W Oplock SharePath Name Time
15494 10345 DENY_ALL 0x3019f RDWR EXCLUSIVE+BATCH /home/CORP/user1 app.profile/user1.thunderbird/parent.lock
Windows applications frequently use DENY_ALL locks to prevent other processes from accessing files. When the client crashes or disconnects abruptly, Samba maintains these locks by default, following the CIFS/SMB protocol specifications.
Here are several approaches to handle stale locks while maintaining proper locking functionality:
1. Adjusting Samba's Oplock Configuration
Modify your smb.conf to implement more aggressive lock timeouts:
[global]
oplocks = yes
kernel oplocks = no
strict locking = yes
smb2 leases = no
deadtime = 15
keepalive = 60
2. Implementing a Lock Cleanup Script
Create a cron job to periodically clear stale locks:
#!/bin/bash
# Cleanup stale Samba locks
for lock in $(smbstatus -L | grep "DENY_ALL" | awk '{print $1}'); do
smbcontrol smbd close-share "$lock"
done
3. Client-Side Profile Configuration
Configure Windows clients to handle profile files more gracefully:
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Winlogon]
"SlowLinkProfileDefault"=dword:00000001
"ProfileDlgTimeOut"=dword:0000001e
For enterprise environments, consider implementing a custom VFS module:
vfs objects = preopen
preopen:names = /etc/samba/preopen.conf
preopen:check_parent = yes
Create /etc/samba/preopen.conf with patterns for problematic files:
*.thunderbird/*.lock
*.firefox/*.lock
Implement regular monitoring of your lock situation:
# Daily lock report
smbstatus -L > /var/log/samba/lock_report_$(date +%Y%m%d).log
Combine this with logrotate to maintain historical data while preventing log files from growing too large.
When running Windows profiles directly from Samba shares (common in corporate environments), we frequently encounter situations where client disconnections leave stale file locks. This occurs particularly with applications like Thunderbird and Firefox that aggressively maintain profile locks. Examining the locking table reveals entries like:
Pid Uid DenyMode Access R/W Oplock SharePath Name Time
15494 10345 DENY_ALL 0x3019f RDWR EXCLUSIVE+BATCH /home/CORP/user1 profile/user1.thunderbird/parent.lock
While completely disabling file locking (kernel oplocks = no
in smb.conf) would technically solve the issue, it's not viable for production environments where file integrity matters. The challenge is maintaining locking functionality while automatically cleaning up stale locks.
These smb.conf parameters help mitigate the problem:
[global]
kernel change notify = no
oplock break wait time = 60
deadtime = 30
keepalive = 60
smb2 leases = yes
veto oplock files = /*.lock/*.LOCK/
For persistent cases, implement a cron job that identifies and clears stale locks:
#!/bin/bash
SMBCLIENT="/usr/bin/smbclient"
LOCKFILE="/var/run/samba/lock_cleanup.pid"
# Prevent multiple instances
if [ -f "$LOCKFILE" ]; then
exit 0
fi
echo $$ > "$LOCKFILE"
# Find stale locks older than 2 hours
STALE_LOCKS=$(smbstatus -L | awk '$6 ~ /DENY_ALL/ && $9 ~ /Thunderbird|Firefox/ {
cmd = "ps -p " $1 " >/dev/null 2>&1"
if (system(cmd) != 0) {
print $1, $7 "/" $8
}
}')
while read -r pid path; do
echo "Clearing stale lock from PID $pid on $path"
smbcontrol smbd close-share "$path"
done <<< "$STALE_LOCKS"
rm -f "$LOCKFILE"
Complement server-side changes with these client registry modifications to prevent aggressive locking:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\MRxSmb\Parameters]
"SessionTimeout"=dword:0000003c
"OpportunisticLocking"=dword:00000000
Implement monitoring to track lock persistence:
# Nagios plugin to check for stale locks
#!/bin/bash
WARNING_THRESHOLD=10
CRITICAL_THRESHOLD=30
STALE_COUNT=$(smbstatus -L | grep DENY_ALL | awk -v now=$(date +%s) '{
locktime = $NF; gsub(/-|:/," ",locktime);
lock_epoch = mktime(locktime);
if ((now - lock_epoch) > 7200) print $0;
}' | wc -l)
if [ "$STALE_COUNT" -ge "$CRITICAL_THRESHOLD" ]; then
echo "CRITICAL: $STALE_COUNT stale locks detected"
exit 2
elif [ "$STALE_COUNT" -ge "$WARNING_THRESHOLD" ]; then
echo "WARNING: $STALE_COUNT stale locks detected"
exit 1
else
echo "OK: $STALE_COUNT stale locks detected"
exit 0
fi