Skip to content

Commit b60db7b

Browse files
committed
Reduce and handle EAGAIN errors on AIO label reads
At least FreeBSD has a limit of 256 simultaneous AIO requests per process. Attempt to issue more results in EAGAIN errors. Since we issue 4 requests per disk/partition from 2xCPUs threads, it is quite easy to reach that limit on large systems, that results in random pool import failures. It annoyed me for quite a while on a system with 64 CPUs and 70+ partitioned disks. This patch from one side limits the number of threads to avoid the error, while from another should softly fall back to sync reads in case of error. It takes into account _SC_AIO_MAX as a system-wide AIO limit and _SC_AIO_LISTIO_MAX as a closest value to per-process limit. The last not exactly right, but it is the best I found. Signed-off-by: Alexander Motin <[email protected]> Sponsored by: iXsystems, Inc.
1 parent 4d469ac commit b60db7b

File tree

1 file changed

+16
-1
lines changed

1 file changed

+16
-1
lines changed

lib/libzutil/zutil_import.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1071,6 +1071,7 @@ zpool_read_label(int fd, nvlist_t **config, int *num_labels)
10711071
* Try the slow method.
10721072
*/
10731073
zfs_fallthrough;
1074+
case EAGAIN:
10741075
case EOPNOTSUPP:
10751076
case ENOSYS:
10761077
do_slow = B_TRUE;
@@ -1464,7 +1465,21 @@ zpool_find_import_impl(libpc_handle_t *hdl, importargs_t *iarg,
14641465
* validating labels, a large number of threads can be used due to
14651466
* minimal contention.
14661467
*/
1467-
t = tpool_create(1, 2 * sysconf(_SC_NPROCESSORS_ONLN), 0, NULL);
1468+
long threads = 2 * sysconf(_SC_NPROCESSORS_ONLN);
1469+
#ifdef HAVE_AIO_H
1470+
long am;
1471+
#ifdef _SC_AIO_LISTIO_MAX
1472+
am = sysconf(_SC_AIO_LISTIO_MAX);
1473+
if (am >= VDEV_LABELS)
1474+
threads = MIN(threads, am / VDEV_LABELS);
1475+
#endif
1476+
#ifdef _SC_AIO_MAX
1477+
am = sysconf(_SC_AIO_MAX);
1478+
if (am >= VDEV_LABELS)
1479+
threads = MIN(threads, am / VDEV_LABELS);
1480+
#endif
1481+
#endif
1482+
t = tpool_create(1, threads, 0, NULL);
14681483
for (slice = avl_first(cache); slice;
14691484
(slice = avl_walk(cache, slice, AVL_AFTER)))
14701485
(void) tpool_dispatch(t, zpool_open_func, slice);

0 commit comments

Comments
 (0)