Re: Possible deadlocking between jcifs.smb.Dfs and jcifs.smb.SmbTransport [PATCH]

Xavier Roche <[email protected]>
Newsgroups gmane.network.samba.java
Organization Exalead
Message-ID <[email protected]>
Hi again,

On 02/29/2012 05:42 PM, Xavier Roche wrote:
> [ Issue found in jcifs 1.3.17 ]
> jcifs.smb.Dfs and jcifs.smb.SmbTransport seems to be deadlocking due to
> Mutex ordering mismatch in the code.

The attached patch seems to solve the issue.

Basically, the Dfs.resolve() and Dfs.insert() methods do not need to be 
synchronized, only the "referrals" member needs to be locked (using an 
additional lock, because the member itself can be replaced). This way, 
calls such as getDc() in Dfs.resolve() won't deadlock.

I successfully ran a stress test with 32 threads enumerating a DFS, and 
it seems to work fine.

Could this fix me merged in the next release, if it is good enough ?


Regards,
Xavier
jcifs-1.3.17-Dfs_deadlock_fix.patch (text/x-patch, 2.6 KB)
diff -rudb /ng/sdk/jcifs/1.3.17/src/jcifs/smb/Dfs.java jcifs/smb/Dfs.java
--- /ng/sdk/jcifs/1.3.17/src/jcifs/smb/Dfs.java	2011-10-18 21:26:25.000000000 +0200
+++ jcifs/smb/Dfs.java	2012-03-01 10:23:49.353867365 +0100
@@ -47,7 +47,9 @@
     protected static CacheEntry FALSE_ENTRY = new Dfs.CacheEntry(0L);
 
     protected CacheEntry _domains = null; /* aka trusted domains cache */
+    
     protected CacheEntry referrals = null;
+    protected final Object referralsLock = new Object();
 
     public HashMap getTrustedDomains(NtlmPasswordAuthentication auth) throws SmbAuthException {
         if (DISABLED || auth.domain == "?")
@@ -152,7 +154,7 @@
         }
         return null;
     }
-    public synchronized DfsReferral resolve(String domain,
+    public DfsReferral resolve(String domain,
                 String root,
                 String path,
                 NtlmPasswordAuthentication auth) throws SmbAuthException {
@@ -252,12 +254,14 @@
             /* We did not match a domain based root. Now try to match the
              * longest path in the list of stand-alone referrals.
              */
+            synchronized (referralsLock) {
             if (referrals != null && now > referrals.expiration) {
                 referrals = null;
             }
             if (referrals == null) {
                 referrals = new CacheEntry(0);
             }
+
             String key = "\\" + domain + "\\" + root;
             if (path.equals("\\") == false)
                 key += path;
@@ -265,7 +269,7 @@
 
             Iterator iter = referrals.map.keySet().iterator();
             while (iter.hasNext()) {
-                String _key = (String)iter.next();
+                    String _key = (String) iter.next();
                 int _klen = _key.length();
                 boolean match = false;
 
@@ -276,13 +280,15 @@
                 }
 
                 if (match)
-                    dr = (DfsReferral)referrals.map.get(_key);
+                        dr = (DfsReferral) referrals.map.get(_key);
+                }
             }
         }
 
         return dr;
     }
-    synchronized void insert(String path, DfsReferral dr) {
+    
+    void insert(String path, DfsReferral dr) {
         int s1, s2;
         String server, share, key;
 
@@ -316,6 +322,7 @@
          */
         dr.pathConsumed -= 1 + server.length() + 1 + share.length();
 
+        synchronized (referralsLock) {
         if (referrals != null && (System.currentTimeMillis() + 10000) > referrals.expiration) {
             referrals = null;
         }
@@ -324,4 +331,5 @@
         }
         referrals.map.put(key, dr);
     }
+    }
 }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.