From owner-svn-src-all@freebsd.org Fri Aug 25 16:38:23 2017 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 0C9D8DDC395; Fri, 25 Aug 2017 16:38:23 +0000 (UTC) (envelope-from cem@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id DBA7066BA1; Fri, 25 Aug 2017 16:38:22 +0000 (UTC) (envelope-from cem@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v7PGcLsk063463; Fri, 25 Aug 2017 16:38:21 GMT (envelope-from cem@FreeBSD.org) Received: (from cem@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v7PGcLR0063459; Fri, 25 Aug 2017 16:38:21 GMT (envelope-from cem@FreeBSD.org) Message-Id: <201708251638.v7PGcLR0063459@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: cem set sender to cem@FreeBSD.org using -f From: Conrad Meyer Date: Fri, 25 Aug 2017 16:38:21 +0000 (UTC) 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 X-SVN-Group: head X-SVN-Commit-Author: cem X-SVN-Commit-Paths: in head/lib/libc: gen tests/gen X-SVN-Commit-Revision: 322895 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 25 Aug 2017 16:38:23 -0000 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 (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 #include +#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 + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include + +#include + +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()); +}