php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #65774 no max file descriptor check for events.mechanism = /dev/poll
Submitted: 2013-09-27 16:00 UTC Modified: 2017-10-24 07:45 UTC
Votes:128
Avg. Score:5.0 ± 0.2
Reproduced:127 of 127 (100.0%)
Same Version:127 (100.0%)
Same OS:127 (100.0%)
From: aglarond at gmail dot com Assigned:
Status: Open Package: FPM related
PHP Version: Irrelevant OS: SmartOS, possibly others
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: aglarond at gmail dot com
New email:
PHP Version: OS:

 

 [2013-09-27 16:00 UTC] aglarond at gmail dot com
Description:
------------
When using PHP-FPM with 'events.mechanism = /dev/poll' and 'pm = dynamic', we noticed that the log would fill with lines like the following:

WARNING: pid 61603, fpm_event_devpoll_wait(), line 166: /dev/poll: ioctl() returns 22


The line referenced refers to sapi/fpm/fpm/events/devpoll.c:

159	        /* wait for inconming event or timeout */
160	        ret = ioctl(dpfd, DP_POLL, &dopoll);
161	
162	        if (ret < 0) {
163	
164	                /* trigger error unless signal interrupt */
165	                if (errno != EINTR) {
166	                        zlog(ZLOG_WARNING, "/dev/poll: ioctl() returns %d", errno);
167	                        return -1;
168	                }
169	        }


Unfortunately, these log entries didn't help us to solve the problem.  They only served to fill the disk, as they were written as quickly as the I/O subsystem allowed.


What did help narrow down the problem was seeing the following entry:

DEBUG: pid 61603, fpm_event_init_main(), line 333: event module is /dev/poll and 1061 fds have been reserved


It seemed we had reached a watermark, as the default maximum number of file descriptors on this system is 1024:

NAME    PRIVILEGE       VALUE    FLAG   ACTION                       RECIPIENT
process.max-file-descriptor
        basic           1.02K       -   deny                             57203
        privileged      65.5K       -   deny                                 -
        system          2.15G     max   deny                                 -


Increasing the number of file descriptors makes the log entries go away:

NAME    PRIVILEGE       VALUE    FLAG   ACTION                       RECIPIENT
process.max-file-descriptor
        basic           65.5K       -   deny                             70867
        privileged      65.5K       -   deny                                 -
        system          2.15G     max   deny                                 -


I propose prefacing the errno check (line 165) with one for EBADF.  I don't have time to write and test a patch right now, to verify that errno is indeed EBADF in this case (error number 22 is EINVAL, but I suspect this is getting passed from the device driver).  The patch should make this check and then probably end the main process.


An alternative is to change fpm_event_init_main in sapi/fpm/fpm/fpm_events.c to end the main process at file descriptor reservation time:

323	        /* count the max number of necessary fds for polling */
324	        max = 1; /* only one FD is necessary at startup for the master process signal pipe */
325	        for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
326	                if (!wp->config) continue;
327	                if (wp->config->catch_workers_output && wp->config->pm_max_children > 0) {
328	                        max += (wp->config->pm_max_children * 2);
329	                }
330	        }
331	
332	        if (module->init(max) < 0) {
333	                zlog(ZLOG_ERROR, "Unable to initialize the event module %s", module->name);
334	                return -1;
335	        }
336	
337	        zlog(ZLOG_DEBUG, "event module is %s and %d fds have been reserved", module->name, max);
338	


Briefly looking at devpool's init function shows checks for allocating enough memory, but doesn't seem to check if the max file descriptors can actually be allocated.  Ideally, a check should be made at this point to see if an OS limit will be hit before even initializing the module.  I don't know if there are any module-specific semantics that would need to be taken into account and preclude a general check in fpm_event_init_main.


The relevant code paths are unchanged for 5.3.27, 5.4.20, 5.5.4, so marking this as version Irrelevant.



Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2013-10-05 16:38 UTC] felipe@php.net
-Status: Open +Status: Assigned -Assigned To: +Assigned To: fat
 [2017-10-24 07:45 UTC] kalle@php.net
-Status: Assigned +Status: Open -Assigned To: fat +Assigned To:
 
PHP Copyright © 2001-2019 The PHP Group
All rights reserved.
Last updated: Wed Nov 13 14:01:29 2019 UTC