resource.c revision 290001
1/*
2 * Copyright (C) 2004, 2007-2009  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000, 2001  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id: resource.c,v 1.23 2009/02/13 23:48:14 tbox Exp $ */
19
20#include <config.h>
21
22#include <sys/types.h>
23#include <sys/time.h>	/* Required on some systems for <sys/resource.h>. */
24#include <sys/resource.h>
25
26#include <isc/platform.h>
27#include <isc/resource.h>
28#include <isc/result.h>
29#include <isc/util.h>
30
31#ifdef __linux__
32#include <linux/fs.h>	/* To get the large NR_OPEN. */
33#endif
34
35#if defined(__hpux) && defined(HAVE_SYS_DYNTUNE_H)
36#include <sys/dyntune.h>
37#endif
38
39#include "errno2result.h"
40
41static isc_result_t
42resource2rlim(isc_resource_t resource, int *rlim_resource) {
43	isc_result_t result = ISC_R_SUCCESS;
44
45	switch (resource) {
46	case isc_resource_coresize:
47		*rlim_resource = RLIMIT_CORE;
48		break;
49	case isc_resource_cputime:
50		*rlim_resource = RLIMIT_CPU;
51		break;
52	case isc_resource_datasize:
53		*rlim_resource = RLIMIT_DATA;
54		break;
55	case isc_resource_filesize:
56		*rlim_resource = RLIMIT_FSIZE;
57		break;
58	case isc_resource_lockedmemory:
59#ifdef RLIMIT_MEMLOCK
60		*rlim_resource = RLIMIT_MEMLOCK;
61#else
62		result = ISC_R_NOTIMPLEMENTED;
63#endif
64		break;
65	case isc_resource_openfiles:
66#ifdef RLIMIT_NOFILE
67		*rlim_resource = RLIMIT_NOFILE;
68#else
69		result = ISC_R_NOTIMPLEMENTED;
70#endif
71		break;
72	case isc_resource_processes:
73#ifdef RLIMIT_NPROC
74		*rlim_resource = RLIMIT_NPROC;
75#else
76		result = ISC_R_NOTIMPLEMENTED;
77#endif
78		break;
79	case isc_resource_residentsize:
80#ifdef RLIMIT_RSS
81		*rlim_resource = RLIMIT_RSS;
82#else
83		result = ISC_R_NOTIMPLEMENTED;
84#endif
85		break;
86	case isc_resource_stacksize:
87		*rlim_resource = RLIMIT_STACK;
88		break;
89	default:
90		/*
91		 * This test is not very robust if isc_resource_t
92		 * changes, but generates a clear assertion message.
93		 */
94		REQUIRE(resource >= isc_resource_coresize &&
95			resource <= isc_resource_stacksize);
96
97		result = ISC_R_RANGE;
98		break;
99	}
100
101	return (result);
102}
103
104isc_result_t
105isc_resource_setlimit(isc_resource_t resource, isc_resourcevalue_t value) {
106	struct rlimit rl;
107	ISC_PLATFORM_RLIMITTYPE rlim_value;
108	int unixresult;
109	int unixresource;
110	isc_result_t result;
111
112	result = resource2rlim(resource, &unixresource);
113	if (result != ISC_R_SUCCESS)
114		return (result);
115
116	if (value == ISC_RESOURCE_UNLIMITED)
117		rlim_value = RLIM_INFINITY;
118
119	else {
120		/*
121		 * isc_resourcevalue_t was chosen as an unsigned 64 bit
122		 * integer so that it could contain the maximum range of
123		 * reasonable values.  Unfortunately, this exceeds the typical
124		 * range on Unix systems.  Ensure the range of
125		 * ISC_PLATFORM_RLIMITTYPE is not overflowed.
126		 */
127		isc_resourcevalue_t rlim_max;
128		isc_boolean_t rlim_t_is_signed =
129			ISC_TF(((double)(ISC_PLATFORM_RLIMITTYPE)-1) < 0);
130
131		if (rlim_t_is_signed)
132			rlim_max = ~((ISC_PLATFORM_RLIMITTYPE)1 <<
133				     (sizeof(ISC_PLATFORM_RLIMITTYPE) * 8 - 1));
134		else
135			rlim_max = (ISC_PLATFORM_RLIMITTYPE)-1;
136
137		if (value > rlim_max)
138			value = rlim_max;
139
140		rlim_value = value;
141	}
142
143	rl.rlim_cur = rl.rlim_max = rlim_value;
144	unixresult = setrlimit(unixresource, &rl);
145
146	if (unixresult == 0)
147		return (ISC_R_SUCCESS);
148
149#if defined(OPEN_MAX) && defined(__APPLE__)
150	/*
151	 * The Darwin kernel doesn't accept RLIM_INFINITY for rlim_cur; the
152	 * maximum possible value is OPEN_MAX.  BIND8 used to use
153	 * sysconf(_SC_OPEN_MAX) for such a case, but this value is much
154	 * smaller than OPEN_MAX and is not really effective.
155	 */
156	if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
157		rl.rlim_cur = OPEN_MAX;
158		unixresult = setrlimit(unixresource, &rl);
159		if (unixresult == 0)
160			return (ISC_R_SUCCESS);
161	}
162#elif defined(__linux__)
163#ifndef NR_OPEN
164#define NR_OPEN (1024*1024)
165#endif
166
167	/*
168	 * Some Linux kernels don't accept RLIM_INFINIT; the maximum
169	 * possible value is the NR_OPEN defined in linux/fs.h.
170	 */
171	if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
172		rl.rlim_cur = rl.rlim_max = NR_OPEN;
173		unixresult = setrlimit(unixresource, &rl);
174		if (unixresult == 0)
175			return (ISC_R_SUCCESS);
176	}
177#elif defined(__hpux) && defined(HAVE_SYS_DYNTUNE_H)
178	if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
179		uint64_t maxfiles;
180		if (gettune("maxfiles_lim", &maxfiles) == 0) {
181			rl.rlim_cur = rl.rlim_max = maxfiles;
182			unixresult = setrlimit(unixresource, &rl);
183			if (unixresult == 0)
184				return (ISC_R_SUCCESS);
185		}
186	}
187#endif
188	if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
189		if (getrlimit(unixresource, &rl) == 0) {
190			rl.rlim_cur = rl.rlim_max;
191			unixresult = setrlimit(unixresource, &rl);
192			if (unixresult == 0)
193				return (ISC_R_SUCCESS);
194		}
195	}
196	return (isc__errno2result(errno));
197}
198
199isc_result_t
200isc_resource_getlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
201	int unixresult;
202	int unixresource;
203	struct rlimit rl;
204	isc_result_t result;
205
206	result = resource2rlim(resource, &unixresource);
207	if (result == ISC_R_SUCCESS) {
208		unixresult = getrlimit(unixresource, &rl);
209		INSIST(unixresult == 0);
210		*value = rl.rlim_max;
211	}
212
213	return (result);
214}
215
216isc_result_t
217isc_resource_getcurlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
218	int unixresult;
219	int unixresource;
220	struct rlimit rl;
221	isc_result_t result;
222
223	result = resource2rlim(resource, &unixresource);
224	if (result == ISC_R_SUCCESS) {
225		unixresult = getrlimit(unixresource, &rl);
226		INSIST(unixresult == 0);
227		*value = rl.rlim_cur;
228	}
229
230	return (result);
231}
232