Clean up check_pf allocation pattern. addresses

We simplify allocation strategy there so instead of using temporary linked list
and then copying entries to output array we keep them in resizable
array.
This commit is contained in:
Ondřej Bílka 2015-01-06 17:26:44 +01:00
parent 14bb4e57c0
commit 4790d9a2c0

View File

@ -105,6 +105,11 @@ cache_valid_p (void)
static struct cached_data *
make_request (int fd, pid_t pid)
{
struct cached_data *result = NULL;
size_t result_len = 0;
size_t result_cap = 32;
struct req
{
struct nlmsghdr nlh;
@ -130,26 +135,11 @@ make_request (int fd, pid_t pid)
nladdr.nl_family = AF_NETLINK;
#ifdef PAGE_SIZE
/* Help the compiler optimize out the malloc call if PAGE_SIZE
is constant and smaller or equal to PTHREAD_STACK_MIN/4. */
const size_t buf_size = PAGE_SIZE;
#else
const size_t buf_size = __getpagesize ();
const size_t buf_size = 4096;
#endif
bool use_malloc = false;
char *buf;
size_t alloca_used = 0;
if (__libc_use_alloca (buf_size))
buf = alloca_account (buf_size, alloca_used);
else
{
buf = malloc (buf_size);
if (buf != NULL)
use_malloc = true;
else
goto out_fail;
}
char buf[buf_size];
struct iovec iov = { buf, buf_size };
@ -159,13 +149,7 @@ make_request (int fd, pid_t pid)
goto out_fail;
bool done = false;
struct in6ailist
{
struct in6addrinfo info;
struct in6ailist *next;
bool use_malloc;
} *in6ailist = NULL;
size_t in6ailistlen = 0;
bool seen_ipv4 = false;
bool seen_ipv6 = false;
@ -181,10 +165,10 @@ make_request (int fd, pid_t pid)
ssize_t read_len = TEMP_FAILURE_RETRY (__recvmsg (fd, &msg, 0));
if (read_len <= 0)
goto out_fail2;
goto out_fail;
if (msg.msg_flags & MSG_TRUNC)
goto out_fail2;
goto out_fail;
struct nlmsghdr *nlmh;
for (nlmh = (struct nlmsghdr *) buf;
@ -240,40 +224,35 @@ make_request (int fd, pid_t pid)
}
}
struct in6ailist *newp;
if (__libc_use_alloca (alloca_used + sizeof (*newp)))
if (result_len == 0 || result_len == result_cap)
{
newp = alloca_account (sizeof (*newp), alloca_used);
newp->use_malloc = false;
result_cap = 2 * result_cap;
result = realloc (result, sizeof (*result)
+ result_cap
* sizeof (struct in6addrinfo));
}
else
{
newp = malloc (sizeof (*newp));
if (newp == NULL)
goto out_fail2;
newp->use_malloc = true;
}
newp->info.flags = (((ifam->ifa_flags
& (IFA_F_DEPRECATED
| IFA_F_OPTIMISTIC))
? in6ai_deprecated : 0)
| ((ifam->ifa_flags
& IFA_F_HOMEADDRESS)
? in6ai_homeaddress : 0));
newp->info.prefixlen = ifam->ifa_prefixlen;
newp->info.index = ifam->ifa_index;
if (!result)
goto out_fail;
struct in6addrinfo *info = &result->in6ai[result_len++];
info->flags = (((ifam->ifa_flags
& (IFA_F_DEPRECATED | IFA_F_OPTIMISTIC))
? in6ai_deprecated : 0)
| ((ifam->ifa_flags & IFA_F_HOMEADDRESS)
? in6ai_homeaddress : 0));
info->prefixlen = ifam->ifa_prefixlen;
info->index = ifam->ifa_index;
if (ifam->ifa_family == AF_INET)
{
newp->info.addr[0] = 0;
newp->info.addr[1] = 0;
newp->info.addr[2] = htonl (0xffff);
newp->info.addr[3] = *(const in_addr_t *) address;
info->addr[0] = 0;
info->addr[1] = 0;
info->addr[2] = htonl (0xffff);
info->addr[3] = *(const in_addr_t *) address;
}
else
memcpy (newp->info.addr, address, sizeof (newp->info.addr));
newp->next = in6ailist;
in6ailist = newp;
++in6ailistlen;
memcpy (info->addr, address, sizeof (info->addr));
}
else if (nlmh->nlmsg_type == NLMSG_DONE)
/* We found the end, leave the loop. */
@ -282,53 +261,29 @@ make_request (int fd, pid_t pid)
}
while (! done);
struct cached_data *result;
if (seen_ipv6 && in6ailist != NULL)
if (seen_ipv6 && result != NULL)
{
result = malloc (sizeof (*result)
+ in6ailistlen * sizeof (struct in6addrinfo));
if (result == NULL)
goto out_fail2;
result->timestamp = get_nl_timestamp ();
result->usecnt = 2;
result->seen_ipv4 = seen_ipv4;
result->seen_ipv6 = true;
result->in6ailen = in6ailistlen;
do
{
result->in6ai[--in6ailistlen] = in6ailist->info;
struct in6ailist *next = in6ailist->next;
if (in6ailist->use_malloc)
free (in6ailist);
in6ailist = next;
}
while (in6ailist != NULL);
result->in6ailen = result_len;
}
else
{
free (result);
atomic_add (&noai6ai_cached.usecnt, 2);
noai6ai_cached.seen_ipv4 = seen_ipv4;
noai6ai_cached.seen_ipv6 = seen_ipv6;
result = &noai6ai_cached;
}
if (use_malloc)
free (buf);
return result;
out_fail2:
while (in6ailist != NULL)
{
struct in6ailist *next = in6ailist->next;
if (in6ailist->use_malloc)
free (in6ailist);
in6ailist = next;
}
out_fail:
if (use_malloc)
free (buf);
free (result);
return NULL;
}