Bottleneck with Winbind and NT ACLs in 2.2.7a

Michael Steffens michael.steffens at hp.com
Tue Feb 4 13:12:29 GMT 2003


Hi,

we are running a big Samba 2.2.7a server with Winbind (>100 concurrent
users, >600 id mappings created since then) since last weekend.

It's running quite well! :)

However, users are complaining about Samba being very slow when
NT ACL support is enabled. I'm suspecting that winbindd is the
bottleneck.

In winbindd's log I can see that it has to serve "[ug]id to sid"
requests at a very high frequency. Most of them seem to be triggered
by smbd daemons working on POSIX ACLs, and the UIDs and GIDs
requested are almost always those of the user running a session.
Requests are keeping winbindd busy all the time. And when winbindd
is busy talking to DCs, user sessions have to wait for ACL settings
to complete.

As the ID mappings are static - as soon as they exist - wouldn't it
be a good idea to have smbd cache those it has come across in the
current session?

In the attached patch I have tried to implement such a local
mapping cache for smbd. What do you think about it?

Cheers!
Michael
-------------- next part --------------
Index: source/smbd/uid.c
===================================================================
RCS file: /cvsroot/samba/source/smbd/uid.c,v
retrieving revision 1.50.4.27
diff -u -r1.50.4.27 uid.c
--- source/smbd/uid.c	7 Jun 2002 03:49:15 -0000	1.50.4.27
+++ source/smbd/uid.c	4 Feb 2003 12:49:25 -0000
@@ -24,6 +24,164 @@
 /* what user is current? */
 extern struct current_user current_user;
 
+/* Id mapping cache.  This is to avoid Winbind mappings already
+   seen by smbd to be queried too frequently, keeping winbindd
+   busy, and blocking smbd while winbindd is busy with other
+   stuff. */
+
+#define UID_SID_CACHE_SIZE 256
+#define GID_SID_CACHE_SIZE 256
+
+static int n_uid_sid_cache = 0;
+static int n_gid_sid_cache = 0;
+
+static struct {uid_t uid; DOM_SID sid;} uid_sid_cache[UID_SID_CACHE_SIZE];
+static struct {gid_t gid; DOM_SID sid;} gid_sid_cache[GID_SID_CACHE_SIZE];
+
+
+/* convert uid to sid from cache */
+
+static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid) {
+	int i;
+	fstring sid;
+
+	for (i = 0; i < n_uid_sid_cache; i++) {
+		if (uid_sid_cache[i].uid == uid) {
+			*psid = uid_sid_cache[i].sid;
+			DEBUG(3,("fetch sid from uid cache %u -> %s\n",
+				(unsigned int)uid, sid_to_string(sid, psid)));
+			return TRUE;
+		}
+	}
+	return False;
+}
+
+
+/* convert sid to uid from cache */
+
+static BOOL fetch_uid_from_cache(uid_t *puid, DOM_SID *psid) {
+	int i;
+	fstring sid;
+
+	for (i = 0; i < n_uid_sid_cache; i++) {
+		if (sid_compare(&uid_sid_cache[i].sid, psid) == 0) {
+			*puid = uid_sid_cache[i].uid;
+			DEBUG(3,("fetch uid from cache %u -> %s\n",
+				(unsigned int)*puid, sid_to_string(sid, psid)));
+			return TRUE;
+		}
+	}
+	return False;
+}
+
+
+/* store uid mapping in cache */
+
+static void store_uid_sid_cache(DOM_SID *psid, uid_t uid) {
+	int i;
+	fstring sid;
+
+	/* first lookup whether cache entry already exists, */
+
+	for (i = 0; i < n_uid_sid_cache; i++) {
+		if (uid_sid_cache[i].uid == uid) {
+			if (sid_compare(psid, &uid_sid_cache[i].sid)) {
+				DEBUG(0,("Warning: uid mapping has changed to %u -> %s\n",
+					(unsigned int)uid, sid_to_string(sid, psid)));
+				goto store;
+			}
+			return;
+		}
+	}
+	if (n_uid_sid_cache < UID_SID_CACHE_SIZE) {
+		i = n_uid_sid_cache++;
+	} else {
+		/* cache full, overwrite random old entry */
+		i = rand() % UID_SID_CACHE_SIZE;
+		DEBUG(3,("overwrite uid mapping [%d] in cache: %u -> %s\n", i,
+			(unsigned int)uid_sid_cache[i].uid,
+			sid_to_string(sid, &uid_sid_cache[i].sid)));
+	}
+
+ store:
+	uid_sid_cache[i].uid = uid;
+	uid_sid_cache[i].sid = *psid;
+	DEBUG(3,("store uid mapping in cache %u -> %s\n",
+		(unsigned int)uid, sid_to_string(sid, psid)));
+}
+
+
+/* convert gid to sid from cache */
+
+static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid) {
+	int i;
+	fstring sid;
+
+	for (i = 0; i < n_gid_sid_cache; i++) {
+		if (gid_sid_cache[i].gid == gid) {
+			*psid = gid_sid_cache[i].sid;
+			DEBUG(3,("fetch sid from gid cache %u -> %s\n",
+				(unsigned int)gid, sid_to_string(sid, psid)));
+			return TRUE;
+		}
+	}
+	return False;
+}
+
+
+/* convert sid to gid from cache */
+
+static BOOL fetch_gid_from_cache(gid_t *pgid, DOM_SID *psid) {
+	int i;
+	fstring sid;
+
+	for (i = 0; i < n_gid_sid_cache; i++) {
+		if (sid_compare(&gid_sid_cache[i].sid, psid) == 0) {
+			*pgid = gid_sid_cache[i].gid;
+			DEBUG(3,("fetch gid from cache %u -> %s\n",
+				(unsigned int)*pgid, sid_to_string(sid, psid)));
+			return TRUE;
+		}
+	}
+	return False;
+}
+
+/* store gid mapping in cache */
+
+static void store_gid_sid_cache(DOM_SID *psid, gid_t gid) {
+	int i;
+	fstring sid;
+
+	/* first lookup whether cache entry already exists */
+
+	for (i = 0; i < n_gid_sid_cache; i++) {
+		if (gid_sid_cache[i].gid == gid) {
+			if (sid_compare(psid, &gid_sid_cache[i].sid)) {
+				DEBUG(0,("Warning: gid mapping has changed to %u -> %s\n",
+					(unsigned int)gid, sid_to_string(sid, psid)));
+				goto store;
+			}
+			return;
+		}
+	}
+	if (n_gid_sid_cache < GID_SID_CACHE_SIZE) {
+		i = n_gid_sid_cache++;
+	} else {
+		/* cache full, overwrite random old entry */
+		i = rand() % GID_SID_CACHE_SIZE;
+		DEBUG(3,("overwrite gid mapping [%d] in cache: %u -> %s\n", i,
+			(unsigned int)gid_sid_cache[i].gid,
+			sid_to_string(sid, &gid_sid_cache[i].sid)));
+	}
+
+ store:
+	gid_sid_cache[i].gid = gid;
+	gid_sid_cache[i].sid = *psid;
+	DEBUG(3,("store gid mapping in cache %u -> %s\n",
+		(unsigned int)gid, sid_to_string(sid, psid)));
+}
+
+
 /****************************************************************************
  Become the guest user without changing the security context stack.
 ****************************************************************************/
