2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-29 13:18:12 +00:00

postfix-2.5.7

This commit is contained in:
Wietse Venema 2009-05-12 00:00:00 -05:00 committed by Viktor Dukhovni
parent 575d50e0e3
commit 9dd2815512
16 changed files with 172 additions and 52 deletions

View File

@ -14469,3 +14469,48 @@ Apologies for any names omitted.
Documentation: log the "*" pattern as the last transport
map lookup. File: proto/transport.
20090122
Bugfix: the data_directory was not automatically created!
File: conf/postfix-files.
20090304
Cleanup: skip over suspended or throttled queues while
looking for delivery requests. File: *qmgr/qmgr_transport.c.
20090305
Bugfix: in the "new queue manager", the _destination_rate_delay
code needed to postpone the job scheduler updates after
delivery completion, otherwise the scheduler could loop on
blocked jobs. Victor & Wietse. File: qmgr/qmgr_entry.c,
qmgr/qmgr_queue.c, qmgr/qmgr_job.c.
Cleanup: report a "queue file write error", instead of
passing though bogus 2xx replies from proxy filters to SMTP
clients. File: smtpd/smtpd_proxy.c.
20090310
Bugfix: Postfix used mumble_concurrency_failed_cohort_limit
instead of mumble_destination_concurrency_failed_cohort_limit
as documented. File: global/mail_params.h.
20090419
Bugfix: don't re-enable SIGHUP if it is ignored in the
parent. This may cause random "Postfix integrity check
failed" errors at boot time (POSIX SIGHUP death), causing
Postfix not to start. We duplicate code from postdrop and
thus avoid past mistakes. File: postsuper/postsuper.c.
Robustness: don't re-enable SIGTERM if it is ignored in the
parent. Files: postsuper/postsuper.c, postdrop/postdrop.c.
20090428
Bugfix: don't disable MIME parsing with smtp_header_checks,
smtp_mime_header_checks, smtp_nested_header_checks or with
smtp_body_checks. Bug reported by Victor. File: smtp/smtp_proto.c.

View File

@ -42,7 +42,7 @@
# permissions, so that running "make install" fixes any glitches.
#
$config_directory:d:root:-:755:u
$data_directory:d:$mail_owner:-:700:u
$data_directory:d:$mail_owner:-:700:uc
$daemon_directory:d:root:-:755:u
$queue_directory:d:root:-:755:uc
$sample_directory:d:root:-:755:o

View File

@ -1792,7 +1792,7 @@ is decremented by 1 after each failed pseudo-cohort. </dd>
<p> A pseudo-cohort is the number of deliveries equal to a destination's
delivery concurrency. </p>
<p> Use <a href="postconf.5.html#transport_destination_concurrency_positive_feedback"><i>transport</i>_destination_concurrency_negative_feedback</a>
<p> Use <a href="postconf.5.html#transport_destination_concurrency_negative_feedback"><i>transport</i>_destination_concurrency_negative_feedback</a>
to specify a transport-specific override, where <i>transport</i>
is the <a href="master.5.html">master.cf</a>
name of the message delivery transport. </p>
@ -3718,7 +3718,7 @@ client, for example:
<blockquote>
<pre>
/etc/postfix/<a href="master.5.html">master.cf</a>:
mylmtp ... lmtp -o <a href="postconf.5.html#lmtp_lhloname">lmtp_lhlo_name</a>=foo.bar.com
mylmtp ... lmtp -o <a href="postconf.5.html#lmtp_lhlo_name">lmtp_lhlo_name</a>=foo.bar.com
</pre>
</blockquote>

View File

