[PATCH 2/6] s3-printing: Initiate pcap reload from parent smbd

David Disseldorp ddiss at suse.de
Thu Dec 23 04:14:21 MST 2010


Since commit 7022554, smbds share a printcap cache (printer_list.tdb),
therefore ordering of events between smbd processes is important when
updating printcap cache information. Consider the following two process
example:
1) smbd1 receives HUP or printcap cache time expiry
2) smbd1 checks whether pcap needs refresh, it does
3) smbd1 marks pcap as refreshed
4) smbd1 forks child1 to obtain cups printer info
5) smbd2 receives HUP or printcap cache time expiry
6) smbd2 checks whether pcap needs refresh, it does not (due to step 3)
7) smbd2 reloads printer shares prior to child1 completion (stale pcap)
8) child1 completion, pcap cache (printer_list.tdb) is updated by smbd1
9) smbd1 reloads printer shares based on new pcap information

In this case both smbd1 and smbd2 are reliant on the pcap update
performed on child1 completion.
The prior commit "reload shares after pcap cache fill" ensures that
smbd1 only reloads printer shares following pcap update, however smbd2
continues to present shares based on stale pcap data.

This commit addresses the above problem by driving pcap cache and
printer share updates from the parent smbd process.
1) smbd0 (parent) receives a HUP or printcap cache time expiry
2) smbd0 forks child0 to obtain cups printer info
3) child0 completion, pcap cache (printer_list.tdb) is updated by smbd0
4) smbd0 reloads printer shares
5) smbd0 notifies child smbds of pcap update via message_send_all()
6) child smbds read fresh pcap data and reload printer shares

This architecture has the additional advantage that only a single
process (the parent smbd) requests printer information from the printcap
backend.
---
 docs-xml/smbdotconf/printing/printcapcachetime.xml |    4 +-
 source3/include/local.h                            |    1 +
 source3/include/proto.h                            |    2 +
 source3/librpc/idl/messaging.idl                   |    1 +
 source3/smbd/globals.c                             |    1 -
 source3/smbd/globals.h                             |    1 -
 source3/smbd/process.c                             |   43 +++--------------
 source3/smbd/server.c                              |   50 ++++++++++++++++++++
 source3/smbd/server_reload.c                       |   11 ++++-
 source3/web/swat.c                                 |   13 ++++--
 10 files changed, 80 insertions(+), 47 deletions(-)

diff --git a/docs-xml/smbdotconf/printing/printcapcachetime.xml b/docs-xml/smbdotconf/printing/printcapcachetime.xml
index 7dcd1b6..e9e0c98 100644
--- a/docs-xml/smbdotconf/printing/printcapcachetime.xml
+++ b/docs-xml/smbdotconf/printing/printcapcachetime.xml
@@ -5,9 +5,7 @@
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This option specifies the number of seconds before the printing
-    subsystem is again asked for the known printers.  If the value
-    is greater than 60 the initial waiting time is set to 60 seconds
-    to allow an earlier first rescan of the printing subsystem.
+    subsystem is again asked for the known printers.
     </para>
 
     <para>Setting this parameter to 0 disables any rescanning for new 
diff --git a/source3/include/local.h b/source3/include/local.h
index a8889af..bb73840 100644
--- a/source3/include/local.h
+++ b/source3/include/local.h
@@ -139,6 +139,7 @@
 #define LPQ_LOCK_TIMEOUT (5)
 #define NMBD_INTERFACES_RELOAD (120)
 #define NMBD_UNEXPECTED_TIMEOUT (15)
+#define SMBD_HOUSEKEEPING_INTERVAL SMBD_SELECT_TIMEOUT
 
 /* the following are in milliseconds */
 #define LOCK_RETRY_TIMEOUT (100)
diff --git a/source3/include/proto.h b/source3/include/proto.h
index f841a96..d9ed5ea 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -5383,6 +5383,8 @@ void reload_printers(struct tevent_context *ev,
 		     struct messaging_context *msg_ctx);
 bool reload_services(struct messaging_context *msg_ctx, int smb_sock,
 		     bool test);
+void reload_pcap_change_notify(struct tevent_context *ev,
+			       struct messaging_context *msg_ctx);
 void exit_server(const char *const explanation);
 void exit_server_cleanly(const char *const explanation);
 void exit_server_fault(void);
diff --git a/source3/librpc/idl/messaging.idl b/source3/librpc/idl/messaging.idl
index 9041d22..faa9a6e 100644
--- a/source3/librpc/idl/messaging.idl
+++ b/source3/librpc/idl/messaging.idl
@@ -45,6 +45,7 @@ interface messaging
 		MSG_PRINTERDATA_INIT_RESET	= 0x0204,
 		MSG_PRINTER_UPDATE		= 0x0205,
 		MSG_PRINTER_MOD			= 0x0206,
+		MSG_PRINTER_PCAP		= 0x0207,
 
 		/* smbd messages */
 		MSG_SMB_CONF_UPDATED		= 0x0301,
