1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <errno.h> 29 #include <strings.h> 30 #include <sys/types.h> 31 #include <sys/systm.h> 32 #include <sys/resource.h> 33 #include <sys/sysconfig.h> 34 #include <sys/lx_types.h> 35 #include <sys/lx_misc.h> 36 37 #define LX_RLIMIT_RSS 5 38 #define LX_RLIMIT_NPROC 6 39 #define LX_RLIMIT_MEMLOCK 8 40 #define LX_RLIMIT_LOCKS 10 41 #define LX_RLIMIT_NLIMITS 11 42 43 /* 44 * Linux supports many of the same resources that we do, but the numbering 45 * is slightly different. This table is used to translate Linux resource 46 * limit keys into their Solaris equivalents. 47 */ 48 static int ltos_resource[LX_RLIMIT_NLIMITS] = { 49 RLIMIT_CPU, 50 RLIMIT_FSIZE, 51 RLIMIT_DATA, 52 RLIMIT_STACK, 53 RLIMIT_CORE, 54 -1, /* RSS */ 55 -1, /* NPROC */ 56 RLIMIT_NOFILE, 57 -1, /* MEMLOCK */ 58 RLIMIT_AS, 59 -1 /* LOCKS */ 60 }; 61 62 #define NLIMITS (sizeof (ltos_resource) / sizeof (int)) 63 64 /* 65 * Magic values Linux uses to indicate infinity 66 */ 67 #define LX_RLIM_INFINITY_O (0x7fffffffUL) 68 #define LX_RLIM_INFINITY_N (0xffffffffUL) 69 70 /* 71 * Array to store the rlimits that we track but do not enforce. 72 */ 73 static struct rlimit fake_limits[NLIMITS] = { 74 0, 0, 75 0, 0, 76 0, 0, 77 0, 0, 78 0, 0, 79 RLIM_INFINITY, RLIM_INFINITY, /* LX_RLIM_RSS */ 80 RLIM_INFINITY, RLIM_INFINITY, /* LX_RLIM_NPROC */ 81 0, 0, 82 RLIM_INFINITY, RLIM_INFINITY, /* LX_RLIM_MEMLOCK */ 83 0, 0, 84 RLIM_INFINITY, RLIM_INFINITY /* LX_RLIM_LOCKS */ 85 }; 86 87 static int 88 lx_getrlimit_common(int resource, struct rlimit *rlp, int inf) 89 { 90 int rv; 91 int sresource; 92 struct rlimit rl; 93 94 if (resource < 0 || resource >= LX_RLIMIT_NLIMITS) 95 return (-EINVAL); 96 97 sresource = ltos_resource[resource]; 98 99 if (sresource == -1) { 100 switch (resource) { 101 case LX_RLIMIT_MEMLOCK: 102 case LX_RLIMIT_RSS: 103 case LX_RLIMIT_LOCKS: 104 case LX_RLIMIT_NPROC: 105 rl.rlim_max = fake_limits[resource].rlim_max; 106 rl.rlim_cur = fake_limits[resource].rlim_cur; 107 if (rl.rlim_cur == RLIM_INFINITY) 108 rl.rlim_cur = inf; 109 if (rl.rlim_max == RLIM_INFINITY) 110 rl.rlim_max = inf; 111 if ((uucopy(&rl, rlp, sizeof (rl))) != 0) 112 return (-errno); 113 return (0); 114 default: 115 lx_unsupported("Unsupported resource type %d\n", 116 resource); 117 return (-ENOTSUP); 118 } 119 } else { 120 rv = getrlimit(sresource, rlp); 121 } 122 123 if (rv < 0) 124 return (-errno); 125 126 if (rlp->rlim_cur == RLIM_INFINITY) 127 rlp->rlim_cur = inf; 128 129 if (rlp->rlim_max == RLIM_INFINITY) 130 rlp->rlim_max = inf; 131 132 return (0); 133 } 134 135 /* 136 * This is the 'new' getrlimit, variously called getrlimit or ugetrlimit 137 * in Linux headers and code. The only difference between this and the old 138 * getrlimit (variously called getrlimit or old_getrlimit) is the value of 139 * RLIM_INFINITY, which is smaller for the older version. Modern code will 140 * use this version by default. 141 */ 142 int 143 lx_getrlimit(uintptr_t p1, uintptr_t p2) 144 { 145 int resource = (int)p1; 146 struct rlimit *rlp = (struct rlimit *)p2; 147 148 return (lx_getrlimit_common(resource, rlp, LX_RLIM_INFINITY_N)); 149 } 150 151 /* 152 * This is the 'old' getrlimit, variously called getrlimit or old_getrlimit 153 * in Linux headers and code. The only difference between this and the new 154 * getrlimit (variously called getrlimit or ugetrlimit) is the value of 155 * RLIM_INFINITY, which is smaller for the older version. 156 */ 157 int 158 lx_oldgetrlimit(uintptr_t p1, uintptr_t p2) 159 { 160 int resource = (int)p1; 161 struct rlimit *rlp = (struct rlimit *)p2; 162 163 return (lx_getrlimit_common(resource, rlp, LX_RLIM_INFINITY_O)); 164 } 165 166 int 167 lx_setrlimit(uintptr_t p1, uintptr_t p2) 168 { 169 int resource = (int)p1; 170 struct rlimit *rlp = (struct rlimit *)p2; 171 struct rlimit rl; 172 int rv, sresource; 173 174 if (resource < 0 || resource >= LX_RLIMIT_NLIMITS) 175 return (-EINVAL); 176 177 sresource = ltos_resource[resource]; 178 179 if (sresource == -1) { 180 if (uucopy((void *)p2, &rl, sizeof (rl)) != 0) 181 return (-errno); 182 183 switch (resource) { 184 case LX_RLIMIT_MEMLOCK: 185 case LX_RLIMIT_RSS: 186 case LX_RLIMIT_LOCKS: 187 case LX_RLIMIT_NPROC: 188 if (rl.rlim_max != LX_RLIM_INFINITY_N && 189 (rl.rlim_cur == LX_RLIM_INFINITY_N || 190 rl.rlim_cur > rl.rlim_max)) 191 return (-EINVAL); 192 if (rl.rlim_max == LX_RLIM_INFINITY_N) 193 fake_limits[resource].rlim_max = RLIM_INFINITY; 194 else 195 fake_limits[resource].rlim_max = rl.rlim_max; 196 if (rl.rlim_cur == LX_RLIM_INFINITY_N) 197 fake_limits[resource].rlim_cur = RLIM_INFINITY; 198 else 199 fake_limits[resource].rlim_cur = rl.rlim_cur; 200 return (0); 201 } 202 203 lx_unsupported("Unsupported resource type %d\n", resource); 204 return (-ENOTSUP); 205 } 206 207 rv = setrlimit(sresource, rlp); 208 209 return (rv < 0 ? -errno : 0); 210 } 211 212 /* 213 * We lucked out here. Linux and Solaris have exactly the same 214 * rusage structures. 215 */ 216 int 217 lx_getrusage(uintptr_t p1, uintptr_t p2) 218 { 219 int who = (int)p1; 220 struct rusage *rup = (struct rusage *)p2; 221 int rv, swho; 222 223 if (who == LX_RUSAGE_SELF) 224 swho = _RUSAGESYS_GETRUSAGE; 225 else if (who == LX_RUSAGE_CHILDREN) 226 swho = _RUSAGESYS_GETRUSAGE_CHLD; 227 else 228 return (-EINVAL); 229 230 rv = getrusage(swho, rup); 231 232 return (rv < 0 ? -errno : 0); 233 }