]>
Commit | Line | Data |
---|---|---|
1d13e637 AF |
1 | From 61c58824cc9117ffe206ae7c126929bfa2384486 Mon Sep 17 00:00:00 2001 |
2 | From: David Disseldorp <ddiss@samba.org> | |
3 | Date: Thu, 10 Jul 2014 00:18:10 +0200 | |
4 | Subject: [PATCH 1/7] PATCHSET18: printing: traverse_read the printer list for | |
5 | share updates | |
6 | MIME-Version: 1.0 | |
7 | Content-Type: text/plain; charset=UTF-8 | |
8 | Content-Transfer-Encoding: 8bit | |
9 | ||
10 | The printcap update procedure involves the background printer process | |
11 | obtaining the printcap information from the printing backend, writing | |
12 | this to printer_list.tdb, and then notifying all smbd processes of the | |
13 | new list. The processes then all attempt to simultaneously traverse | |
14 | printer_list.tdb, in order to update their local share lists. | |
15 | ||
16 | With a large number of printers, and a large number of per-client smbd | |
17 | processes, this traversal results in significant lock contention, mostly | |
18 | due to the fact that the traversal is unnecessarily done with an | |
19 | exclusive (write) lock on the printer_list.tdb database. | |
20 | ||
21 | This commit changes the share update code path to perform a read-only | |
22 | traversal. | |
23 | ||
24 | Bug: https://bugzilla.samba.org/show_bug.cgi?id=10652 | |
25 | ||
26 | Reported-by: Alex K <korobkin+samba@gmail.com> | |
27 | Reported-by: Franz Pförtsch <franz.pfoertsch@brose.com> | |
28 | Signed-off-by: David Disseldorp <ddiss@samba.org> | |
29 | --- | |
30 | source3/printing/load.c | 2 +- | |
31 | source3/printing/pcap.c | 4 ++-- | |
32 | source3/printing/pcap.h | 2 +- | |
33 | source3/printing/printer_list.c | 17 +++++++++++------ | |
34 | source3/printing/printer_list.h | 4 ++-- | |
35 | 5 files changed, 17 insertions(+), 12 deletions(-) | |
36 | ||
37 | diff --git a/source3/printing/load.c b/source3/printing/load.c | |
38 | index 829c3e3..0a3de73 100644 | |
39 | --- a/source3/printing/load.c | |
40 | +++ b/source3/printing/load.c | |
41 | @@ -70,5 +70,5 @@ void load_printers(struct tevent_context *ev, | |
42 | ||
43 | /* load all printcap printers */ | |
44 | if (lp_load_printers() && lp_servicenumber(PRINTERS_NAME) >= 0) | |
45 | - pcap_printer_fn(lp_add_one_printer, NULL); | |
46 | + pcap_printer_read_fn(lp_add_one_printer, NULL); | |
47 | } | |
48 | diff --git a/source3/printing/pcap.c b/source3/printing/pcap.c | |
49 | index 62db4f5..6ad8e33 100644 | |
50 | --- a/source3/printing/pcap.c | |
51 | +++ b/source3/printing/pcap.c | |
52 | @@ -229,11 +229,11 @@ void pcap_printer_fn_specific(const struct pcap_cache *pc, | |
53 | return; | |
54 | } | |
55 | ||
56 | -void pcap_printer_fn(void (*fn)(const char *, const char *, const char *, void *), void *pdata) | |
57 | +void pcap_printer_read_fn(void (*fn)(const char *, const char *, const char *, void *), void *pdata) | |
58 | { | |
59 | NTSTATUS status; | |
60 | ||
61 | - status = printer_list_run_fn(fn, pdata); | |
62 | + status = printer_list_read_run_fn(fn, pdata); | |
63 | if (!NT_STATUS_IS_OK(status)) { | |
64 | DEBUG(3, ("Failed to run fn for all printers!\n")); | |
65 | } | |
66 | diff --git a/source3/printing/pcap.h b/source3/printing/pcap.h | |
67 | index 7056213..6c062c3 100644 | |
68 | --- a/source3/printing/pcap.h | |
69 | +++ b/source3/printing/pcap.h | |
70 | @@ -39,7 +39,7 @@ bool pcap_cache_add(const char *name, const char *comment, const char *location) | |
71 | bool pcap_cache_loaded(void); | |
72 | bool pcap_cache_replace(const struct pcap_cache *cache); | |
73 | void pcap_printer_fn_specific(const struct pcap_cache *, void (*fn)(const char *, const char *, const char *, void *), void *); | |
74 | -void pcap_printer_fn(void (*fn)(const char *, const char *, const char *, void *), void *); | |
75 | +void pcap_printer_read_fn(void (*fn)(const char *, const char *, const char *, void *), void *); | |
76 | ||
77 | void pcap_cache_reload(struct tevent_context *ev, | |
78 | struct messaging_context *msg_ctx, | |
79 | diff --git a/source3/printing/printer_list.c b/source3/printing/printer_list.c | |
80 | index 603ce4b..b24bf83 100644 | |
81 | --- a/source3/printing/printer_list.c | |
82 | +++ b/source3/printing/printer_list.c | |
83 | @@ -280,7 +280,8 @@ done: | |
84 | typedef int (printer_list_trv_fn_t)(struct db_record *, void *); | |
85 | ||
86 | static NTSTATUS printer_list_traverse(printer_list_trv_fn_t *fn, | |
87 | - void *private_data) | |
88 | + void *private_data, | |
89 | + bool read_only) | |
90 | { | |
91 | struct db_context *db; | |
92 | int ret; | |
93 | @@ -290,7 +291,11 @@ static NTSTATUS printer_list_traverse(printer_list_trv_fn_t *fn, | |
94 | return NT_STATUS_INTERNAL_DB_CORRUPTION; | |
95 | } | |
96 | ||
97 | - ret = db->traverse(db, fn, private_data); | |
98 | + if (read_only) { | |
99 | + ret = db->traverse_read(db, fn, private_data); | |
100 | + } else { | |
101 | + ret = db->traverse(db, fn, private_data); | |
102 | + } | |
103 | if (ret < 0) { | |
104 | return NT_STATUS_UNSUCCESSFUL; | |
105 | } | |
106 | @@ -357,7 +362,7 @@ NTSTATUS printer_list_clean_old(void) | |
107 | ||
108 | state.status = NT_STATUS_OK; | |
109 | ||
110 | - status = printer_list_traverse(printer_list_clean_fn, &state); | |
111 | + status = printer_list_traverse(printer_list_clean_fn, &state, false); | |
112 | if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL) && | |
113 | !NT_STATUS_IS_OK(state.status)) { | |
114 | status = state.status; | |
115 | @@ -404,8 +409,8 @@ static int printer_list_exec_fn(struct db_record *rec, void *private_data) | |
116 | return 0; | |
117 | } | |
118 | ||
119 | -NTSTATUS printer_list_run_fn(void (*fn)(const char *, const char *, const char *, void *), | |
120 | - void *private_data) | |
121 | +NTSTATUS printer_list_read_run_fn(void (*fn)(const char *, const char *, const char *, void *), | |
122 | + void *private_data) | |
123 | { | |
124 | struct printer_list_exec_state state; | |
125 | NTSTATUS status; | |
126 | @@ -414,7 +419,7 @@ NTSTATUS printer_list_run_fn(void (*fn)(const char *, const char *, const char * | |
127 | state.private_data = private_data; | |
128 | state.status = NT_STATUS_OK; | |
129 | ||
130 | - status = printer_list_traverse(printer_list_exec_fn, &state); | |
131 | + status = printer_list_traverse(printer_list_exec_fn, &state, true); | |
132 | if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL) && | |
133 | !NT_STATUS_IS_OK(state.status)) { | |
134 | status = state.status; | |
135 | diff --git a/source3/printing/printer_list.h b/source3/printing/printer_list.h | |
136 | index fb2e007..b12c192 100644 | |
137 | --- a/source3/printing/printer_list.h | |
138 | +++ b/source3/printing/printer_list.h | |
139 | @@ -100,6 +100,6 @@ NTSTATUS printer_list_mark_reload(void); | |
140 | */ | |
141 | NTSTATUS printer_list_clean_old(void); | |
142 | ||
143 | -NTSTATUS printer_list_run_fn(void (*fn)(const char *, const char *, const char *, void *), | |
144 | - void *private_data); | |
145 | +NTSTATUS printer_list_read_run_fn(void (*fn)(const char *, const char *, const char *, void *), | |
146 | + void *private_data); | |
147 | #endif /* _PRINTER_LIST_H_ */ | |
148 | -- | |
149 | 2.1.0 | |
150 | ||
151 | ||
152 | From 18b15f127b656ad9232789b073460c95b1aaa835 Mon Sep 17 00:00:00 2001 | |
153 | From: David Disseldorp <ddiss@samba.org> | |
154 | Date: Fri, 11 Jul 2014 17:00:05 +0200 | |
155 | Subject: [PATCH 2/7] PATCHSET18: printing: only reload printer shares on | |
156 | client enum | |
157 | ||
158 | Currently, automatic printer share updates are handled in the following | |
159 | way: | |
160 | - Background printer process (BPP) forked on startup | |
161 | - Parent smbd and per-client children await MSG_PRINTER_PCAP messages | |
162 | - BPP periodically polls the printing backend for printcap data | |
163 | - printcap data written to printer_list.tdb | |
164 | - MSG_PRINTER_PCAP sent to all smbd processes following update | |
165 | - smbd processes all read the latest printer_list.tdb data, and update | |
166 | their share listings | |
167 | ||
168 | This procedure is not scalable, as all smbd processes hit | |
169 | printer_list.tdb in parallel, resulting in a large spike in CPU usage. | |
170 | ||
171 | This change sees smbd processes only update their printer share lists | |
172 | only when a client asks for this information, e.g. via NetShareEnum or | |
173 | EnumPrinters. | |
174 | ||
175 | Bug: https://bugzilla.samba.org/show_bug.cgi?id=10652 | |
176 | ||
177 | Suggested-by: Volker Lendecke <vl@samba.org> | |
178 | Signed-off-by: David Disseldorp <ddiss@samba.org> | |
179 | --- | |
180 | source3/printing/spoolssd.c | 17 +---------------- | |
181 | source3/rpc_server/spoolss/srv_spoolss_nt.c | 11 ++++++++++- | |
182 | source3/rpc_server/srvsvc/srv_srvsvc_nt.c | 1 + | |
183 | source3/smbd/lanman.c | 3 +++ | |
184 | source3/smbd/server.c | 27 +++++---------------------- | |
185 | 5 files changed, 20 insertions(+), 39 deletions(-) | |
186 | ||
187 | diff --git a/source3/printing/spoolssd.c b/source3/printing/spoolssd.c | |
188 | index 83727df..7953237 100644 | |
189 | --- a/source3/printing/spoolssd.c | |
190 | +++ b/source3/printing/spoolssd.c | |
191 | @@ -74,20 +74,6 @@ static void smb_conf_updated(struct messaging_context *msg, | |
192 | spoolss_reopen_logs(); | |
193 | } | |
194 | ||
195 | -static void spoolss_pcap_updated(struct messaging_context *msg, | |
196 | - void *private_data, | |
197 | - uint32_t msg_type, | |
198 | - struct server_id server_id, | |
199 | - DATA_BLOB *data) | |
200 | -{ | |
201 | - struct tevent_context *ev_ctx = talloc_get_type_abort(private_data, | |
202 | - struct tevent_context); | |
203 | - | |
204 | - DEBUG(10, ("Got message saying pcap was updated. Reloading.\n")); | |
205 | - change_to_root_user(); | |
206 | - reload_printers(ev_ctx, msg); | |
207 | -} | |
208 | - | |
209 | static void spoolss_sig_term_handler(struct tevent_context *ev, | |
210 | struct tevent_signal *se, | |
211 | int signum, | |
212 | @@ -206,12 +192,11 @@ void start_spoolssd(struct tevent_context *ev_ctx, | |
213 | exit(1); | |
214 | } | |
215 | ||
216 | + /* printer shares updated from printer_list.tdb on client enumeration */ | |
217 | messaging_register(msg_ctx, NULL, | |
218 | MSG_PRINTER_UPDATE, print_queue_receive); | |
219 | messaging_register(msg_ctx, ev_ctx, | |
220 | MSG_SMB_CONF_UPDATED, smb_conf_updated); | |
221 | - messaging_register(msg_ctx, ev_ctx, | |
222 | - MSG_PRINTER_PCAP, spoolss_pcap_updated); | |
223 | ||
224 | /* | |
225 | * Initialize spoolss with an init function to convert printers first. | |
226 | diff --git a/source3/rpc_server/spoolss/srv_spoolss_nt.c b/source3/rpc_server/spoolss/srv_spoolss_nt.c | |
227 | index 516b7dc..db48574 100644 | |
228 | --- a/source3/rpc_server/spoolss/srv_spoolss_nt.c | |
229 | +++ b/source3/rpc_server/spoolss/srv_spoolss_nt.c | |
230 | @@ -4316,12 +4316,21 @@ static WERROR enum_all_printers_info_level(TALLOC_CTX *mem_ctx, | |
231 | uint32_t *count_p) | |
232 | { | |
233 | int snum; | |
234 | - int n_services = lp_numservices(); | |
235 | + int n_services; | |
236 | union spoolss_PrinterInfo *info = NULL; | |
237 | uint32_t count = 0; | |
238 | WERROR result = WERR_OK; | |
239 | struct dcerpc_binding_handle *b = NULL; | |
240 | ||
241 | + /* | |
242 | + * printer shares are only updated on client enumeration. The background | |
243 | + * printer process updates printer_list.tdb at regular intervals. | |
244 | + */ | |
245 | + become_root(); | |
246 | + reload_printers(messaging_event_context(msg_ctx), msg_ctx); | |
247 | + unbecome_root(); | |
248 | + | |
249 | + n_services = lp_numservices(); | |
250 | *count_p = 0; | |
251 | *info_p = NULL; | |
252 | ||
253 | diff --git a/source3/rpc_server/srvsvc/srv_srvsvc_nt.c b/source3/rpc_server/srvsvc/srv_srvsvc_nt.c | |
254 | index b9345d6..4600da3 100644 | |
255 | --- a/source3/rpc_server/srvsvc/srv_srvsvc_nt.c | |
256 | +++ b/source3/rpc_server/srvsvc/srv_srvsvc_nt.c | |
257 | @@ -568,6 +568,7 @@ static WERROR init_srv_share_info_ctr(struct pipes_struct *p, | |
258 | ||
259 | /* Ensure all the usershares are loaded. */ | |
260 | become_root(); | |
261 | + reload_printers(messaging_event_context(p->msg_ctx), p->msg_ctx); | |
262 | load_usershare_shares(); | |
263 | load_registry_shares(); | |
264 | num_services = lp_numservices(); | |
265 | diff --git a/source3/smbd/lanman.c b/source3/smbd/lanman.c | |
266 | index f56ea30..49f7583 100644 | |
267 | --- a/source3/smbd/lanman.c | |
268 | +++ b/source3/smbd/lanman.c | |
269 | @@ -43,6 +43,7 @@ | |
270 | #include "passdb/machine_sid.h" | |
271 | #include "auth.h" | |
272 | #include "rpc_server/rpc_ncacn_np.h" | |
273 | +#include "messages.h" | |
274 | ||
275 | #ifdef CHECK_TYPES | |
276 | #undef CHECK_TYPES | |
277 | @@ -2091,6 +2092,8 @@ static bool api_RNetShareEnum(struct smbd_server_connection *sconn, | |
278 | ||
279 | /* Ensure all the usershares are loaded. */ | |
280 | become_root(); | |
281 | + reload_printers(messaging_event_context(sconn->msg_ctx), | |
282 | + sconn->msg_ctx); | |
283 | load_registry_shares(); | |
284 | count = load_usershare_shares(); | |
285 | unbecome_root(); | |
286 | diff --git a/source3/smbd/server.c b/source3/smbd/server.c | |
287 | index a26dbc4..102e8dd 100644 | |
288 | --- a/source3/smbd/server.c | |
289 | +++ b/source3/smbd/server.c | |
290 | @@ -111,24 +111,6 @@ static void smb_conf_updated(struct messaging_context *msg, | |
291 | /* printer reload triggered by background printing process */ | |
292 | } | |
293 | ||
294 | -/******************************************************************* | |
295 | - What to do when printcap is updated. | |
296 | - ********************************************************************/ | |
297 | - | |
298 | -static void smb_pcap_updated(struct messaging_context *msg, | |
299 | - void *private_data, | |
300 | - uint32_t msg_type, | |
301 | - struct server_id server_id, | |
302 | - DATA_BLOB *data) | |
303 | -{ | |
304 | - struct tevent_context *ev_ctx = | |
305 | - talloc_get_type_abort(private_data, struct tevent_context); | |
306 | - | |
307 | - DEBUG(10,("Got message saying pcap was updated. Reloading.\n")); | |
308 | - change_to_root_user(); | |
309 | - reload_printers(ev_ctx, msg); | |
310 | -} | |
311 | - | |
312 | static void smbd_sig_term_handler(struct tevent_context *ev, | |
313 | struct tevent_signal *se, | |
314 | int signum, | |
315 | @@ -1287,10 +1269,11 @@ extern void build_options(bool screen); | |
316 | ||
317 | if (is_daemon && !interactive | |
318 | && lp_parm_bool(-1, "smbd", "backgroundqueue", true)) { | |
319 | - /* background queue is responsible for printcap cache updates */ | |
320 | - messaging_register(smbd_server_conn->msg_ctx, | |
321 | - smbd_event_context(), | |
322 | - MSG_PRINTER_PCAP, smb_pcap_updated); | |
323 | + /* | |
324 | + * background queue is responsible for printcap cache updates. | |
325 | + * Other smbd processes only reload printers when a client | |
326 | + * issues an enumeration request. | |
327 | + */ | |
328 | start_background_queue(server_event_context(), | |
329 | smbd_server_conn->msg_ctx); | |
330 | } else { | |
331 | -- | |
332 | 2.1.0 | |
333 | ||
334 | ||
335 | From 52196380547dde4784e42c35c46135bb5230a08d Mon Sep 17 00:00:00 2001 | |
336 | From: David Disseldorp <ddiss@samba.org> | |
337 | Date: Tue, 22 Jul 2014 20:17:38 +0200 | |
338 | Subject: [PATCH 3/7] PATCHSET18: printing: reload printer_list.tdb from in | |
339 | memory list | |
340 | ||
341 | This will allow in future for a single atomic printer_list.tdb update. | |
342 | ||
343 | Bug: https://bugzilla.samba.org/show_bug.cgi?id=10652 | |
344 | ||
345 | Signed-off-by: David Disseldorp <ddiss@samba.org> | |
346 | --- | |
347 | source3/printing/pcap.c | 26 +++++++++++--------------- | |
348 | source3/printing/pcap.h | 8 ++++---- | |
349 | source3/printing/print_aix.c | 17 ++++++++++++++--- | |
350 | source3/printing/print_iprint.c | 16 ++++++++++------ | |
351 | source3/printing/print_standard.c | 8 ++++++-- | |
352 | source3/printing/print_svid.c | 11 +++++++---- | |
353 | 6 files changed, 52 insertions(+), 34 deletions(-) | |
354 | ||
355 | diff --git a/source3/printing/pcap.c b/source3/printing/pcap.c | |
356 | index 6ad8e33..5173fc9 100644 | |
357 | --- a/source3/printing/pcap.c | |
358 | +++ b/source3/printing/pcap.c | |
359 | @@ -83,7 +83,7 @@ void pcap_cache_destroy_specific(struct pcap_cache **pp_cache) | |
360 | *pp_cache = NULL; | |
361 | } | |
362 | ||
363 | -bool pcap_cache_add(const char *name, const char *comment, const char *location) | |
364 | +static bool pcap_cache_add(const char *name, const char *comment, const char *location) | |
365 | { | |
366 | NTSTATUS status; | |
367 | time_t t = time_mono(NULL); | |
368 | @@ -132,8 +132,8 @@ void pcap_cache_reload(struct tevent_context *ev, | |
369 | { | |
370 | const char *pcap_name = lp_printcapname(); | |
371 | bool pcap_reloaded = False; | |
372 | - NTSTATUS status; | |
373 | bool post_cache_fill_fn_handled = false; | |
374 | + struct pcap_cache *pcache = NULL; | |
375 | ||
376 | DEBUG(3, ("reloading printcap cache\n")); | |
377 | ||
378 | @@ -143,12 +143,6 @@ void pcap_cache_reload(struct tevent_context *ev, | |
379 | return; | |
380 | } | |
381 | ||
382 | - status = printer_list_mark_reload(); | |
383 | - if (!NT_STATUS_IS_OK(status)) { | |
384 | - DEBUG(0, ("Failed to mark printer list for reload!\n")); | |
385 | - return; | |
386 | - } | |
387 | - | |
388 | #ifdef HAVE_CUPS | |
389 | if (strequal(pcap_name, "cups")) { | |
390 | pcap_reloaded = cups_cache_reload(ev, msg_ctx, | |
391 | @@ -164,26 +158,26 @@ void pcap_cache_reload(struct tevent_context *ev, | |
392 | ||
393 | #ifdef HAVE_IPRINT | |
394 | if (strequal(pcap_name, "iprint")) { | |
395 | - pcap_reloaded = iprint_cache_reload(); | |
396 | + pcap_reloaded = iprint_cache_reload(&pcache); | |
397 | goto done; | |
398 | } | |
399 | #endif | |
400 | ||
401 | #if defined(SYSV) || defined(HPUX) | |
402 | if (strequal(pcap_name, "lpstat")) { | |
403 | - pcap_reloaded = sysv_cache_reload(); | |
404 | + pcap_reloaded = sysv_cache_reload(&pcache); | |
405 | goto done; | |
406 | } | |
407 | #endif | |
408 | ||
409 | #ifdef AIX | |
410 | if (strstr_m(pcap_name, "/qconfig") != NULL) { | |
411 | - pcap_reloaded = aix_cache_reload(); | |
412 | + pcap_reloaded = aix_cache_reload(&pcache); | |
413 | goto done; | |
414 | } | |
415 | #endif | |
416 | ||
417 | - pcap_reloaded = std_pcap_cache_reload(pcap_name); | |
418 | + pcap_reloaded = std_pcap_cache_reload(pcap_name, &pcache); | |
419 | ||
420 | done: | |
421 | DEBUG(3, ("reload status: %s\n", (pcap_reloaded) ? "ok" : "error")); | |
422 | @@ -192,14 +186,16 @@ done: | |
423 | /* cleanup old entries only if the operation was successful, | |
424 | * otherwise keep around the old entries until we can | |
425 | * successfuly reaload */ | |
426 | - status = printer_list_clean_old(); | |
427 | - if (!NT_STATUS_IS_OK(status)) { | |
428 | - DEBUG(0, ("Failed to cleanup printer list!\n")); | |
429 | + | |
430 | + if (!pcap_cache_replace(pcache)) { | |
431 | + DEBUG(0, ("Failed to replace printer list!\n")); | |
432 | } | |
433 | + | |
434 | if (post_cache_fill_fn != NULL) { | |
435 | post_cache_fill_fn(ev, msg_ctx); | |
436 | } | |
437 | } | |
438 | + pcap_cache_destroy_specific(&pcache); | |
439 | ||
440 | return; | |
441 | } | |
442 | diff --git a/source3/printing/pcap.h b/source3/printing/pcap.h | |
443 | index 6c062c3..d388d7d 100644 | |
444 | --- a/source3/printing/pcap.h | |
445 | +++ b/source3/printing/pcap.h | |
446 | @@ -49,7 +49,7 @@ bool pcap_printername_ok(const char *printername); | |
447 | ||
448 | /* The following definitions come from printing/print_aix.c */ | |
449 | ||
450 | -bool aix_cache_reload(void); | |
451 | +bool aix_cache_reload(struct pcap_cache **_pcache); | |
452 | ||
453 | /* The following definitions come from printing/print_cups.c */ | |
454 | ||
455 | @@ -60,13 +60,13 @@ bool cups_cache_reload(struct tevent_context *ev, | |
456 | ||
457 | /* The following definitions come from printing/print_iprint.c */ | |
458 | ||
459 | -bool iprint_cache_reload(void); | |
460 | +bool iprint_cache_reload(struct pcap_cache **_pcache); | |
461 | ||
462 | /* The following definitions come from printing/print_svid.c */ | |
463 | ||
464 | -bool sysv_cache_reload(void); | |
465 | +bool sysv_cache_reload(struct pcap_cache **_pcache); | |
466 | ||
467 | /* The following definitions come from printing/print_standard.c */ | |
468 | -bool std_pcap_cache_reload(const char *pcap_name); | |
469 | +bool std_pcap_cache_reload(const char *pcap_name, struct pcap_cache **_pcache); | |
470 | ||
471 | #endif /* _PRINTING_PCAP_H_ */ | |
472 | diff --git a/source3/printing/print_aix.c b/source3/printing/print_aix.c | |
473 | index 23d9a86..927a71b 100644 | |
474 | --- a/source3/printing/print_aix.c | |
475 | +++ b/source3/printing/print_aix.c | |
476 | @@ -29,12 +29,13 @@ | |
477 | #include "printing/pcap.h" | |
478 | ||
479 | #ifdef AIX | |
480 | -bool aix_cache_reload(void) | |
481 | +bool aix_cache_reload(struct pcap_cache **_pcache) | |
482 | { | |
483 | int iEtat; | |
484 | XFILE *pfile; | |
485 | char *line = NULL, *p; | |
486 | char *name = NULL; | |
487 | + struct pcap_cache *pcache = NULL; | |
488 | TALLOC_CTX *ctx = talloc_init("aix_cache_reload"); | |
489 | ||
490 | if (!ctx) { | |
491 | @@ -52,6 +53,8 @@ bool aix_cache_reload(void) | |
492 | iEtat = 0; | |
493 | /* scan qconfig file for searching <printername>: */ | |
494 | for (;(line = fgets_slash(NULL, 1024, pfile)); free(line)) { | |
495 | + bool ok; | |
496 | + | |
497 | if (*line == '*' || *line == 0) | |
498 | continue; | |
499 | ||
500 | @@ -67,6 +70,7 @@ bool aix_cache_reload(void) | |
501 | if (strcmp(p, "bsh") != 0) { | |
502 | name = talloc_strdup(ctx, p); | |
503 | if (!name) { | |
504 | + pcap_cache_destroy_specific(&pcache); | |
505 | SAFE_FREE(line); | |
506 | x_fclose(pfile); | |
507 | TALLOC_FREE(ctx); | |
508 | @@ -86,7 +90,10 @@ bool aix_cache_reload(void) | |
509 | /* name is found without stanza device */ | |
510 | /* probably a good printer ??? */ | |
511 | iEtat = 0; | |
512 | - if (!pcap_cache_add(name, NULL, NULL)) { | |
513 | + ok = pcap_cache_add_specific(&pcache, | |
514 | + name, NULL, NULL); | |
515 | + if (!ok) { | |
516 | + pcap_cache_destroy_specific(&pcache); | |
517 | SAFE_FREE(line); | |
518 | x_fclose(pfile); | |
519 | TALLOC_FREE(ctx); | |
520 | @@ -101,7 +108,10 @@ bool aix_cache_reload(void) | |
521 | } else if (strstr_m(line, "device")) { | |
522 | /* it's a good virtual printer */ | |
523 | iEtat = 0; | |
524 | - if (!pcap_cache_add(name, NULL, NULL)) { | |
525 | + ok = pcap_cache_add_specific(&pcache, | |
526 | + name, NULL, NULL); | |
527 | + if (!ok) { | |
528 | + pcap_cache_destroy_specific(&pcache); | |
529 | SAFE_FREE(line); | |
530 | x_fclose(pfile); | |
531 | TALLOC_FREE(ctx); | |
532 | @@ -113,6 +123,7 @@ bool aix_cache_reload(void) | |
533 | } | |
534 | } | |
535 | ||
536 | + *_pcache = pcache; | |
537 | x_fclose(pfile); | |
538 | TALLOC_FREE(ctx); | |
539 | return true; | |
540 | diff --git a/source3/printing/print_iprint.c b/source3/printing/print_iprint.c | |
541 | index 529f0dd..6e91747 100644 | |
542 | --- a/source3/printing/print_iprint.c | |
543 | +++ b/source3/printing/print_iprint.c | |
544 | @@ -204,7 +204,8 @@ static int iprint_get_server_version(http_t *http, char* serviceUri) | |
545 | ||
546 | static int iprint_cache_add_printer(http_t *http, | |
547 | int reqId, | |
548 | - char* url) | |
549 | + char *url, | |
550 | + struct pcap_cache **pcache) | |
551 | { | |
552 | ipp_t *request = NULL, /* IPP Request */ | |
553 | *response = NULL; /* IPP Response */ | |
554 | @@ -340,7 +341,7 @@ static int iprint_cache_add_printer(http_t *http, | |
555 | */ | |
556 | ||
557 | if (name != NULL && !secure && smb_enabled) | |
558 | - pcap_cache_add(name, info, NULL); | |
559 | + pcap_cache_add_specific(pcache, name, info, NULL); | |
560 | } | |
561 | ||
562 | out: | |
563 | @@ -349,7 +350,7 @@ static int iprint_cache_add_printer(http_t *http, | |
564 | return(0); | |
565 | } | |
566 | ||
567 | -bool iprint_cache_reload(void) | |
568 | +bool iprint_cache_reload(struct pcap_cache **_pcache) | |
569 | { | |
570 | http_t *http = NULL; /* HTTP connection to server */ | |
571 | ipp_t *request = NULL, /* IPP Request */ | |
572 | @@ -357,7 +358,8 @@ bool iprint_cache_reload(void) | |
573 | ipp_attribute_t *attr; /* Current attribute */ | |
574 | cups_lang_t *language = NULL; /* Default language */ | |
575 | int i; | |
576 | - bool ret = False; | |
577 | + bool ret = false; | |
578 | + struct pcap_cache *pcache = NULL; | |
579 | ||
580 | DEBUG(5, ("reloading iprint printcap cache\n")); | |
581 | ||
582 | @@ -439,14 +441,16 @@ bool iprint_cache_reload(void) | |
583 | char *url = ippGetString(attr, i, NULL); | |
584 | if (!url || !strlen(url)) | |
585 | continue; | |
586 | - iprint_cache_add_printer(http, i+2, url); | |
587 | + iprint_cache_add_printer(http, i+2, url, | |
588 | + &pcache); | |
589 | } | |
590 | } | |
591 | attr = ippNextAttribute(response); | |
592 | } | |
593 | } | |
594 | ||
595 | - ret = True; | |
596 | + ret = true; | |
597 | + *_pcache = pcache; | |
598 | ||
599 | out: | |
600 | if (response) | |
601 | diff --git a/source3/printing/print_standard.c b/source3/printing/print_standard.c | |
602 | index c4f9c5b..b5f1056 100644 | |
603 | --- a/source3/printing/print_standard.c | |
604 | +++ b/source3/printing/print_standard.c | |
605 | @@ -59,10 +59,11 @@ | |
606 | #include "printing/pcap.h" | |
607 | ||
608 | /* handle standard printcap - moved from pcap_printer_fn() */ | |
609 | -bool std_pcap_cache_reload(const char *pcap_name) | |
610 | +bool std_pcap_cache_reload(const char *pcap_name, struct pcap_cache **_pcache) | |
611 | { | |
612 | XFILE *pcap_file; | |
613 | char *pcap_line; | |
614 | + struct pcap_cache *pcache = NULL; | |
615 | ||
616 | if ((pcap_file = x_fopen(pcap_name, O_RDONLY, 0)) == NULL) { | |
617 | DEBUG(0, ("Unable to open printcap file %s for read!\n", pcap_name)); | |
618 | @@ -117,12 +118,15 @@ bool std_pcap_cache_reload(const char *pcap_name) | |
619 | } | |
620 | } | |
621 | ||
622 | - if (*name && !pcap_cache_add(name, comment, NULL)) { | |
623 | + if ((*name != '\0') | |
624 | + && !pcap_cache_add_specific(&pcache, name, comment, NULL)) { | |
625 | x_fclose(pcap_file); | |
626 | + pcap_cache_destroy_specific(&pcache); | |
627 | return false; | |
628 | } | |
629 | } | |
630 | ||
631 | x_fclose(pcap_file); | |
632 | + *_pcache = pcache; | |
633 | return true; | |
634 | } | |
635 | diff --git a/source3/printing/print_svid.c b/source3/printing/print_svid.c | |
636 | index 2226493..879661b 100644 | |
637 | --- a/source3/printing/print_svid.c | |
638 | +++ b/source3/printing/print_svid.c | |
639 | @@ -35,10 +35,11 @@ | |
640 | #include "printing/pcap.h" | |
641 | ||
642 | #if defined(SYSV) || defined(HPUX) | |
643 | -bool sysv_cache_reload(void) | |
644 | +bool sysv_cache_reload(struct pcap_cache **_pcache) | |
645 | { | |
646 | char **lines; | |
647 | int i; | |
648 | + struct pcap_cache *pcache = NULL; | |
649 | ||
650 | #if defined(HPUX) | |
651 | DEBUG(5, ("reloading hpux printcap cache\n")); | |
652 | @@ -111,14 +112,16 @@ bool sysv_cache_reload(void) | |
653 | *tmp = '\0'; | |
654 | ||
655 | /* add it to the cache */ | |
656 | - if (!pcap_cache_add(name, NULL, NULL)) { | |
657 | + if (!pcap_cache_add_specific(&pcache, name, NULL, NULL)) { | |
658 | TALLOC_FREE(lines); | |
659 | - return False; | |
660 | + pcap_cache_destroy_specific(&pcache); | |
661 | + return false; | |
662 | } | |
663 | } | |
664 | ||
665 | TALLOC_FREE(lines); | |
666 | - return True; | |
667 | + *_pcache = pcache; | |
668 | + return true; | |
669 | } | |
670 | ||
671 | #else | |
672 | -- | |
673 | 2.1.0 | |
674 | ||
675 | ||
676 | From 91c0b6477fcd4ad20d1cda45f78f160cee8e58ff Mon Sep 17 00:00:00 2001 | |
677 | From: David Disseldorp <ddiss@samba.org> | |
678 | Date: Fri, 25 Jul 2014 12:18:54 +0200 | |
679 | Subject: [PATCH 4/7] PATCHSET18: printing: remove pcap_cache_add() | |
680 | ||
681 | All print list updates are now done via pcap_cache_replace(), which can | |
682 | call into the print_list code directly. | |
683 | ||
684 | Bug: https://bugzilla.samba.org/show_bug.cgi?id=10652 | |
685 | ||
686 | Signed-off-by: David Disseldorp <ddiss@samba.org> | |
687 | --- | |
688 | source3/printing/pcap.c | 16 ++++++---------- | |
689 | source3/printing/pcap.h | 1 - | |
690 | 2 files changed, 6 insertions(+), 11 deletions(-) | |
691 | ||
692 | diff --git a/source3/printing/pcap.c b/source3/printing/pcap.c | |
693 | index 5173fc9..5059f20 100644 | |
694 | --- a/source3/printing/pcap.c | |
695 | +++ b/source3/printing/pcap.c | |
696 | @@ -83,15 +83,6 @@ void pcap_cache_destroy_specific(struct pcap_cache **pp_cache) | |
697 | *pp_cache = NULL; | |
698 | } | |
699 | ||
700 | -static bool pcap_cache_add(const char *name, const char *comment, const char *location) | |
701 | -{ | |
702 | - NTSTATUS status; | |
703 | - time_t t = time_mono(NULL); | |
704 | - | |
705 | - status = printer_list_set_printer(talloc_tos(), name, comment, location, t); | |
706 | - return NT_STATUS_IS_OK(status); | |
707 | -} | |
708 | - | |
709 | bool pcap_cache_loaded(void) | |
710 | { | |
711 | NTSTATUS status; | |
712 | @@ -105,6 +96,7 @@ bool pcap_cache_replace(const struct pcap_cache *pcache) | |
713 | { | |
714 | const struct pcap_cache *p; | |
715 | NTSTATUS status; | |
716 | + time_t t = time_mono(NULL); | |
717 | ||
718 | status = printer_list_mark_reload(); | |
719 | if (!NT_STATUS_IS_OK(status)) { | |
720 | @@ -113,7 +105,11 @@ bool pcap_cache_replace(const struct pcap_cache *pcache) | |
721 | } | |
722 | ||
723 | for (p = pcache; p; p = p->next) { | |
724 | - pcap_cache_add(p->name, p->comment, p->location); | |
725 | + status = printer_list_set_printer(talloc_tos(), p->name, | |
726 | + p->comment, p->location, t); | |
727 | + if (!NT_STATUS_IS_OK(status)) { | |
728 | + return false; | |
729 | + } | |
730 | } | |
731 | ||
732 | status = printer_list_clean_old(); | |
733 | diff --git a/source3/printing/pcap.h b/source3/printing/pcap.h | |
734 | index d388d7d..7dccf84 100644 | |
735 | --- a/source3/printing/pcap.h | |
736 | +++ b/source3/printing/pcap.h | |
737 | @@ -35,7 +35,6 @@ struct pcap_cache; | |
738 | ||
739 | bool pcap_cache_add_specific(struct pcap_cache **ppcache, const char *name, const char *comment, const char *location); | |
740 | void pcap_cache_destroy_specific(struct pcap_cache **ppcache); | |
741 | -bool pcap_cache_add(const char *name, const char *comment, const char *location); | |
742 | bool pcap_cache_loaded(void); | |
743 | bool pcap_cache_replace(const struct pcap_cache *cache); | |
744 | void pcap_printer_fn_specific(const struct pcap_cache *, void (*fn)(const char *, const char *, const char *, void *), void *); | |
745 | -- | |
746 | 2.1.0 | |
747 | ||
748 | ||
749 | From 10582491e417d5ab5c77afe2337793dbacd98fa8 Mon Sep 17 00:00:00 2001 | |
750 | From: David Disseldorp <ddiss@samba.org> | |
751 | Date: Wed, 23 Jul 2014 12:12:34 +0200 | |
752 | Subject: [PATCH 5/7] PATCHSET18: printing: return last change time with | |
753 | pcap_cache_loaded() | |
754 | ||
755 | Bug: https://bugzilla.samba.org/show_bug.cgi?id=10652 | |
756 | ||
757 | Signed-off-by: David Disseldorp <ddiss@samba.org> | |
758 | --- | |
759 | source3/printing/load.c | 2 +- | |
760 | source3/printing/pcap.c | 10 ++++++++-- | |
761 | source3/printing/pcap.h | 2 +- | |
762 | source3/web/swat.c | 4 ++-- | |
763 | 4 files changed, 12 insertions(+), 6 deletions(-) | |
764 | ||
765 | diff --git a/source3/printing/load.c b/source3/printing/load.c | |
766 | index 0a3de73..83f1095 100644 | |
767 | --- a/source3/printing/load.c | |
768 | +++ b/source3/printing/load.c | |
769 | @@ -64,7 +64,7 @@ load automatic printer services from pre-populated pcap cache | |
770 | void load_printers(struct tevent_context *ev, | |
771 | struct messaging_context *msg_ctx) | |
772 | { | |
773 | - SMB_ASSERT(pcap_cache_loaded()); | |
774 | + SMB_ASSERT(pcap_cache_loaded(NULL)); | |
775 | ||
776 | add_auto_printers(); | |
777 | ||
778 | diff --git a/source3/printing/pcap.c b/source3/printing/pcap.c | |
779 | index 5059f20..027c1b2 100644 | |
780 | --- a/source3/printing/pcap.c | |
781 | +++ b/source3/printing/pcap.c | |
782 | @@ -83,13 +83,19 @@ void pcap_cache_destroy_specific(struct pcap_cache **pp_cache) | |
783 | *pp_cache = NULL; | |
784 | } | |
785 | ||
786 | -bool pcap_cache_loaded(void) | |
787 | +bool pcap_cache_loaded(time_t *_last_change) | |
788 | { | |
789 | NTSTATUS status; | |
790 | time_t last; | |
791 | ||
792 | status = printer_list_get_last_refresh(&last); | |
793 | - return NT_STATUS_IS_OK(status); | |
794 | + if (!NT_STATUS_IS_OK(status)) { | |
795 | + return false; | |
796 | + } | |
797 | + if (_last_change != NULL) { | |
798 | + *_last_change = last; | |
799 | + } | |
800 | + return true; | |
801 | } | |
802 | ||
803 | bool pcap_cache_replace(const struct pcap_cache *pcache) | |
804 | diff --git a/source3/printing/pcap.h b/source3/printing/pcap.h | |
805 | index 7dccf84..8fc9e9d 100644 | |
806 | --- a/source3/printing/pcap.h | |
807 | +++ b/source3/printing/pcap.h | |
808 | @@ -35,7 +35,7 @@ struct pcap_cache; | |
809 | ||
810 | bool pcap_cache_add_specific(struct pcap_cache **ppcache, const char *name, const char *comment, const char *location); | |
811 | void pcap_cache_destroy_specific(struct pcap_cache **ppcache); | |
812 | -bool pcap_cache_loaded(void); | |
813 | +bool pcap_cache_loaded(time_t *_last_change); | |
814 | bool pcap_cache_replace(const struct pcap_cache *cache); | |
815 | void pcap_printer_fn_specific(const struct pcap_cache *, void (*fn)(const char *, const char *, const char *, void *), void *); | |
816 | void pcap_printer_read_fn(void (*fn)(const char *, const char *, const char *, void *), void *); | |
817 | diff --git a/source3/web/swat.c b/source3/web/swat.c | |
818 | index f8933d2..a1a035c 100644 | |
819 | --- a/source3/web/swat.c | |
820 | +++ b/source3/web/swat.c | |
821 | @@ -586,7 +586,7 @@ static int save_reload(int snum) | |
822 | return 0; | |
823 | } | |
824 | iNumNonAutoPrintServices = lp_numservices(); | |
825 | - if (pcap_cache_loaded()) { | |
826 | + if (pcap_cache_loaded(NULL)) { | |
827 | load_printers(server_event_context(), | |
828 | server_messaging_context()); | |
829 | } | |
830 | @@ -1572,7 +1572,7 @@ const char *lang_msg_rotate(TALLOC_CTX *ctx, const char *msgid) | |
831 | reopen_logs(); | |
832 | load_interfaces(); | |
833 | iNumNonAutoPrintServices = lp_numservices(); | |
834 | - if (pcap_cache_loaded()) { | |
835 | + if (pcap_cache_loaded(NULL)) { | |
836 | load_printers(server_event_context(), | |
837 | server_messaging_context()); | |
838 | } | |
839 | -- | |
840 | 2.1.0 | |
841 | ||
842 | ||
843 | From 484667ff73b54b275f8629264aef27ec9628c7fd Mon Sep 17 00:00:00 2001 | |
844 | From: David Disseldorp <ddiss@samba.org> | |
845 | Date: Wed, 23 Jul 2014 14:42:00 +0200 | |
846 | Subject: [PATCH 6/7] PATCHSET18: smbd: only reprocess printer_list.tdb if it | |
847 | changed | |
848 | ||
849 | The per-client smbd printer share inventory is currently updated from | |
850 | printer_list.tdb when a client enumerates printers, via EnumPrinters or | |
851 | NetShareEnum. | |
852 | printer_list.tdb is populated by the background print process, based on | |
853 | the latest printcap values retrieved from the printing backend (e.g. | |
854 | CUPS) at regular intervals. | |
855 | This change ensures that per-client smbd processes don't reparse | |
856 | printer_list.tdb if it hasn't been updated since the last enumeration. | |
857 | ||
858 | Bug: https://bugzilla.samba.org/show_bug.cgi?id=10652 | |
859 | ||
860 | Suggested-by: Volker Lendecke <vl@samba.org> | |
861 | Signed-off-by: David Disseldorp <ddiss@samba.org> | |
862 | --- | |
863 | source3/smbd/server_reload.c | 21 +++++++++++++++++++++ | |
864 | 1 file changed, 21 insertions(+) | |
865 | ||
866 | diff --git a/source3/smbd/server_reload.c b/source3/smbd/server_reload.c | |
867 | index c4c5a8d..57f7972 100644 | |
868 | --- a/source3/smbd/server_reload.c | |
869 | +++ b/source3/smbd/server_reload.c | |
870 | @@ -30,6 +30,13 @@ | |
871 | #include "auth.h" | |
872 | #include "messages.h" | |
873 | ||
874 | +/* | |
875 | + * The persistent pcap cache is populated by the background print process. Per | |
876 | + * client smbds should only reload their printer share inventories if this | |
877 | + * information has changed. Use last_reload_time to detect this. | |
878 | + */ | |
879 | +static time_t reload_last_pcap_time = 0; | |
880 | + | |
881 | /**************************************************************************** | |
882 | purge stale printers and reload from pre-populated pcap cache | |
883 | **************************************************************************/ | |
884 | @@ -40,6 +47,20 @@ void reload_printers(struct tevent_context *ev, | |
885 | int pnum; | |
886 | int snum; | |
887 | const char *pname; | |
888 | + bool ok; | |
889 | + time_t pcap_last_update; | |
890 | + | |
891 | + ok = pcap_cache_loaded(&pcap_last_update); | |
892 | + if (!ok) { | |
893 | + DEBUG(1, ("pcap cache not loaded\n")); | |
894 | + return; | |
895 | + } | |
896 | + | |
897 | + if (reload_last_pcap_time == pcap_last_update) { | |
898 | + DEBUG(5, ("skipping printer reload, already up to date.\n")); | |
899 | + return; | |
900 | + } | |
901 | + reload_last_pcap_time = pcap_last_update; | |
902 | ||
903 | n_services = lp_numservices(); | |
904 | pnum = lp_servicenumber(PRINTERS_NAME); | |
905 | -- | |
906 | 2.1.0 | |
907 | ||
908 | ||
909 | From 08848f939b735b5a68066ebcc995247d77f5fa2d Mon Sep 17 00:00:00 2001 | |
910 | From: David Disseldorp <ddiss@samba.org> | |
911 | Date: Wed, 6 Aug 2014 14:33:02 +0200 | |
912 | Subject: [PATCH 7/7] PATCHSET18: printing: reload printer shares on | |
913 | OpenPrinter | |
914 | ||
915 | The printer share inventory should be reloaded on open _and_ | |
916 | enumeration, as there are some clients, such as cupsaddsmb, that do not | |
917 | perform an enumeration prior to access. | |
918 | ||
919 | Bug: https://bugzilla.samba.org/show_bug.cgi?id=10652 | |
920 | ||
921 | Signed-off-by: David Disseldorp <ddiss@samba.org> | |
922 | --- | |
923 | source3/rpc_server/spoolss/srv_spoolss_nt.c | 12 +++++++++++- | |
924 | 1 file changed, 11 insertions(+), 1 deletion(-) | |
925 | ||
926 | diff --git a/source3/rpc_server/spoolss/srv_spoolss_nt.c b/source3/rpc_server/spoolss/srv_spoolss_nt.c | |
927 | index db48574..fb8f61f 100644 | |
928 | --- a/source3/rpc_server/spoolss/srv_spoolss_nt.c | |
929 | +++ b/source3/rpc_server/spoolss/srv_spoolss_nt.c | |
930 | @@ -1737,6 +1737,16 @@ WERROR _spoolss_OpenPrinterEx(struct pipes_struct *p, | |
931 | return WERR_INVALID_PARAM; | |
932 | } | |
933 | ||
934 | + /* | |
935 | + * The printcap printer share inventory is updated on client | |
936 | + * enumeration. For clients that do not perform enumeration prior to | |
937 | + * access, such as cupssmbadd, we reinitialise the printer share | |
938 | + * inventory on open as well. | |
939 | + */ | |
940 | + become_root(); | |
941 | + reload_printers(messaging_event_context(p->msg_ctx), p->msg_ctx); | |
942 | + unbecome_root(); | |
943 | + | |
944 | /* some sanity check because you can open a printer or a print server */ | |
945 | /* aka: \\server\printer or \\server */ | |
946 | ||
947 | @@ -4323,7 +4333,7 @@ static WERROR enum_all_printers_info_level(TALLOC_CTX *mem_ctx, | |
948 | struct dcerpc_binding_handle *b = NULL; | |
949 | ||
950 | /* | |
951 | - * printer shares are only updated on client enumeration. The background | |
952 | + * printer shares are updated on client enumeration. The background | |
953 | * printer process updates printer_list.tdb at regular intervals. | |
954 | */ | |
955 | become_root(); | |
956 | -- | |
957 | 2.1.0 | |
958 |