diff --git a/source3/smbd/globals.c b/source3/smbd/globals.c
index aac30ea..ca97884 100644
--- a/source3/smbd/globals.c
+++ b/source3/smbd/globals.c
@@ -54,7 +54,6 @@ struct msg_state *smbd_msg_state = NULL;
 
 bool logged_ioctl_message = false;
 
-pid_t mypid = 0;
 time_t last_smb_conf_reload_time = 0;
 time_t last_printer_reload_time = 0;
 /****************************************************************************
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index cb97cb5..7771049 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -61,7 +61,6 @@ extern bool logged_ioctl_message;
 
 extern int trans_num;
 
-extern pid_t mypid;
 extern time_t last_smb_conf_reload_time;
 extern time_t last_printer_reload_time;
 /****************************************************************************
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 2992576..8f5abda 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -943,6 +943,8 @@ static void smbd_sig_hup_handler(struct tevent_context *ev,
 	change_to_root_user();
 	DEBUG(1,("Reloading services after SIGHUP\n"));
 	reload_services(msg_ctx, smbd_server_conn->sock, False);
+	if (am_parent)
+		pcap_cache_reload(ev, msg_ctx, &reload_pcap_change_notify);
 }
 
 void smbd_setup_sig_hup_handler(struct tevent_context *ev,
@@ -2222,48 +2224,14 @@ void chain_reply(struct smb_request *req)
 
 static void check_reload(struct smbd_server_connection *sconn, time_t t)
 {
-	time_t printcap_cache_time = (time_t)lp_printcap_cache_time();
 
-	if(last_smb_conf_reload_time == 0) {
+	if (last_smb_conf_reload_time == 0)
 		last_smb_conf_reload_time = t;
-		/* Our printing subsystem might not be ready at smbd start up.
-		   Then no printer is available till the first printers check
-		   is performed.  A lower initial interval circumvents this. */
-		if ( printcap_cache_time > 60 )
-			last_printer_reload_time = t - printcap_cache_time + 60;
-		else
-			last_printer_reload_time = t;
-	}
-
-	if (mypid != getpid()) { /* First time or fork happened meanwhile */
-		/* randomize over 60 second the printcap reload to avoid all
-		 * process hitting cupsd at the same time */
-		int time_range = 60;
-
-		last_printer_reload_time += random() % time_range;
-		mypid = getpid();
-	}
 
 	if (t >= last_smb_conf_reload_time+SMBD_RELOAD_CHECK) {
 		reload_services(sconn->msg_ctx, sconn->sock, True);
 		last_smb_conf_reload_time = t;
 	}
-
-	/* 'printcap cache time = 0' disable the feature */
-
-	if ( printcap_cache_time != 0 )
-	{ 
-		/* see if it's time to reload or if the clock has been set back */
-
-		if ( (t >= last_printer_reload_time+printcap_cache_time) 
-			|| (t-last_printer_reload_time  < 0) ) 
-		{
-			DEBUG( 3,( "Printcap cache time expired.\n"));
-			pcap_cache_reload(server_event_context(),
-					  sconn->msg_ctx, &reload_printers);
-			last_printer_reload_time = t;
-		}
-	}
 }
 
 static bool fd_is_readable(int fd)
@@ -2493,6 +2461,9 @@ static bool housekeeping_fn(const struct timeval *now, void *private_data)
 {
 	struct smbd_server_connection *sconn = talloc_get_type_abort(
 		private_data, struct smbd_server_connection);
+
+	DEBUG(5, ("\'ousekeeping\n"));
+
 	change_to_root_user();
 
 	/* update printer queue caches if necessary */
@@ -3106,7 +3077,7 @@ void smbd_process(struct smbd_server_connection *sconn)
 	}
 
 	if (!(event_add_idle(smbd_event_context(), NULL,
-			     timeval_set(SMBD_SELECT_TIMEOUT, 0),
+			     timeval_set(SMBD_HOUSEKEEPING_INTERVAL, 0),
 			     "housekeeping", housekeeping_fn, sconn))) {
 		DEBUG(0, ("Could not add housekeeping event\n"));
 		exit(1);
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 81e714c..f723f6c 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -104,8 +104,26 @@ static void smb_conf_updated(struct messaging_context *msg,
 		  "updated. Reloading.\n"));
 	change_to_root_user();
 	reload_services(msg, smbd_server_conn->sock, False);
+	if (am_parent) {
+		pcap_cache_reload(server_event_context(), msg,
+				  &reload_pcap_change_notify);
+	}
 }
 