@@ -556,11 +714,15 @@
 	fstring sid;
 
 	if (lp_winbind_uid(&low, &high) && uid >= low && uid <= high) {
+		if (fetch_sid_from_uid_cache(psid, uid))
+			return psid;
+
 		if (winbind_uid_to_sid(psid, uid)) {
 
 			DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
 				(unsigned int)uid, sid_to_string(sid, psid)));
 
+			store_uid_sid_cache(psid, uid);
 			return psid;
 		}
 	}
@@ -584,11 +746,15 @@
 	fstring sid;
 
 	if (lp_winbind_gid(&low, &high) && gid >= low && gid <= high) {
+	 	if (fetch_sid_from_gid_cache(psid, gid))
+			return psid;
+
 		if (winbind_gid_to_sid(psid, gid)) {
 
 			DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
 				(unsigned int)gid, sid_to_string(sid, psid)));
                         
+			store_gid_sid_cache(psid, gid);
 			return psid;
 		}
 	}
@@ -646,10 +812,14 @@
 	 * Get the uid for this SID.
 	 */
 
-	if (!winbind_sid_to_uid(puid, psid)) {
-		DEBUG(10,("sid_to_uid: winbind lookup for sid %s failed.\n",
-				sid_to_string(sid_str, psid) ));
-		return local_sid_to_uid(puid, psid, sidtype);;
+	if (!fetch_uid_from_cache(puid, psid)) {
+		if (winbind_sid_to_uid(puid, psid)) {
+			store_uid_sid_cache(psid, *puid);
+		} else {
+			DEBUG(10,("sid_to_uid: winbind lookup for sid %s failed.\n",
+					sid_to_string(sid_str, psid) ));
+			return local_sid_to_uid(puid, psid, sidtype);;
+		}
 	}
 
 	DEBUG(10,("sid_to_uid: winbindd %s -> %u\n",
@@ -701,10 +871,14 @@
 	 * Get the gid for this SID.
 	 */
 
-	if (!winbind_sid_to_gid(pgid, psid)) {
-		DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed.\n",
-				sid_to_string(sid_str, psid) ));
-		return False;
+	if (!fetch_gid_from_cache(pgid, psid)) {
+		if (winbind_sid_to_gid(pgid, psid)) {
+			store_gid_sid_cache(psid, *pgid);
+		} else {
+			DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed.\n",
+					sid_to_string(sid_str, psid) ));
+			return False;
+		}
 	}
 
 	DEBUG(10,("sid_to_gid: winbindd %s -> %u\n",


More information about the samba-technical mailing list