Date: Fri, 25 Aug 2017 16:38:21 +0000 (UTC) From: Conrad Meyer <cem@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r322895 - in head/lib/libc: gen tests/gen Message-ID: <201708251638.v7PGcLR0063459@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: cem Date: Fri Aug 25 16:38:21 2017 New Revision: 322895 URL: https://svnweb.freebsd.org/changeset/base/322895 Log: getmntinfo(3): Scale faster, and return sooner getmntinfo(3) is designed around a relatively static or slow growing set of current mounts. It tried to detect a race with somewhat concurrent mount and re-call getfsstat(2) in that case, looping indefinitely. It also allocated space for a single extra mount as slop. In the case where the user has a large number of mounts and is adding them at a rapid pace, it fell over. This patch makes two functional changes: 1. Allocate even more slop. Double whatever the last getfsstat(2) returned. 2. Abort and return some known results after looping a few times (arbitrarily, 3). If the list is constantly changing, we can't guarantee we return a full result to the user at any point anyways. While here, add very basic functional tests for getmntinfo(3) to the libc suite. PR: 221743 Submitted by: Peter Eriksson <peter AT ifm.liu.se> (earlier version) Sponsored by: Dell EMC Isilon Added: head/lib/libc/tests/gen/getmntinfo_test.c (contents, props changed) Modified: head/lib/libc/gen/getmntinfo.c head/lib/libc/tests/gen/Makefile Modified: head/lib/libc/gen/getmntinfo.c ============================================================================== --- head/lib/libc/gen/getmntinfo.c Fri Aug 25 16:10:16 2017 (r322894) +++ head/lib/libc/gen/getmntinfo.c Fri Aug 25 16:38:21 2017 (r322895) @@ -38,6 +38,9 @@ __FBSDID("$FreeBSD$"); #include <sys/mount.h> #include <stdlib.h> +#define MAX_TRIES 3 +#define SCALING_FACTOR 2 + /* * Return information about mounted filesystems. */ @@ -47,20 +50,21 @@ getmntinfo(struct statfs **mntbufp, int mode) static struct statfs *mntbuf; static int mntsize; static long bufsize; + unsigned tries = 0; if (mntsize <= 0 && (mntsize = getfsstat(0, 0, MNT_NOWAIT)) < 0) return (0); if (bufsize > 0 && (mntsize = getfsstat(mntbuf, bufsize, mode)) < 0) return (0); - while (bufsize <= mntsize * sizeof(struct statfs)) { - if (mntbuf) - free(mntbuf); - bufsize = (mntsize + 1) * sizeof(struct statfs); - if ((mntbuf = malloc(bufsize)) == NULL) + while (tries++ < MAX_TRIES && bufsize <= mntsize * sizeof(*mntbuf)) { + bufsize = (mntsize * SCALING_FACTOR) * sizeof(*mntbuf); + if ((mntbuf = reallocf(mntbuf, bufsize)) == NULL) return (0); if ((mntsize = getfsstat(mntbuf, bufsize, mode)) < 0) return (0); } *mntbufp = mntbuf; + if (mntsize > (bufsize / sizeof(*mntbuf))) + return (bufsize / sizeof(*mntbuf)); return (mntsize); } Modified: head/lib/libc/tests/gen/Makefile ============================================================================== --- head/lib/libc/tests/gen/Makefile Fri Aug 25 16:10:16 2017 (r322894) +++ head/lib/libc/tests/gen/Makefile Fri Aug 25 16:38:21 2017 (r322895) @@ -8,6 +8,7 @@ ATF_TESTS_C+= fmtmsg_test ATF_TESTS_C+= fnmatch2_test ATF_TESTS_C+= fpclassify2_test ATF_TESTS_C+= ftw_test +ATF_TESTS_C+= getmntinfo_test ATF_TESTS_C+= glob2_test ATF_TESTS_C+= popen_test ATF_TESTS_C+= posix_spawn_test Added: head/lib/libc/tests/gen/getmntinfo_test.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/lib/libc/tests/gen/getmntinfo_test.c Fri Aug 25 16:38:21 2017 (r322895) @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 2017 Conrad Meyer <cem@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Limited test program for getmntinfo(3), a non-standard BSDism. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/mount.h> +#include <sys/ucred.h> + +#include <errno.h> + +#include <atf-c.h> + +static void +check_mntinfo(struct statfs *mntinfo, int n) +{ + int i; + + for (i = 0; i < n; i++) { + ATF_REQUIRE_MSG(mntinfo[i].f_version == STATFS_VERSION, "%ju", + (uintmax_t)mntinfo[i].f_version); + ATF_REQUIRE(mntinfo[i].f_namemax <= sizeof(mntinfo[0].f_mntonname)); + } +} + +ATF_TC_WITHOUT_HEAD(getmntinfo_test); +ATF_TC_BODY(getmntinfo_test, tc) +{ + int nmnts; + struct statfs *mntinfo; + + /* Test bogus mode */ + nmnts = getmntinfo(&mntinfo, 199); + ATF_REQUIRE_MSG(nmnts == 0 && errno == EINVAL, + "getmntinfo() succeeded; errno=%d", errno); + + /* Valid modes */ + nmnts = getmntinfo(&mntinfo, MNT_NOWAIT); + ATF_REQUIRE_MSG(nmnts != 0, "getmntinfo(MNT_NOWAIT) failed; errno=%d", + errno); + + check_mntinfo(mntinfo, nmnts); + memset(mntinfo, 0xdf, sizeof(*mntinfo) * nmnts); + + nmnts = getmntinfo(&mntinfo, MNT_WAIT); + ATF_REQUIRE_MSG(nmnts != 0, "getmntinfo(MNT_WAIT) failed; errno=%d", + errno); + + check_mntinfo(mntinfo, nmnts); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, getmntinfo_test); + + return (atf_no_error()); +}
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201708251638.v7PGcLR0063459>