@ -254,7 +254,7 @@ while (<>) {
s;\blmtp_tls_note_starttls_offer\b;<a href="postconf.5.html#lmtp_tls_note_starttls_offer">$&</a>;g;
s;\blmtp_sender_dependent_authentication\b;<a href="postconf.5.html#lmtp_sender_dependent_authentication">$&</a>;g;
s;\blmtp_sasl_path\b;<a href="postconf.5.html#lmtp_sasl_path">$&</a>;g;
s;\blmtp_lhlo_name\b;<a href="postconf.5.html#lmtp_lhloname">$&</a>;g;
s;\blmtp_lhlo_name\b;<a href="postconf.5.html#lmtp_lhlo_name">$&</a>;g;
s;\blmtp_connect_timeout\b;<a href="postconf.5.html#lmtp_connect_timeout">$&</a>;g;
s;\blmtp_data_done_timeout\b;<a href="postconf.5.html#lmtp_data_done_timeout">$&</a>;g;
s;\blmtp_data_init_timeout\b;<a href="postconf.5.html#lmtp_data_init_timeout">$&</a>;g;
@ -636,7 +636,7 @@ while (<>) {
# Transport-dependent magical parameters.
s;(<i>transport</i>)(<b>)?(_destination_concurrency_failed_cohort_limit)\b;$2<a href="postconf.5.html#transport_destination_concurrency_failed_cohort_limit">$1$3</a>;g;
s;(<i>transport</i>)(<b>)?(_destination_concurrency_negative_feedback)\b;$2<a href="postconf.5.html#transport_destination_concurrency_positive_feedback">$1$3</a>;g;
s;(<i>transport</i>)(<b>)?(_destination_concurrency_negative_feedback)\b;$2<a href="postconf.5.html#transport_destination_concurrency_negative_feedback">$1$3</a>;g;
s;(<i>transport</i>)(<b>)?(_destination_concurrency_positive_feedback)\b;$2<a href="postconf.5.html#transport_destination_concurrency_positive_feedback">$1$3</a>;g;
s;(<i>transport</i>)(<b>)?(_delivery_slot_cost)\b;$2<a href="postconf.5.html#transport_delivery_slot_cost">$1$3</a>;g;
s;(<i>transport</i>)(<b>)?(_delivery_slot_discount)\b;$2<a href="postconf.5.html#transport_delivery_slot_discount">$1$3</a>;g;

View File

@ -2899,12 +2899,12 @@ extern char *var_smtp_body_chks;
* Scheduler concurrency feedback algorithms.
*/
#define VAR_CONC_POS_FDBACK "default_destination_concurrency_positive_feedback"
#define _CONC_POS_FDBACK "_concurrency_positive_feedback"
#define _CONC_POS_FDBACK "_destination_concurrency_positive_feedback"
#define DEF_CONC_POS_FDBACK "1"
extern char *var_conc_pos_feedback;
#define VAR_CONC_NEG_FDBACK "default_destination_concurrency_negative_feedback"
#define _CONC_NEG_FDBACK "_concurrency_negative_feedback"
#define _CONC_NEG_FDBACK "_destination_concurrency_negative_feedback"
#define DEF_CONC_NEG_FDBACK "1"
extern char *var_conc_neg_feedback;
@ -2912,7 +2912,7 @@ extern char *var_conc_neg_feedback;
#define CONC_FDBACK_NAME_SQRT_WIN "sqrt_concurrency"
#define VAR_CONC_COHORT_LIM "default_destination_concurrency_failed_cohort_limit"
#define _CONC_COHORT_LIM "_concurrency_failed_cohort_limit"
#define _CONC_COHORT_LIM "_destination_concurrency_failed_cohort_limit"
#define DEF_CONC_COHORT_LIM 1
extern int var_conc_cohort_limit;

View File

@ -20,8 +20,8 @@
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
#define MAIL_RELEASE_DATE "20090103"
#define MAIL_VERSION_NUMBER "2.5.6"
#define MAIL_RELEASE_DATE "20090512"
#define MAIL_VERSION_NUMBER "2.5.7"
#ifdef SNAPSHOT
# define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE

View File

@ -286,6 +286,8 @@ QMGR_TRANSPORT *qmgr_transport_select(void)
continue;
need = xport->pending + 1;
for (queue = xport->queue_list.next; queue; queue = queue->peers.next) {
if (QMGR_QUEUE_READY(queue) == 0)
continue;
if ((need -= MIN5af51743e4eef(queue->window - queue->busy_refcount,
queue->todo_refcount)) <= 0) {
QMGR_LIST_ROTATE(qmgr_transport_list, xport);

View File

@ -340,7 +340,8 @@ int main(int argc, char **argv)
signal(SIGINT, postdrop_sig);
signal(SIGQUIT, postdrop_sig);
signal(SIGTERM, postdrop_sig);
if (signal(SIGTERM, SIG_IGN) == SIG_DFL)
signal(SIGTERM, postdrop_sig);
if (signal(SIGHUP, SIG_IGN) == SIG_DFL)
signal(SIGHUP, postdrop_sig);
msg_cleanup(postdrop_cleanup);

View File

@ -974,11 +974,17 @@ static void interrupted(int sig)
/*
* This commands requires root privileges. We therefore do not worry
* about hostile signals, and report problems via msg_warn().
*
* We use the in-kernel SIGINT handler address as an atomic variable to
* prevent nested interrupted() calls. For this reason, main() must
* configure interrupted() as SIGINT handler before other signal handlers
* are allowed to invoke interrupted(). See also similar code in
* postdrop.
*/
if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
(void) signal(SIGINT, SIG_IGN);
if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
(void) signal(SIGQUIT, SIG_IGN);
(void) signal(SIGTERM, SIG_IGN);
(void) signal(SIGHUP, SIG_IGN);
if (inode_mismatch > 0 || inode_fixed > 0 || position_mismatch > 0)
msg_warn("OPERATION INCOMPLETE -- RERUN COMMAND TO FIX THE QUEUE FIRST");
if (sig)
@ -1175,11 +1181,20 @@ int main(int argc, char **argv)
*
* Set up signal handlers after permanently dropping super-user privileges,
* so that signal handlers will always run with the correct privileges.
*
* XXX Don't enable SIGHUP or SIGTERM if it was ignored by the parent.
*
* interrupted() uses the in-kernel SIGINT handler address as an atomic
* variable to prevent nested interrupted() calls. For this reason, the
* SIGINT handler must be configured before other signal handlers are
* allowed to invoke interrupted(). See also similar code in postdrop.
*/
signal(SIGHUP, interrupted);
signal(SIGINT, interrupted);
signal(SIGQUIT, interrupted);
signal(SIGTERM, interrupted);
if (signal(SIGTERM, SIG_IGN) == SIG_DFL)
signal(SIGTERM, interrupted);
if (signal(SIGHUP, SIG_IGN) == SIG_DFL)
signal(SIGHUP, interrupted);
msg_cleanup(fatal_warning);
/*

View File

@ -436,6 +436,7 @@ struct QMGR_PEER {
extern QMGR_ENTRY *qmgr_job_entry_select(QMGR_TRANSPORT *);
extern QMGR_PEER *qmgr_peer_select(QMGR_JOB *);
extern void qmgr_job_blocker_update(QMGR_QUEUE *);
extern QMGR_JOB *qmgr_job_obtain(QMGR_MESSAGE *, QMGR_TRANSPORT *);
extern void qmgr_job_free(QMGR_JOB *);

View File

@ -299,29 +299,25 @@ void qmgr_entry_done(QMGR_ENTRY *entry, int which)
}
/*
* If the queue was blocking some of the jobs on the job list, check if
* the concurrency limit has lifted. If there are still some pending
* deliveries, give it a try and unmark all transport blockers at once.
* The qmgr_job_entry_select() will do the rest. In either case make sure
* the queue is not marked as a blocker anymore, with extra handling of
* queues which were declared dead.
* We implement a rate-limited queue by emulating a slow delivery
* channel. We insert the artificial delays with qmgr_queue_suspend().
*
* Note that changing the blocker status also affects the candidate cache.
* Most of the cases would be automatically recognized by the current job
* change, but we play safe and reset the cache explicitly below.
*
* Keeping the transport blocker tag odd is an easy way to make sure the tag
* never matches jobs that are not explicitly marked as blockers.
* When a queue is suspended, we must postpone any job scheduling decisions
* until the queue is resumed. Otherwise, we make those decisions now.
* The job scheduling decisions are made by qmgr_job_blocker_update().
*/
if (queue->blocker_tag == transport->blocker_tag) {
if (queue->window > queue->busy_refcount && queue->todo.next != 0) {
transport->blocker_tag += 2;
transport->job_current = transport->job_list.next;
transport->candidate_cache_current = 0;
}
if (queue->window > queue->busy_refcount || QMGR_QUEUE_THROTTLED(queue))
queue->blocker_tag = 0;
if (which == QMGR_QUEUE_BUSY && transport->rate_delay > 0) {
if (queue->window > 1)
msg_panic("%s: queue %s/%s: window %d > 1 on rate-limited service",
myname, transport->name, queue->name, queue->window);
if (QMGR_QUEUE_THROTTLED(queue)) /* XXX */
qmgr_queue_unthrottle(queue);
if (QMGR_QUEUE_READY(queue))
qmgr_queue_suspend(queue, transport->rate_delay);
}
if (!QMGR_QUEUE_SUSPENDED(queue)
&& queue->blocker_tag == transport->blocker_tag)
qmgr_job_blocker_update(queue);
/*
* When there are no more entries for this peer, discard the peer
@ -337,19 +333,6 @@ void qmgr_entry_done(QMGR_ENTRY *entry, int which)
if (which == QMGR_QUEUE_BUSY)
queue->last_done = event_time();
/*
* Suspend a rate-limited queue, so that mail trickles out.
*/
if (which == QMGR_QUEUE_BUSY && transport->rate_delay > 0) {
if (queue->window > 1)
msg_panic("%s: queue %s/%s: window %d > 1 on rate-limited service",
myname, transport->name, queue->name, queue->window);
if (QMGR_QUEUE_THROTTLED(queue)) /* XXX */
qmgr_queue_unthrottle(queue);
if (QMGR_QUEUE_READY(queue))
qmgr_queue_suspend(queue, transport->rate_delay);
}
/*
* When the in-core queue for this site is empty and when this site is
* not dead or suspended, discard the in-core queue. When this site is

View File

@ -18,6 +18,9 @@
/*
/* QMGR_ENTRY *qmgr_job_entry_select(transport)
/* QMGR_TRANSPORT *transport;
/*
/* void qmgr_job_blocker_update(queue)
/* QMGR_QUEUE *queue;
/* DESCRIPTION
/* These routines add/delete/manipulate per-transport jobs.
/* Each job corresponds to a specific transport and message.
@ -38,6 +41,11 @@
/* If necessary, an attempt to read more recipients into core is made.
/* This can result in creation of more job, queue and entry structures.
/*
/* qmgr_job_blocker_update() updates the status of blocked
/* jobs after a decrease in the queue's concurrency level,
/* after the queue is throttled, or after the queue is resumed
/* from suspension.
/*
/* qmgr_job_move_limits() takes care of proper distribution of the
/* per-transport recipients limit among the per-transport jobs.
/* Should be called whenever a job's recipient slot becomes available.
@ -937,3 +945,36 @@ QMGR_ENTRY *qmgr_job_entry_select(QMGR_TRANSPORT *transport)
transport->job_current = 0;
return (0);
}
/* qmgr_job_blocker_update - update "blocked job" status */
void qmgr_job_blocker_update(QMGR_QUEUE *queue)
{
QMGR_TRANSPORT *transport = queue->transport;
/*
* If the queue was blocking some of the jobs on the job list, check if
* the concurrency limit has lifted. If there are still some pending
* deliveries, give it a try and unmark all transport blockers at once.
* The qmgr_job_entry_select() will do the rest. In either case make sure
* the queue is not marked as a blocker anymore, with extra handling of
* queues which were declared dead.
*
* Note that changing the blocker status also affects the candidate cache.
* Most of the cases would be automatically recognized by the current job
* change, but we play safe and reset the cache explicitly below.
*
* Keeping the transport blocker tag odd is an easy way to make sure the tag
* never matches jobs that are not explicitly marked as blockers.
*/
if (queue->blocker_tag == transport->blocker_tag) {
if (queue->window > queue->busy_refcount && queue->todo.next != 0) {
transport->blocker_tag += 2;
transport->job_current = transport->job_list.next;
transport->candidate_cache_current = 0;
}
if (queue->window > queue->busy_refcount || QMGR_QUEUE_THROTTLED(queue))
queue->blocker_tag = 0;
}
}

View File

@ -66,7 +66,11 @@
/* "slow open" mode, and eliminates the "thundering herd" problem.
/*
/* qmgr_queue_suspend() suspends delivery for this destination
/* briefly.
/* briefly. This function invalidates any scheduling decisions
/* that are based on the present queue's concurrency window.
/* To compensate for work skipped by qmgr_entry_done(), the
/* status of blocker jobs is re-evaluated after the queue is
/* resumed.
/* DIAGNOSTICS
/* Panic: consistency check failure.
/* LICENSE
@ -152,9 +156,20 @@ static void qmgr_queue_resume(int event, char *context)
/*
* Every event handler that leaves a queue in the "ready" state should
* remove the queue when it is empty.
*
* XXX Do not omit the redundant test below. It is here to simplify code
* consistency checks. The check is trivially eliminated by the compiler
* optimizer. There is no need to sacrifice code clarity for the sake of
* performance.
*
* XXX Do not expose the blocker job logic here. Rate-limited queues are not
* a performance-critical feature. Here, too, there is no need to sacrifice
* code clarity for the sake of performance.
*/
if (QMGR_QUEUE_READY(queue) && queue->todo.next == 0 && queue->busy.next == 0)
qmgr_queue_done(queue);
else
qmgr_job_blocker_update(queue);
}
/* qmgr_queue_suspend - briefly suspend a destination */

View File

@ -291,6 +291,8 @@ QMGR_TRANSPORT *qmgr_transport_select(void)
continue;
need = xport->pending + 1;
for (queue = xport->queue_list.next; queue; queue = queue->peers.next) {
if (QMGR_QUEUE_READY(queue) == 0)
continue;
if ((need -= MIN5af51743e4eef(queue->window - queue->busy_refcount,
queue->todo_refcount)) <= 0) {
QMGR_LIST_ROTATE(qmgr_transport_list, xport, peers);

View File

@ -1771,12 +1771,15 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
* XXX Don't downgrade just because generic_maps is turned
* on.
*/
if (downgrading || smtp_generic_maps || smtp_header_checks
|| smtp_body_checks)
#define SMTP_ANY_CHECKS (smtp_header_checks || smtp_body_checks)
if (downgrading || smtp_generic_maps || SMTP_ANY_CHECKS)
session->mime_state = mime_state_alloc(downgrading ?
MIME_OPT_DOWNGRADE
| MIME_OPT_REPORT_NESTING :
MIME_OPT_DISABLE_MIME,
SMTP_ANY_CHECKS == 0 ?
MIME_OPT_DISABLE_MIME :
0,
smtp_generic_maps
|| smtp_header_checks ?
smtp_header_rewrite :

View File

@ -564,11 +564,23 @@ int smtpd_proxy_cmd(SMTPD_STATE *state, int expect, const char *fmt,...)
/*
* Log a warning in case the proxy does not send the expected response.
* Silently accept any response when the client expressed no expectation.
*
* Don't pass through misleading 2xx replies. it confuses naive users and
* SMTP clients, and creates support problems.
*/
if (expect != SMTPD_PROX_WANT_ANY && expect != *STR(state->proxy_buffer)) {
va_start(ap, fmt);
smtpd_proxy_cmd_error(state, fmt, ap);
va_end(ap);
if (*STR(state->proxy_buffer) == SMTPD_PROX_WANT_OK
|| *STR(state->proxy_buffer) == SMTPD_PROX_WANT_MORE) {
state->error_mask |= MAIL_ERROR_SOFTWARE;
state->err |= CLEANUP_STAT_PROXY;
detail = cleanup_stat_detail(CLEANUP_STAT_PROXY);
vstring_sprintf(state->proxy_buffer,
"%d %s Error: %s",
detail->smtp, detail->dsn, detail->text);
}
return (-1);
} else {
return (0);