"killtime" parameter patch ?

Jeremy Allison jra at samba.org
Tue May 15 18:23:56 MDT 2012


Interesting situation just came up (original guilty party who
raised the issue deleted :-).

Testing a Samba server for reliability. Connected Windows client
with open files.

Ethernet cable gets unplugged for a few minutes, client IO fails,
then it gets reconnected.

Client reconnects to Samba, gets a new smbd but finds its open files
still locked.

"deadtime" doesn't fire because the smbd still has resources open.

Original smbd is still hanging around so sharemode detection finds
an open process.

If the files are oplocked oplock break send will get a TCP reset
and cause the original smbd to die, but what if the oplock was already
broken ?

In that case a "FILE_SHARE_NONE" blocks everything for as long as
the original smbd is still around.

Client has no way to signal original server smbd process that it
should die.

TCP timeouts will kill after 2 hours but this is considered *way*
too long for client to wait. "reset on zero vc" isn't set due to
potential NAT issues.

So here is an (untested, but compiles and I think it'll do the job)
solution. Parameter "killtime" (set in minutes). If nothing received
on a TCP connection (including no SMBecho calls) for "killtime"
minutes, it causes the smbd to commit suicide (even with open
resources). Cleanly of course :-).

Thoughts on whether this is a good idea ? If so I'll write up the
man page :-).

Jeremy.
-------------- next part --------------
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 28b58b2..39f030c 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -1531,6 +1531,7 @@ int lp_maxmux(void);
 int lp_passwordlevel(void);
 int lp_usernamelevel(void);
 int lp_deadtime(void);
+int lp_killtime(void);
 bool lp_getwd_cache(void);
 int lp_maxprotocol(void);
 int lp_minprotocol(void);
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index 6ad2452..d75620f 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -241,6 +241,7 @@ struct global {
 	int pwordlevel;
 	int unamelevel;
 	int deadtime;
+	int killtime;
 	bool getwd_cache;
 	int maxprotocol;
 	int minprotocol;
@@ -2383,6 +2384,15 @@ static struct parm_struct parm_table[] = {
 		.flags		= FLAG_ADVANCED,
 	},
 	{
+		.label		= "killtime",
+		.type		= P_INTEGER,
+		.p_class	= P_GLOBAL,
+		.ptr		= &Globals.killtime,
+		.special	= NULL,
+		.enum_list	= NULL,
+		.flags		= FLAG_ADVANCED,
+	},
+	{
 		.label		= "getwd cache",
 		.type		= P_BOOL,
 		.p_class	= P_GLOBAL,
@@ -5279,6 +5289,7 @@ static void init_globals(bool reinit_globals)
 	Globals.pwordlevel = 0;
 	Globals.unamelevel = 0;
 	Globals.deadtime = 0;
+	Globals.killtime = 0;
 	Globals.getwd_cache = true;
 	Globals.bLargeReadwrite = True;
 	Globals.max_log_size = 5000;
@@ -5850,6 +5861,7 @@ FN_GLOBAL_INTEGER(lp_maxmux, &Globals.max_mux)
 FN_GLOBAL_INTEGER(lp_passwordlevel, &Globals.pwordlevel)
 FN_GLOBAL_INTEGER(lp_usernamelevel, &Globals.unamelevel)
 FN_GLOBAL_INTEGER(lp_deadtime, &Globals.deadtime)
+FN_GLOBAL_INTEGER(lp_killtime, &Globals.killtime)
 FN_GLOBAL_BOOL(lp_getwd_cache, &Globals.getwd_cache)
 static FN_GLOBAL_INTEGER(_lp_maxprotocol, &Globals.maxprotocol)
 int lp_maxprotocol(void)
diff --git a/source3/smbd/conn.c b/source3/smbd/conn.c
index 8a96e88..5193d80 100644
--- a/source3/smbd/conn.c
+++ b/source3/smbd/conn.c
@@ -281,15 +281,67 @@ static void conn_lastused_update(struct smbd_server_connection *sconn,time_t t)
 }
 
 /****************************************************************************
+ Commit suicide dropping all resources if we go over a given kill timelimit
+ (in seconds) and there has been no activity.
+****************************************************************************/
+
+static bool conn_force_suicide(struct smbd_server_connection *sconn, int killtime, time_t t)
+{
+	if (killtime <= 0) {
+		return false;
+	}
+
+	if (sconn->using_smb2) {
+		/* SMB2 */
+		struct smbd_smb2_session *sess;
+		for (sess = sconn->smb2.sessions.list; sess; sess = sess->next) {
+			struct smbd_smb2_tcon *ptcon;
+
+			for (ptcon = sess->tcons.list; ptcon; ptcon = ptcon->next) {
+				time_t age;
+				connection_struct *conn = ptcon->compat_conn;
+
+				if (conn == NULL) {
+					continue;
+				}
+
+				age = t - conn->lastused;
+				if (age < killtime) {
+					return false;
+				}
+
+			}
+		}
+	} else {
+		/* SMB1 */
+		connection_struct *conn;
+		for (conn=sconn->smb1.tcons.Connections;conn;conn=conn->next) {
+			time_t age = t - conn->lastused;
+
+			if (age < killtime) {
+				return false;
+			}
+		}
+	}
+	/* Die with all resources open. */
+	return true;
+}
+
+/****************************************************************************
  Idle inactive connections.
 ****************************************************************************/
 
 bool conn_idle_all(struct smbd_server_connection *sconn, time_t t)
 {
 	int deadtime = lp_deadtime()*60;
+	int killtime = lp_killtime()*60;
 
 	conn_lastused_update(sconn, t);
 
+	if (killtime && conn_force_suicide(sconn, killtime, t)) {
+		return true;
+	}
+
 	if (deadtime <= 0) {
 		deadtime = DEFAULT_SMBD_TIMEOUT;
 	}


More information about the samba-technical mailing list