+/*******************************************************************
+ What to do when printcap is updated.
+ ********************************************************************/
+
+static void smb_pcap_updated(struct messaging_context *msg,
+			     void *private_data,
+			     uint32_t msg_type,
+			     struct server_id server_id,
+			     DATA_BLOB *data)
+{
+	DEBUG(10,("Got message saying pcap was updated. Reloading.\n"));
+	change_to_root_user();
+	reload_printers(server_event_context(), msg);
+}
 
 /*******************************************************************
  Delete a statcache entry.
@@ -581,6 +599,29 @@ static bool smbd_open_one_socket(struct smbd_parent_context *parent,
 	return true;
 }
 
+static bool smbd_parent_housekeeping(const struct timeval *now, void *private_data)
+{
+	time_t printcap_cache_time = (time_t)lp_printcap_cache_time();
+	time_t t = time(NULL);
+
+	DEBUG(5, ("parent \'ousekeeping\n"));
+
+	if (printcap_cache_time != 0) {
+		/* see if it's time to reload or if the clock has been set back */
+
+		if ((t >= (last_printer_reload_time + printcap_cache_time))
+		 || ((t - last_printer_reload_time) < 0)) {
+			DEBUG( 3,( "Printcap cache time expired.\n"));
+			pcap_cache_reload(server_event_context(),
+					  smbd_messaging_context(),
+					  &reload_pcap_change_notify);
+			last_printer_reload_time = t;
+		}
+	}
+
+	return true;
+}
+
 /****************************************************************************
  Open the socket communication.
 ****************************************************************************/
@@ -715,6 +756,14 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
 		return false;
 	}
 
+	if (!(event_add_idle(smbd_event_context(), NULL,
+			     timeval_set(SMBD_HOUSEKEEPING_INTERVAL, 0),
+			     "parent_housekeeping", smbd_parent_housekeeping,
+			     NULL))) {
+		DEBUG(0, ("Could not add parent_housekeeping event\n"));
+		return false;
+	}
+
         /* Listen to messages */
 
 	messaging_register(msg_ctx, NULL, MSG_SMB_SAM_SYNC, msg_sam_sync);
@@ -726,6 +775,7 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
 	messaging_register(msg_ctx, NULL, MSG_SMB_STAT_CACHE_DELETE,
 			   smb_stat_cache_delete);
 	messaging_register(msg_ctx, NULL, MSG_DEBUG, smbd_msg_debug);
+	messaging_register(msg_ctx, NULL, MSG_PRINTER_PCAP, smb_pcap_updated);
 	brl_register_msgs(msg_ctx);
 
 #ifdef CLUSTER_SUPPORT
diff --git a/source3/smbd/server_reload.c b/source3/smbd/server_reload.c
index 2b74e7a..bdca29d 100644
--- a/source3/smbd/server_reload.c
+++ b/source3/smbd/server_reload.c
@@ -114,8 +114,6 @@ bool reload_services(struct messaging_context *msg_ctx, int smb_sock,
 
 	ret = lp_load(get_dyn_CONFIGFILE(), False, False, True, True);
 
-	pcap_cache_reload(server_event_context(), msg_ctx, &reload_printers);
-
 	/* perhaps the config filename is now set */
 	if (!test)
 		reload_services(msg_ctx, smb_sock, True);
@@ -137,3 +135,12 @@ bool reload_services(struct messaging_context *msg_ctx, int smb_sock,
 
 	return(ret);
 }
+
+/****************************************************************************
+ Notify smbds of new printcap data
+**************************************************************************/
+void reload_pcap_change_notify(struct tevent_context *ev,
+			       struct messaging_context *msg_ctx)
+{
+	message_send_all(msg_ctx, MSG_PRINTER_PCAP, NULL, 0, NULL);
+}
diff --git a/source3/web/swat.c b/source3/web/swat.c
index 1cbecd4..93fe368 100644
--- a/source3/web/swat.c
+++ b/source3/web/swat.c
@@ -30,6 +30,7 @@
 #include "includes.h"
 #include "popt_common.h"
 #include "web/swat_proto.h"
+#include "printing/pcap.h"
 
 static int demo_mode = False;
 static int passwd_only = False;
@@ -491,8 +492,10 @@ static int save_reload(int snum)
                 return 0;
         }
 	iNumNonAutoPrintServices = lp_numservices();
-	pcap_cache_reload(server_event_context(), server_messaging_context(),
-			  &load_printers);
+	if (pcap_cache_loaded()) {
+		load_printers(server_event_context(),
+			      server_messaging_context());
+	}
 
 	return 1;
 }
@@ -1436,8 +1439,10 @@ const char *lang_msg_rotate(TALLOC_CTX *ctx, const char *msgid)
 	reopen_logs();
 	load_interfaces();
 	iNumNonAutoPrintServices = lp_numservices();
-	pcap_cache_reload(server_event_context(), server_messaging_context(),
-			  &load_printers);
+	if (pcap_cache_loaded()) {
+		load_printers(server_event_context(),
+			      server_messaging_context());
+	}
 
 	cgi_setup(get_dyn_SWATDIR(), !demo_mode);
 
-- 
1.7.1


--MP_/Db.Efq6a5W1YjEvpEDSnP+4
Content-Type: text/x-patch
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename=0003-s3-printing-remove-old-entries-in-pcap_cache_replace.patch



More information about the samba-technical mailing list