nfs server resource exhaustion (before it's too late)

Rick Macklem rmacklem at
Tue May 19 15:29:48 UTC 2009

In the experimental nfs server (sys/fs/nfsserver), there is a function that,
when it returns non-zero, causes the server to reply NFSERR_DELAY to the
client so that it will try the RPC again a little later. (Or, for NFSv2 over
UDP, which doesn't have NFSERR_DELAY, it simply drops the request and assumes
the client will timeout and try it again.) This is intended to avoid the
situation where the server cannot m_get/m_getcl/malloc part way through
processing a request, due to resource exhaustion. (The malloc case isn't
as critical, since I have high water marks set to limit the # of allocations
for the various NFSv4 state related structures that are malloc'd.)

At this point the function is just a stub:

 	return (0);

I just took a quick look (I don't know anything about UMA, except that it
seems to be used by m_get and m_getcl) and this was what I could think of
for doing the above on FreeBSD8. (It wasn't obvious to me if there
was a limit set for the various zones used by malloc(), so I didn't
include them.

 	u_int32_t pages, maxpages;

 	uma_zone_get_pagecnts(zone_clust, &pages, &maxpages);
 	if (maxpages != 0 && (pages * 12 / 10) > maxpages)
 		return (1);
 	return (0);

At this point, the only function I could see that would return the above
information is sysctl_vm_zone_stats() and it looks like overkill. Also,
the function needs to be relatively low overhead, since it is called for
every nfs rpc the server gets so I thought this might be ok?
/* added to sys/vm/uma_core.c */
uma_zone_get_pagecnts(uma_zone_t zone, u_int32_t *pages, u_int32_t *maxpages)
 	uma_keg_t keg;

 	keg = zone_first_keg(zone);
 	*pages = keg->uk_pages;
 	*maxpages = keg->uk_maxpages;

Does this look reasonable or can anyone suggest a better alternative?

Thanks in advance for any suggestions, rick

More information about the freebsd-arch mailing list