[PATCH 8 of 9] Upstream: disable re-resolve functionality on Windows

Aleksei Bavshin a.bavshin at nginx.com
Thu Jul 11 16:25:43 UTC 2024


On 7/10/2024 6:16 AM, Roman Arutyunyan wrote:
> Hi,
> 
> On Thu, Jun 13, 2024 at 03:29:03PM -0700, Aleksei Bavshin wrote:
>> # HG changeset patch
>> # User Aleksei Bavshin <a.bavshin at nginx.com>
>> # Date 1712181327 25200
>> #      Wed Apr 03 14:55:27 2024 -0700
>> # Node ID 375fa42f1a6010692a8782c4f03c6ad465d3f7f7
>> # Parent  8c8d8118c7ac0a0426f48dbfed94e279dddff992
>> Upstream: disable re-resolve functionality on Windows.
>>
>> Following features are currently not implemented on Windows, making re-resolve
>> functionality unsafe to use:
>>
>>   * 'noreuse' shared zones that are re-created on each configuration reload.
>>     The work scheduling logic is not prepared to handle simultaneous access to
>>     the shared zone from multiple generations of the worker processes.
> 
> I don't see a problem here.  Could you please elaborate.

Now I recall that I could've been running a modified version with 
different handling of `noreuse` when I wrote that.

The problem is still valid; assuming that `noreuse` is simply ignored on 
Windows, we could've get the following behavior:
A new cycle is created on configuration reload, and an existing shared 
zone is referenced by the new cycle. Depending on how we handle that, 
`ngx_http_upstream_init_zone` in the new cycle either will find an 
existing set of peers (still actively used by a previous cycle) and 
overwrite host->event fields with worker-local pointers, or will 
allocate a new `ngx_http_upstream_rr_peers_t` and eventually exhausts 
the zone memory.

Thankfully, neither option is possible and `noreuse` does something on 
Windows platform: an upstream zone in the configuration will completely 
break configuration reload with

     2024/07/10 13:13:12 [alert] 41332#45116: MapViewOfFileEx(65536, 
2EFE0000) of file mapping "upstream_zone" failed (487: Attempt to access 
invalid address)

What's happening there is that we see the 'noreuse' flag and attempt to 
allocate a new shared zone. Due to a platform-specific implementation 
detail, we get `ERROR_ALREADY_EXISTS` and proceed with the existing file 
mapping object mapped at a different address.

Next, the code added in af7eba90645d will notice that the newly mapped 
address does not match the expected address of an existing zone and will 
attempt to remap it at the original address via ngx_shm_remap.

As we're in the master process and the original mapping still exists at 
that address, `MapViewOfFileEx` would fail and abort the configuration 
reload.

Note that you don't even need the patches in this series to reproduce that.

***

Overall, I'm convinced that the problem is not in the resolver but in 
the `noreuse` zone type we use in upstreams. And we already allow these 
on Windows, so the ship has sailed.

I saw a previous idea to resolve that by allocating `noreuse` zones with 
a name unique to the config generation and tried implementing that, but 
it wasn't beautiful.

Thus, I'm retracting this patch. Let's just update the Windows platform 
limitations in the documentation instead.

> 
>>   * 'ngx_worker' identification.
>>     It is possible to configure multiple worker processes on Windows, even if
>>     only one would actually handle the traffic.  All of the worker processes are
>>     currently identified as process 0, breaking scheduling and locking of the
>>     resolver tasks.
> 
> This can be fixed.  Patch attached.

Note that the patch is insufficient, as it does not handle respawning.

We should store the ngx_worker value in the ngx_processes and restore 
the variable when necessary, or find an alternative way of passing it to 
the worker process.
My WIP patch with `cycle->generation` support had an attempt to solve 
that with making environment snapshots (GetEnvironmentStrings) and 
passing these to the CreateProcess, but that quickly escalated into a 
ton of unrelated fixes and I decided to stop.

> 
>> diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
>> --- a/src/http/ngx_http_upstream.c
>> +++ b/src/http/ngx_http_upstream.c
>> @@ -6327,7 +6327,7 @@ ngx_http_upstream_server(ngx_conf_t *cf,
>>               continue;
>>           }
>>   
>> -#if (NGX_HTTP_UPSTREAM_ZONE)
>> +#if (NGX_HTTP_UPSTREAM_ZONE && !(NGX_WIN32))
>>           if (ngx_strcmp(value[i].data, "resolve") == 0) {
>>               resolve = 1;
>>               continue;
>> diff --git a/src/stream/ngx_stream_upstream.c b/src/stream/ngx_stream_upstream.c
>> --- a/src/stream/ngx_stream_upstream.c
>> +++ b/src/stream/ngx_stream_upstream.c
>> @@ -545,7 +545,7 @@ ngx_stream_upstream_server(ngx_conf_t *c
>>               continue;
>>           }
>>   
>> -#if (NGX_STREAM_UPSTREAM_ZONE)
>> +#if (NGX_STREAM_UPSTREAM_ZONE && !(NGX_WIN32))
>>           if (ngx_strcmp(value[i].data, "resolve") == 0) {
>>               resolve = 1;
>>               continue;
>> _______________________________________________
>> nginx-devel mailing list
>> nginx-devel at nginx.org
>> https://mailman.nginx.org/mailman/listinfo/nginx-devel
> 
> --
> Roman Arutyunyan
> 
> 
> _______________________________________________
> nginx-devel mailing list
> nginx-devel at nginx.org
> https://mailman.nginx.org/mailman/listinfo/nginx-devel


More information about the nginx-devel mailing list