xref: /onnv-gate/usr/src/uts/common/fs/sockfs/nl7curi.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/strsubr.h>
30*0Sstevel@tonic-gate #include <sys/strsun.h>
31*0Sstevel@tonic-gate #include <sys/param.h>
32*0Sstevel@tonic-gate #include <sys/sysmacros.h>
33*0Sstevel@tonic-gate #include <vm/seg_map.h>
34*0Sstevel@tonic-gate #include <vm/seg_kpm.h>
35*0Sstevel@tonic-gate #include <sys/condvar_impl.h>
36*0Sstevel@tonic-gate #include <sys/promif.h>
37*0Sstevel@tonic-gate #include <sys/sendfile.h>
38*0Sstevel@tonic-gate #include <fs/sockfs/nl7c.h>
39*0Sstevel@tonic-gate #include <fs/sockfs/nl7curi.h>
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate /*
42*0Sstevel@tonic-gate  * Some externs:
43*0Sstevel@tonic-gate  */
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate extern boolean_t nl7c_logd_enabled;
46*0Sstevel@tonic-gate extern void	nl7c_logd_log(uri_desc_t *, uri_desc_t *, time_t, ipaddr_t);
47*0Sstevel@tonic-gate boolean_t	nl7c_close_addr(struct sonode *);
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate /*
50*0Sstevel@tonic-gate  * Various global tuneables:
51*0Sstevel@tonic-gate  */
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate clock_t		nl7c_uri_ttl = -1;	/* TTL in seconds (-1 == infinite) */
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate boolean_t	nl7c_use_kmem = B_FALSE; /* Force use of kmem (no segmap) */
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate uint64_t	nl7c_file_prefetch = 1; /* File cache prefetch pages */
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate uint64_t	nl7c_uri_max = 0;	/* Maximum bytes (0 == infinite) */
60*0Sstevel@tonic-gate uint64_t	nl7c_uri_bytes = 0;	/* Bytes of kmem used by URIs */
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate /*
63*0Sstevel@tonic-gate  * Counters that need to move to kstat and/or be removed:
64*0Sstevel@tonic-gate  */
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_request = 0;
67*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_hit = 0;
68*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_pass = 0;
69*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_miss = 0;
70*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_temp = 0;
71*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_more = 0;
72*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_data = 0;
73*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_sendfilev = 0;
74*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_reclaim_calls = 0;
75*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_reclaim_cnt = 0;
76*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_pass_urifail = 0;
77*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_pass_dupbfail = 0;
78*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_more_get = 0;
79*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_pass_getnot = 0;
80*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_pass_option = 0;
81*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_more_eol = 0;
82*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_more_http = 0;
83*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_pass_http = 0;
84*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_pass_addfail = 0;
85*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_pass_temp = 0;
86*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_expire = 0;
87*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_NULL1 = 0;
88*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_NULL2 = 0;
89*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_close = 0;
90*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_temp_close = 0;
91*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_free = 0;
92*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_temp_free = 0;
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate /*
95*0Sstevel@tonic-gate  * Various kmem_cache_t's:
96*0Sstevel@tonic-gate  */
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate static kmem_cache_t *uri_kmc;
99*0Sstevel@tonic-gate static kmem_cache_t *uri_rd_kmc;
100*0Sstevel@tonic-gate static kmem_cache_t *uri_desb_kmc;
101*0Sstevel@tonic-gate static kmem_cache_t *uri_segmap_kmc;
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate static void uri_kmc_reclaim(void *);
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate static void nl7c_uri_reclaim(void);
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate /*
108*0Sstevel@tonic-gate  * The URI hash is a dynamically sized A/B bucket hash, when the current
109*0Sstevel@tonic-gate  * hash's average bucket chain length exceeds URI_HASH_AVRG a new hash of
110*0Sstevel@tonic-gate  * the next P2Ps[] size is created.
111*0Sstevel@tonic-gate  *
112*0Sstevel@tonic-gate  * All lookups are done in the current hash then the new hash (if any),
113*0Sstevel@tonic-gate  * if there is a new has then when a current hash bucket chain is examined
114*0Sstevel@tonic-gate  * any uri_desc_t members will be migrated to the new hash and when the
115*0Sstevel@tonic-gate  * last uri_desc_t has been migrated then the new hash will become the
116*0Sstevel@tonic-gate  * current and the previous current hash will be freed leaving a single
117*0Sstevel@tonic-gate  * hash.
118*0Sstevel@tonic-gate  *
119*0Sstevel@tonic-gate  * uri_hash_t - hash bucket (chain) type, contained in the uri_hash_ab[]
120*0Sstevel@tonic-gate  * and can be accessed only after aquiring the uri_hash_access lock (for
121*0Sstevel@tonic-gate  * READER or WRITER) then acquiring the lock uri_hash_t.lock, the uri_hash_t
122*0Sstevel@tonic-gate  * and all linked uri_desc_t.hash members are protected. Note, a REF_HOLD()
123*0Sstevel@tonic-gate  * is placed on all uri_desc_t uri_hash_t list members.
124*0Sstevel@tonic-gate  *
125*0Sstevel@tonic-gate  * uri_hash_access - rwlock for all uri_hash_* variables, READER for read
126*0Sstevel@tonic-gate  * access and WRITER for write access. Note, WRITER is only required for
127*0Sstevel@tonic-gate  * hash geometry changes.
128*0Sstevel@tonic-gate  *
129*0Sstevel@tonic-gate  * uri_hash_which - which uri_hash_ab[] is the current hash.
130*0Sstevel@tonic-gate  *
131*0Sstevel@tonic-gate  * uri_hash_n[] - the P2Ps[] index for each uri_hash_ab[].
132*0Sstevel@tonic-gate  *
133*0Sstevel@tonic-gate  * uri_hash_sz[] - the size for each uri_hash_ab[].
134*0Sstevel@tonic-gate  *
135*0Sstevel@tonic-gate  * uri_hash_cnt[] - the total uri_desc_t members for each uri_hash_ab[].
136*0Sstevel@tonic-gate  *
137*0Sstevel@tonic-gate  * uri_hash_overflow[] - the uri_hash_cnt[] for each uri_hash_ab[] when
138*0Sstevel@tonic-gate  * a new uri_hash_ab[] needs to be created.
139*0Sstevel@tonic-gate  *
140*0Sstevel@tonic-gate  * uri_hash_ab[] - the uri_hash_t entries.
141*0Sstevel@tonic-gate  *
142*0Sstevel@tonic-gate  * uri_hash_lru[] - the last uri_hash_ab[] walked for lru reclaim.
143*0Sstevel@tonic-gate  */
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate typedef struct uri_hash_s {
146*0Sstevel@tonic-gate 	struct uri_desc_s	*list;		/* List of uri_t(s) */
147*0Sstevel@tonic-gate 	kmutex_t		lock;
148*0Sstevel@tonic-gate } uri_hash_t;
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate #define	URI_HASH_AVRG	5	/* Desired average hash chain length */
151*0Sstevel@tonic-gate #define	URI_HASH_N_INIT	9	/* P2Ps[] initial index */
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate static krwlock_t	uri_hash_access;
154*0Sstevel@tonic-gate static uint32_t		uri_hash_which = 0;
155*0Sstevel@tonic-gate static uint32_t		uri_hash_n[2] = {URI_HASH_N_INIT, 0};
156*0Sstevel@tonic-gate static uint32_t		uri_hash_sz[2] = {0, 0};
157*0Sstevel@tonic-gate static uint32_t		uri_hash_cnt[2] = {0, 0};
158*0Sstevel@tonic-gate static uint32_t		uri_hash_overflow[2] = {0, 0};
159*0Sstevel@tonic-gate static uri_hash_t	*uri_hash_ab[2] = {NULL, NULL};
160*0Sstevel@tonic-gate static uri_hash_t	*uri_hash_lru[2] = {NULL, NULL};
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate /*
163*0Sstevel@tonic-gate  * Primes for N of 3 - 24 where P is first prime less then (2^(N-1))+(2^(N-2))
164*0Sstevel@tonic-gate  * these primes have been foud to be useful for prime sized hash tables.
165*0Sstevel@tonic-gate  */
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate static const int P2Ps[] = {
168*0Sstevel@tonic-gate 	0, 0, 0, 5, 11, 23, 47, 89, 191, 383, 761, 1531, 3067,
169*0Sstevel@tonic-gate 	6143, 12281, 24571, 49139, 98299, 196597, 393209,
170*0Sstevel@tonic-gate 	786431, 1572853, 3145721, 6291449, 12582893, 0};
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate /*
173*0Sstevel@tonic-gate  * Hash macros:
174*0Sstevel@tonic-gate  *
175*0Sstevel@tonic-gate  *    H2A(char *cp, char *ep, char c) - convert the escaped octet (ASCII)
176*0Sstevel@tonic-gate  *    hex multichar of the format "%HH" pointeded to by *cp to a char and
177*0Sstevel@tonic-gate  *    return in c, *ep points to past end of (char *), on return *cp will
178*0Sstevel@tonic-gate  *    point to the last char consumed.
179*0Sstevel@tonic-gate  *
180*0Sstevel@tonic-gate  *    URI_HASH(unsigned hix, char *cp, char *ep) - hash the char(s) from
181*0Sstevel@tonic-gate  *    *cp to *ep to the unsigned hix, cp nor ep are modified.
182*0Sstevel@tonic-gate  *
183*0Sstevel@tonic-gate  *    URI_HASH_STR(unsigned hix, str_t *sp) - hash the str_t *sp.
184*0Sstevel@tonic-gate  *
185*0Sstevel@tonic-gate  *    URI_HASH_IX(unsigned hix, int hsz) - convert the hash value hix to
186*0Sstevel@tonic-gate  *    a hash index 0 - hsz.
187*0Sstevel@tonic-gate  *
188*0Sstevel@tonic-gate  *    URI_HASH_DESC(uri_desc_t *uri, int which, unsigned hix) - hash the
189*0Sstevel@tonic-gate  *    uri_desc_t *uri's str_t path member,
190*0Sstevel@tonic-gate  *
191*0Sstevel@tonic-gate  *    URI_HASH_MIGRATE(from, hp, to) - migrate the uri_hash_t *hp list
192*0Sstevel@tonic-gate  *    uri_desc_t members from hash from to hash to.
193*0Sstevel@tonic-gate  *
194*0Sstevel@tonic-gate  *    URI_HASH_UNLINK(cur, new, hp, puri, uri) - unlink the uri_desc_t
195*0Sstevel@tonic-gate  *    *uri which is a member of the uri_hash_t *hp list with a previous
196*0Sstevel@tonic-gate  *    list member of *puri for the uri_hash_ab[] cur. After unlinking
197*0Sstevel@tonic-gate  *    check for cur hash empty, if so make new cur. Note, as this macro
198*0Sstevel@tonic-gate  *    can change a hash chain it needs to be run under hash_access as
199*0Sstevel@tonic-gate  *    RW_WRITER, futher as it can change the new hash to cur any access
200*0Sstevel@tonic-gate  *    to the hash state must be done after either dropping locks and
201*0Sstevel@tonic-gate  *    starting over or making sure the global state is consistent after
202*0Sstevel@tonic-gate  *    as before.
203*0Sstevel@tonic-gate  */
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate #define	H2A(cp, ep, c) {						\
206*0Sstevel@tonic-gate 	int	_h = 2;							\
207*0Sstevel@tonic-gate 	int	_n = 0;							\
208*0Sstevel@tonic-gate 	char	_hc;							\
209*0Sstevel@tonic-gate 									\
210*0Sstevel@tonic-gate 	while (_h > 0 && ++(cp) < (ep)) {				\
211*0Sstevel@tonic-gate 		if (_h == 1)						\
212*0Sstevel@tonic-gate 			_n *= 0x10;					\
213*0Sstevel@tonic-gate 		_hc = *(cp);						\
214*0Sstevel@tonic-gate 		if (_hc >= '0' && _hc <= '9')				\
215*0Sstevel@tonic-gate 			_n += _hc - '0';				\
216*0Sstevel@tonic-gate 		else if (_hc >= 'a' || _hc <= 'f')			\
217*0Sstevel@tonic-gate 			_n += _hc - 'W';				\
218*0Sstevel@tonic-gate 		else if (_hc >= 'A' || _hc <= 'F')			\
219*0Sstevel@tonic-gate 			_n += _hc - '7';				\
220*0Sstevel@tonic-gate 		_h--;							\
221*0Sstevel@tonic-gate 	}								\
222*0Sstevel@tonic-gate 	(c) = _n;							\
223*0Sstevel@tonic-gate }
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate #define	URI_HASH(hv, cp, ep) {						\
226*0Sstevel@tonic-gate 	char	*_s = (cp);						\
227*0Sstevel@tonic-gate 	char	_c;							\
228*0Sstevel@tonic-gate 									\
229*0Sstevel@tonic-gate 	while (_s < (ep)) {						\
230*0Sstevel@tonic-gate 		if ((_c = *_s) == '%') {				\
231*0Sstevel@tonic-gate 			H2A(_s, (ep), _c);				\
232*0Sstevel@tonic-gate 		}							\
233*0Sstevel@tonic-gate 		(hv) = ((hv) << 5) + (hv) + _c;				\
234*0Sstevel@tonic-gate 		(hv) &= 0x7FFFFFFF;					\
235*0Sstevel@tonic-gate 		_s++;							\
236*0Sstevel@tonic-gate 	}								\
237*0Sstevel@tonic-gate }
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate #define	URI_HASH_STR(hix, sp) URI_HASH(hix, (sp)->cp, (sp)->ep)
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate #define	URI_HASH_IX(hix, hsz) (hix) = (hix) % (hsz)
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate #define	URI_HASH_DESC(uri, which, hix) {				\
244*0Sstevel@tonic-gate 	(hix) = 0;							\
245*0Sstevel@tonic-gate 	URI_HASH_STR((hix), &(uri)->path);				\
246*0Sstevel@tonic-gate 	if ((uri)->auth.cp != NULL) {					\
247*0Sstevel@tonic-gate 		URI_HASH_STR((hix), &(uri)->auth);			\
248*0Sstevel@tonic-gate 	}								\
249*0Sstevel@tonic-gate 	URI_HASH_IX((hix), uri_hash_sz[(which)]);			\
250*0Sstevel@tonic-gate }
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate #define	URI_HASH_MIGRATE(from, hp, to) {				\
253*0Sstevel@tonic-gate 	uri_desc_t	*_nuri;						\
254*0Sstevel@tonic-gate 	uint32_t	_nhix;						\
255*0Sstevel@tonic-gate 	uri_hash_t	*_nhp;						\
256*0Sstevel@tonic-gate 									\
257*0Sstevel@tonic-gate 	mutex_enter(&(hp)->lock);					\
258*0Sstevel@tonic-gate 	while ((_nuri = (hp)->list) != NULL) {				\
259*0Sstevel@tonic-gate 		(hp)->list = _nuri->hash;				\
260*0Sstevel@tonic-gate 		atomic_add_32(&uri_hash_cnt[(from)], -1);		\
261*0Sstevel@tonic-gate 		atomic_add_32(&uri_hash_cnt[(to)], 1);			\
262*0Sstevel@tonic-gate 		URI_HASH_DESC(_nuri, (to), _nhix);			\
263*0Sstevel@tonic-gate 		_nhp = &uri_hash_ab[(to)][_nhix];			\
264*0Sstevel@tonic-gate 		mutex_enter(&_nhp->lock);				\
265*0Sstevel@tonic-gate 		_nuri->hash = _nhp->list;				\
266*0Sstevel@tonic-gate 		_nhp->list = _nuri;					\
267*0Sstevel@tonic-gate 		_nuri->hit = 0;						\
268*0Sstevel@tonic-gate 		mutex_exit(&_nhp->lock);				\
269*0Sstevel@tonic-gate 	}								\
270*0Sstevel@tonic-gate 	mutex_exit(&(hp)->lock);					\
271*0Sstevel@tonic-gate }
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate #define	URI_HASH_UNLINK(cur, new, hp, puri, uri) {			\
274*0Sstevel@tonic-gate 	if ((puri) != NULL) {						\
275*0Sstevel@tonic-gate 		(puri)->hash = (uri)->hash;				\
276*0Sstevel@tonic-gate 	} else {							\
277*0Sstevel@tonic-gate 		(hp)->list = (uri)->hash;				\
278*0Sstevel@tonic-gate 	}								\
279*0Sstevel@tonic-gate 	if (atomic_add_32_nv(&uri_hash_cnt[(cur)], -1) == 0 &&		\
280*0Sstevel@tonic-gate 	    uri_hash_ab[(new)] != NULL) {				\
281*0Sstevel@tonic-gate 		kmem_free(uri_hash_ab[cur],				\
282*0Sstevel@tonic-gate 		    sizeof (uri_hash_t) * uri_hash_sz[cur]);		\
283*0Sstevel@tonic-gate 		uri_hash_ab[(cur)] = NULL;				\
284*0Sstevel@tonic-gate 		uri_hash_lru[(cur)] = NULL;				\
285*0Sstevel@tonic-gate 		uri_hash_which = (new);					\
286*0Sstevel@tonic-gate 	} else {							\
287*0Sstevel@tonic-gate 		uri_hash_lru[(cur)] = (hp);				\
288*0Sstevel@tonic-gate 	}								\
289*0Sstevel@tonic-gate }
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate #define	URI_RD_ADD(uri, rdp, size, offset) {				\
292*0Sstevel@tonic-gate 	if ((uri)->tail == NULL) {					\
293*0Sstevel@tonic-gate 		(rdp) = &(uri)->response;				\
294*0Sstevel@tonic-gate 	} else {							\
295*0Sstevel@tonic-gate 		(rdp) = kmem_cache_alloc(uri_rd_kmc, KM_SLEEP);		\
296*0Sstevel@tonic-gate 		(uri)->tail->next = (rdp);				\
297*0Sstevel@tonic-gate 	}								\
298*0Sstevel@tonic-gate 	(rdp)->sz = size;						\
299*0Sstevel@tonic-gate 	(rdp)->off = offset;						\
300*0Sstevel@tonic-gate 	(rdp)->next = NULL;						\
301*0Sstevel@tonic-gate 	(uri)->tail = rdp;						\
302*0Sstevel@tonic-gate 	(uri)->count += size;						\
303*0Sstevel@tonic-gate }
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate void
306*0Sstevel@tonic-gate nl7c_uri_init(void)
307*0Sstevel@tonic-gate {
308*0Sstevel@tonic-gate 	uint32_t	cur = uri_hash_which;
309*0Sstevel@tonic-gate 
310*0Sstevel@tonic-gate 	rw_init(&uri_hash_access, NULL, RW_DEFAULT, NULL);
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate 	uri_hash_sz[cur] = P2Ps[URI_HASH_N_INIT];
313*0Sstevel@tonic-gate 	uri_hash_overflow[cur] = P2Ps[URI_HASH_N_INIT] * URI_HASH_AVRG;
314*0Sstevel@tonic-gate 	uri_hash_ab[cur] = kmem_zalloc(sizeof (uri_hash_t) * uri_hash_sz[cur],
315*0Sstevel@tonic-gate 	    KM_SLEEP);
316*0Sstevel@tonic-gate 	uri_hash_lru[cur] = uri_hash_ab[cur];
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate 	uri_kmc = kmem_cache_create("NL7C_uri_kmc", sizeof (uri_desc_t), 0,
319*0Sstevel@tonic-gate 	    NULL, NULL, uri_kmc_reclaim, NULL, NULL, 0);
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate 	uri_rd_kmc = kmem_cache_create("NL7C_uri_rd_kmc", sizeof (uri_rd_t), 0,
322*0Sstevel@tonic-gate 	    NULL, NULL, NULL, NULL, NULL, 0);
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate 	uri_desb_kmc = kmem_cache_create("NL7C_uri_desb_kmc",
325*0Sstevel@tonic-gate 	    sizeof (uri_desb_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 	uri_segmap_kmc = kmem_cache_create("NL7C_uri_segmap_kmc",
328*0Sstevel@tonic-gate 	    sizeof (uri_segmap_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate 	nl7c_http_init();
331*0Sstevel@tonic-gate }
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate /*
334*0Sstevel@tonic-gate  * The uri_desc_t ref_t inactive function called on the last REF_RELE(),
335*0Sstevel@tonic-gate  * free all resources contained in the uri_desc_t. Note, the uri_desc_t
336*0Sstevel@tonic-gate  * will be freed by REF_RELE() on return.
337*0Sstevel@tonic-gate  */
338*0Sstevel@tonic-gate 
339*0Sstevel@tonic-gate static void
340*0Sstevel@tonic-gate uri_inactive(uri_desc_t *uri)
341*0Sstevel@tonic-gate {
342*0Sstevel@tonic-gate 	int64_t	 bytes = 0;
343*0Sstevel@tonic-gate 
344*0Sstevel@tonic-gate 	if (uri->tail) {
345*0Sstevel@tonic-gate 		uri_rd_t *rdp = &uri->response;
346*0Sstevel@tonic-gate 		uri_rd_t *free = NULL;
347*0Sstevel@tonic-gate 
348*0Sstevel@tonic-gate 		while (rdp) {
349*0Sstevel@tonic-gate 			if (rdp->off == -1) {
350*0Sstevel@tonic-gate 				bytes += rdp->sz;
351*0Sstevel@tonic-gate 				kmem_free(rdp->data.kmem, rdp->sz);
352*0Sstevel@tonic-gate 			} else {
353*0Sstevel@tonic-gate 				VN_RELE(rdp->data.vnode);
354*0Sstevel@tonic-gate 			}
355*0Sstevel@tonic-gate 			rdp = rdp->next;
356*0Sstevel@tonic-gate 			if (free != NULL) {
357*0Sstevel@tonic-gate 				kmem_cache_free(uri_rd_kmc, free);
358*0Sstevel@tonic-gate 			}
359*0Sstevel@tonic-gate 			free = rdp;
360*0Sstevel@tonic-gate 		}
361*0Sstevel@tonic-gate 	}
362*0Sstevel@tonic-gate 	if (bytes) {
363*0Sstevel@tonic-gate 		atomic_add_64(&nl7c_uri_bytes, -bytes);
364*0Sstevel@tonic-gate 	}
365*0Sstevel@tonic-gate 	if (uri->scheme != NULL) {
366*0Sstevel@tonic-gate 		nl7c_http_free(uri->scheme);
367*0Sstevel@tonic-gate 	}
368*0Sstevel@tonic-gate 	if (uri->reqmp) {
369*0Sstevel@tonic-gate 		freeb(uri->reqmp);
370*0Sstevel@tonic-gate 	}
371*0Sstevel@tonic-gate }
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate /*
374*0Sstevel@tonic-gate  * The reclaim is called by the kmem subsystem when kmem is running
375*0Sstevel@tonic-gate  * low. More work is needed to determine the best reclaim policy, for
376*0Sstevel@tonic-gate  * now we just manipulate the nl7c_uri_max global maximum bytes threshold
377*0Sstevel@tonic-gate  * value using a simple arithmetic backoff of the value every time this
378*0Sstevel@tonic-gate  * function is called then call uri_reclaim() to enforce it.
379*0Sstevel@tonic-gate  *
380*0Sstevel@tonic-gate  * Note, this value remains in place and enforced for all subsequent
381*0Sstevel@tonic-gate  * URI request/response processing.
382*0Sstevel@tonic-gate  *
383*0Sstevel@tonic-gate  * Note, nl7c_uri_max is currently initialized to 0 or infinite such that
384*0Sstevel@tonic-gate  * the first call here set it to the current uri_bytes value then backoff
385*0Sstevel@tonic-gate  * from there.
386*0Sstevel@tonic-gate  *
387*0Sstevel@tonic-gate  * XXX how do we determine when to increase nl7c_uri_max ???
388*0Sstevel@tonic-gate  */
389*0Sstevel@tonic-gate 
390*0Sstevel@tonic-gate /*ARGSUSED*/
391*0Sstevel@tonic-gate static void
392*0Sstevel@tonic-gate uri_kmc_reclaim(void *arg)
393*0Sstevel@tonic-gate {
394*0Sstevel@tonic-gate 	uint64_t new_max;
395*0Sstevel@tonic-gate 
396*0Sstevel@tonic-gate 	if ((new_max = nl7c_uri_max) == 0) {
397*0Sstevel@tonic-gate 		/* Currently infinite, initialize to current bytes used */
398*0Sstevel@tonic-gate 		nl7c_uri_max = nl7c_uri_bytes;
399*0Sstevel@tonic-gate 		new_max = nl7c_uri_bytes;
400*0Sstevel@tonic-gate 	}
401*0Sstevel@tonic-gate 	if (new_max > 1) {
402*0Sstevel@tonic-gate 		/* Lower max_bytes to 93% of current value */
403*0Sstevel@tonic-gate 		new_max >>= 1;			/* 50% */
404*0Sstevel@tonic-gate 		new_max += (new_max >> 1);	/* 75% */
405*0Sstevel@tonic-gate 		new_max += (new_max >> 2);	/* 93% */
406*0Sstevel@tonic-gate 		if (new_max < nl7c_uri_max)
407*0Sstevel@tonic-gate 			nl7c_uri_max = new_max;
408*0Sstevel@tonic-gate 		else
409*0Sstevel@tonic-gate 			nl7c_uri_max = 1;
410*0Sstevel@tonic-gate 	}
411*0Sstevel@tonic-gate 	nl7c_uri_reclaim();
412*0Sstevel@tonic-gate }
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate /*
415*0Sstevel@tonic-gate  * Delete a uri_desc_t from the URI hash.
416*0Sstevel@tonic-gate  */
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate static void
419*0Sstevel@tonic-gate uri_delete(uri_desc_t *del)
420*0Sstevel@tonic-gate {
421*0Sstevel@tonic-gate 	uint32_t	hash = 0;
422*0Sstevel@tonic-gate 	uint32_t	hix;
423*0Sstevel@tonic-gate 	uri_hash_t	*hp;
424*0Sstevel@tonic-gate 	uri_desc_t	*uri;
425*0Sstevel@tonic-gate 	uri_desc_t	*puri;
426*0Sstevel@tonic-gate 	uint32_t	cur;
427*0Sstevel@tonic-gate 	uint32_t	new;
428*0Sstevel@tonic-gate 
429*0Sstevel@tonic-gate 	URI_HASH_STR(hash, &(del->path));
430*0Sstevel@tonic-gate 	if (del->auth.cp != NULL) {
431*0Sstevel@tonic-gate 		/* Calculate hash for request authority */
432*0Sstevel@tonic-gate 		URI_HASH(hash, del->auth.cp, del->auth.ep);
433*0Sstevel@tonic-gate 	}
434*0Sstevel@tonic-gate 	rw_enter(&uri_hash_access, RW_WRITER);
435*0Sstevel@tonic-gate 	cur = uri_hash_which;
436*0Sstevel@tonic-gate 	new = cur ? 0 : 1;
437*0Sstevel@tonic-gate next:
438*0Sstevel@tonic-gate 	puri = NULL;
439*0Sstevel@tonic-gate 	hix = hash;
440*0Sstevel@tonic-gate 	URI_HASH_IX(hix, uri_hash_sz[cur]);
441*0Sstevel@tonic-gate 	hp = &uri_hash_ab[cur][hix];
442*0Sstevel@tonic-gate 	for (uri = hp->list; uri != NULL; uri = uri->hash) {
443*0Sstevel@tonic-gate 		if (uri != del) {
444*0Sstevel@tonic-gate 			puri = uri;
445*0Sstevel@tonic-gate 			continue;
446*0Sstevel@tonic-gate 		}
447*0Sstevel@tonic-gate 		/*
448*0Sstevel@tonic-gate 		 * Found the URI, unlink from the hash chain,
449*0Sstevel@tonic-gate 		 * drop locks, ref release it.
450*0Sstevel@tonic-gate 		 */
451*0Sstevel@tonic-gate 		URI_HASH_UNLINK(cur, new, hp, puri, uri);
452*0Sstevel@tonic-gate 		rw_exit(&uri_hash_access);
453*0Sstevel@tonic-gate 		REF_RELE(uri);
454*0Sstevel@tonic-gate 		return;
455*0Sstevel@tonic-gate 	}
456*0Sstevel@tonic-gate 	if (cur != new && uri_hash_ab[new] != NULL) {
457*0Sstevel@tonic-gate 		/*
458*0Sstevel@tonic-gate 		 * Not found in current hash and have a new hash so
459*0Sstevel@tonic-gate 		 * check the new hash next.
460*0Sstevel@tonic-gate 		 */
461*0Sstevel@tonic-gate 		cur = new;
462*0Sstevel@tonic-gate 		goto next;
463*0Sstevel@tonic-gate 	}
464*0Sstevel@tonic-gate 	rw_exit(&uri_hash_access);
465*0Sstevel@tonic-gate }
466*0Sstevel@tonic-gate 
467*0Sstevel@tonic-gate /*
468*0Sstevel@tonic-gate  * Add a uri_desc_t to the URI hash.
469*0Sstevel@tonic-gate  */
470*0Sstevel@tonic-gate 
471*0Sstevel@tonic-gate static void
472*0Sstevel@tonic-gate uri_add(uri_desc_t *uri, krw_t rwlock, boolean_t nonblocking)
473*0Sstevel@tonic-gate {
474*0Sstevel@tonic-gate 	uint32_t	hix;
475*0Sstevel@tonic-gate 	uri_hash_t	*hp;
476*0Sstevel@tonic-gate 	uint32_t	cur = uri_hash_which;
477*0Sstevel@tonic-gate 	uint32_t	new = cur ? 0 : 1;
478*0Sstevel@tonic-gate 
479*0Sstevel@tonic-gate 	/*
480*0Sstevel@tonic-gate 	 * Caller of uri_add() must hold the uri_hash_access rwlock.
481*0Sstevel@tonic-gate 	 */
482*0Sstevel@tonic-gate 	ASSERT((rwlock == RW_READER && RW_READ_HELD(&uri_hash_access)) ||
483*0Sstevel@tonic-gate 	    (rwlock == RW_WRITER && RW_WRITE_HELD(&uri_hash_access)));
484*0Sstevel@tonic-gate 	/*
485*0Sstevel@tonic-gate 	 * uri_add() always succeeds so add a hash ref to the URI now.
486*0Sstevel@tonic-gate 	 */
487*0Sstevel@tonic-gate 	REF_HOLD(uri);
488*0Sstevel@tonic-gate again:
489*0Sstevel@tonic-gate 	URI_HASH_DESC(uri, cur, hix);
490*0Sstevel@tonic-gate 	if (uri_hash_ab[new] == NULL &&
491*0Sstevel@tonic-gate 	    uri_hash_cnt[cur] < uri_hash_overflow[cur]) {
492*0Sstevel@tonic-gate 		/*
493*0Sstevel@tonic-gate 		 * Easy case, no new hash and current hasn't overflowed,
494*0Sstevel@tonic-gate 		 * add URI to current hash and return.
495*0Sstevel@tonic-gate 		 *
496*0Sstevel@tonic-gate 		 * Note, the check for uri_hash_cnt[] above aren't done
497*0Sstevel@tonic-gate 		 * atomictally, i.e. multiple threads can be in this code
498*0Sstevel@tonic-gate 		 * as RW_READER and update the cnt[], this isn't a problem
499*0Sstevel@tonic-gate 		 * as the check is only advisory.
500*0Sstevel@tonic-gate 		 */
501*0Sstevel@tonic-gate 	fast:
502*0Sstevel@tonic-gate 		atomic_add_32(&uri_hash_cnt[cur], 1);
503*0Sstevel@tonic-gate 		hp = &uri_hash_ab[cur][hix];
504*0Sstevel@tonic-gate 		mutex_enter(&hp->lock);
505*0Sstevel@tonic-gate 		uri->hash = hp->list;
506*0Sstevel@tonic-gate 		hp->list = uri;
507*0Sstevel@tonic-gate 		mutex_exit(&hp->lock);
508*0Sstevel@tonic-gate 		rw_exit(&uri_hash_access);
509*0Sstevel@tonic-gate 		return;
510*0Sstevel@tonic-gate 	}
511*0Sstevel@tonic-gate 	if (uri_hash_ab[new] == NULL) {
512*0Sstevel@tonic-gate 		/*
513*0Sstevel@tonic-gate 		 * Need a new a or b hash, if not already RW_WRITER
514*0Sstevel@tonic-gate 		 * try to upgrade our lock to writer.
515*0Sstevel@tonic-gate 		 */
516*0Sstevel@tonic-gate 		if (rwlock != RW_WRITER && ! rw_tryupgrade(&uri_hash_access)) {
517*0Sstevel@tonic-gate 			/*
518*0Sstevel@tonic-gate 			 * Upgrade failed, we can't simple exit and reenter
519*0Sstevel@tonic-gate 			 * the lock as after the exit and before the reenter
520*0Sstevel@tonic-gate 			 * the whole world can change so just wait for writer
521*0Sstevel@tonic-gate 			 * then do everything again.
522*0Sstevel@tonic-gate 			 */
523*0Sstevel@tonic-gate 			if (nonblocking) {
524*0Sstevel@tonic-gate 				/*
525*0Sstevel@tonic-gate 				 * Can't block, use fast-path above.
526*0Sstevel@tonic-gate 				 *
527*0Sstevel@tonic-gate 				 * XXX should have a background thread to
528*0Sstevel@tonic-gate 				 * handle new ab[] in this case so as to
529*0Sstevel@tonic-gate 				 * not overflow the cur hash to much.
530*0Sstevel@tonic-gate 				 */
531*0Sstevel@tonic-gate 				goto fast;
532*0Sstevel@tonic-gate 			}
533*0Sstevel@tonic-gate 			rw_exit(&uri_hash_access);
534*0Sstevel@tonic-gate 			rwlock = RW_WRITER;
535*0Sstevel@tonic-gate 			rw_enter(&uri_hash_access, rwlock);
536*0Sstevel@tonic-gate 			cur = uri_hash_which;
537*0Sstevel@tonic-gate 			new = cur ? 0 : 1;
538*0Sstevel@tonic-gate 			goto again;
539*0Sstevel@tonic-gate 		}
540*0Sstevel@tonic-gate 		rwlock = RW_WRITER;
541*0Sstevel@tonic-gate 		if (uri_hash_ab[new] == NULL) {
542*0Sstevel@tonic-gate 			/*
543*0Sstevel@tonic-gate 			 * Still need a new hash, allocate and initialize
544*0Sstevel@tonic-gate 			 * the new hash.
545*0Sstevel@tonic-gate 			 */
546*0Sstevel@tonic-gate 			uri_hash_n[new] = uri_hash_n[cur] + 1;
547*0Sstevel@tonic-gate 			if (uri_hash_n[new] == 0) {
548*0Sstevel@tonic-gate 				/*
549*0Sstevel@tonic-gate 				 * No larger P2Ps[] value so use current,
550*0Sstevel@tonic-gate 				 * i.e. 2 of the largest are better than 1 ?
551*0Sstevel@tonic-gate 				 */
552*0Sstevel@tonic-gate 				uri_hash_n[new] = uri_hash_n[cur];
553*0Sstevel@tonic-gate 				cmn_err(CE_NOTE, "NL7C: hash index overflow");
554*0Sstevel@tonic-gate 			}
555*0Sstevel@tonic-gate 			uri_hash_sz[new] = P2Ps[uri_hash_n[new]];
556*0Sstevel@tonic-gate 			ASSERT(uri_hash_cnt[new] == 0);
557*0Sstevel@tonic-gate 			uri_hash_overflow[new] = uri_hash_sz[new] *
558*0Sstevel@tonic-gate 			    URI_HASH_AVRG;
559*0Sstevel@tonic-gate 			uri_hash_ab[new] = kmem_zalloc(sizeof (uri_hash_t) *
560*0Sstevel@tonic-gate 			    uri_hash_sz[new], nonblocking ? KM_NOSLEEP :
561*0Sstevel@tonic-gate 			    KM_SLEEP);
562*0Sstevel@tonic-gate 			if (uri_hash_ab[new] == NULL) {
563*0Sstevel@tonic-gate 				/*
564*0Sstevel@tonic-gate 				 * Alloc failed, use fast-path above.
565*0Sstevel@tonic-gate 				 *
566*0Sstevel@tonic-gate 				 * XXX should have a background thread to
567*0Sstevel@tonic-gate 				 * handle new ab[] in this case so as to
568*0Sstevel@tonic-gate 				 * not overflow the cur hash to much.
569*0Sstevel@tonic-gate 				 */
570*0Sstevel@tonic-gate 				goto fast;
571*0Sstevel@tonic-gate 			}
572*0Sstevel@tonic-gate 			uri_hash_lru[new] = uri_hash_ab[new];
573*0Sstevel@tonic-gate 		}
574*0Sstevel@tonic-gate 	}
575*0Sstevel@tonic-gate 	/*
576*0Sstevel@tonic-gate 	 * Hashed against current hash so migrate any current hash chain
577*0Sstevel@tonic-gate 	 * members, if any.
578*0Sstevel@tonic-gate 	 *
579*0Sstevel@tonic-gate 	 * Note, the hash chain list can be checked for a non empty list
580*0Sstevel@tonic-gate 	 * outside of the hash chain list lock as the hash chain struct
581*0Sstevel@tonic-gate 	 * can't be destroyed while in the uri_hash_access rwlock, worst
582*0Sstevel@tonic-gate 	 * case is that a non empty list is found and after acquiring the
583*0Sstevel@tonic-gate 	 * lock another thread beats us to it (i.e. migrated the list).
584*0Sstevel@tonic-gate 	 */
585*0Sstevel@tonic-gate 	hp = &uri_hash_ab[cur][hix];
586*0Sstevel@tonic-gate 	if (hp->list != NULL) {
587*0Sstevel@tonic-gate 		URI_HASH_MIGRATE(cur, hp, new);
588*0Sstevel@tonic-gate 	}
589*0Sstevel@tonic-gate 	/*
590*0Sstevel@tonic-gate 	 * If new hash has overflowed before current hash has been
591*0Sstevel@tonic-gate 	 * completely migrated then walk all current hash chains and
592*0Sstevel@tonic-gate 	 * migrate list members now.
593*0Sstevel@tonic-gate 	 */
594*0Sstevel@tonic-gate 	if (atomic_add_32_nv(&uri_hash_cnt[new], 1) >= uri_hash_overflow[new]) {
595*0Sstevel@tonic-gate 		for (hix = 0; hix < uri_hash_sz[cur]; hix++) {
596*0Sstevel@tonic-gate 			hp = &uri_hash_ab[cur][hix];
597*0Sstevel@tonic-gate 			if (hp->list != NULL) {
598*0Sstevel@tonic-gate 				URI_HASH_MIGRATE(cur, hp, new);
599*0Sstevel@tonic-gate 			}
600*0Sstevel@tonic-gate 		}
601*0Sstevel@tonic-gate 	}
602*0Sstevel@tonic-gate 	/*
603*0Sstevel@tonic-gate 	 * Add URI to new hash.
604*0Sstevel@tonic-gate 	 */
605*0Sstevel@tonic-gate 	URI_HASH_DESC(uri, new, hix);
606*0Sstevel@tonic-gate 	hp = &uri_hash_ab[new][hix];
607*0Sstevel@tonic-gate 	mutex_enter(&hp->lock);
608*0Sstevel@tonic-gate 	uri->hash = hp->list;
609*0Sstevel@tonic-gate 	hp->list = uri;
610*0Sstevel@tonic-gate 	mutex_exit(&hp->lock);
611*0Sstevel@tonic-gate 	/*
612*0Sstevel@tonic-gate 	 * Last, check to see if last cur hash chain has been
613*0Sstevel@tonic-gate 	 * migrated, if so free cur hash and make new hash cur.
614*0Sstevel@tonic-gate 	 */
615*0Sstevel@tonic-gate 	if (uri_hash_cnt[cur] == 0) {
616*0Sstevel@tonic-gate 		/*
617*0Sstevel@tonic-gate 		 * If we don't already hold the uri_hash_access rwlock for
618*0Sstevel@tonic-gate 		 * RW_WRITE try to upgrade to RW_WRITE and if successful
619*0Sstevel@tonic-gate 		 * check again and to see if still need to do the free.
620*0Sstevel@tonic-gate 		 */
621*0Sstevel@tonic-gate 		if ((rwlock == RW_WRITER || rw_tryupgrade(&uri_hash_access)) &&
622*0Sstevel@tonic-gate 		    uri_hash_cnt[cur] == 0 && uri_hash_ab[new] != 0) {
623*0Sstevel@tonic-gate 			kmem_free(uri_hash_ab[cur],
624*0Sstevel@tonic-gate 			    sizeof (uri_hash_t) * uri_hash_sz[cur]);
625*0Sstevel@tonic-gate 			uri_hash_ab[cur] = NULL;
626*0Sstevel@tonic-gate 			uri_hash_lru[cur] = NULL;
627*0Sstevel@tonic-gate 			uri_hash_which = new;
628*0Sstevel@tonic-gate 		}
629*0Sstevel@tonic-gate 	}
630*0Sstevel@tonic-gate 	rw_exit(&uri_hash_access);
631*0Sstevel@tonic-gate }
632*0Sstevel@tonic-gate 
633*0Sstevel@tonic-gate /*
634*0Sstevel@tonic-gate  * Lookup a uri_desc_t in the URI hash, if found free the request uri_desc_t
635*0Sstevel@tonic-gate  * and return the found uri_desc_t with a REF_HOLD() placed on it. Else, use
636*0Sstevel@tonic-gate  * the request URI to create a new hash entry.
637*0Sstevel@tonic-gate  */
638*0Sstevel@tonic-gate 
639*0Sstevel@tonic-gate static uri_desc_t *
640*0Sstevel@tonic-gate uri_lookup(uri_desc_t *ruri, boolean_t add, boolean_t nonblocking)
641*0Sstevel@tonic-gate {
642*0Sstevel@tonic-gate 	uint32_t	hash = 0;
643*0Sstevel@tonic-gate 	uint32_t	hix;
644*0Sstevel@tonic-gate 	uri_hash_t	*hp;
645*0Sstevel@tonic-gate 	uri_desc_t	*uri;
646*0Sstevel@tonic-gate 	uri_desc_t	*puri;
647*0Sstevel@tonic-gate 	uint32_t	cur;
648*0Sstevel@tonic-gate 	uint32_t	new;
649*0Sstevel@tonic-gate 	char		*rcp = ruri->path.cp;
650*0Sstevel@tonic-gate 	char		*rep = ruri->path.ep;
651*0Sstevel@tonic-gate 
652*0Sstevel@tonic-gate 	/* Calculate hash for request path */
653*0Sstevel@tonic-gate 	URI_HASH(hash, rcp, rep);
654*0Sstevel@tonic-gate 	if (ruri->auth.cp != NULL) {
655*0Sstevel@tonic-gate 		/* Calculate hash for request authority */
656*0Sstevel@tonic-gate 		URI_HASH(hash, ruri->auth.cp, ruri->auth.ep);
657*0Sstevel@tonic-gate 	}
658*0Sstevel@tonic-gate again:
659*0Sstevel@tonic-gate 	rw_enter(&uri_hash_access, RW_READER);
660*0Sstevel@tonic-gate 	cur = uri_hash_which;
661*0Sstevel@tonic-gate 	new = cur ? 0 : 1;
662*0Sstevel@tonic-gate nexthash:
663*0Sstevel@tonic-gate 	puri = NULL;
664*0Sstevel@tonic-gate 	hix = hash;
665*0Sstevel@tonic-gate 	URI_HASH_IX(hix, uri_hash_sz[cur]);
666*0Sstevel@tonic-gate 	hp = &uri_hash_ab[cur][hix];
667*0Sstevel@tonic-gate 	mutex_enter(&hp->lock);
668*0Sstevel@tonic-gate 	for (uri = hp->list; uri != NULL; uri = uri->hash) {
669*0Sstevel@tonic-gate 		char	*ap = uri->path.cp;
670*0Sstevel@tonic-gate 		char	*bp = rcp;
671*0Sstevel@tonic-gate 		char	a, b;
672*0Sstevel@tonic-gate 
673*0Sstevel@tonic-gate 		/* Compare paths */
674*0Sstevel@tonic-gate 		while (bp < rep && ap < uri->path.ep) {
675*0Sstevel@tonic-gate 			if ((a = *ap) == '%') {
676*0Sstevel@tonic-gate 				/* Escaped hex multichar, convert it */
677*0Sstevel@tonic-gate 				H2A(ap, uri->path.ep, a);
678*0Sstevel@tonic-gate 			}
679*0Sstevel@tonic-gate 			if ((b = *bp) == '%') {
680*0Sstevel@tonic-gate 				/* Escaped hex multichar, convert it */
681*0Sstevel@tonic-gate 				H2A(bp, rep, b);
682*0Sstevel@tonic-gate 			}
683*0Sstevel@tonic-gate 			if (a != b) {
684*0Sstevel@tonic-gate 				/* Char's don't match */
685*0Sstevel@tonic-gate 				goto nexturi;
686*0Sstevel@tonic-gate 			}
687*0Sstevel@tonic-gate 			ap++;
688*0Sstevel@tonic-gate 			bp++;
689*0Sstevel@tonic-gate 		}
690*0Sstevel@tonic-gate 		if (bp != rep || ap != uri->path.ep) {
691*0Sstevel@tonic-gate 			/* Not same length */
692*0Sstevel@tonic-gate 			goto nexturi;
693*0Sstevel@tonic-gate 		}
694*0Sstevel@tonic-gate 		ap = uri->auth.cp;
695*0Sstevel@tonic-gate 		bp = ruri->auth.cp;
696*0Sstevel@tonic-gate 		if (ap != NULL) {
697*0Sstevel@tonic-gate 			if (bp == NULL) {
698*0Sstevel@tonic-gate 				/* URI has auth request URI doesn't */
699*0Sstevel@tonic-gate 				goto nexturi;
700*0Sstevel@tonic-gate 			}
701*0Sstevel@tonic-gate 			while (bp < ruri->auth.ep && ap < uri->auth.ep) {
702*0Sstevel@tonic-gate 				if ((a = *ap) == '%') {
703*0Sstevel@tonic-gate 					/* Escaped hex multichar, convert it */
704*0Sstevel@tonic-gate 					H2A(ap, uri->path.ep, a);
705*0Sstevel@tonic-gate 				}
706*0Sstevel@tonic-gate 				if ((b = *bp) == '%') {
707*0Sstevel@tonic-gate 					/* Escaped hex multichar, convert it */
708*0Sstevel@tonic-gate 					H2A(bp, rep, b);
709*0Sstevel@tonic-gate 				}
710*0Sstevel@tonic-gate 				if (a != b) {
711*0Sstevel@tonic-gate 					/* Char's don't match */
712*0Sstevel@tonic-gate 					goto nexturi;
713*0Sstevel@tonic-gate 				}
714*0Sstevel@tonic-gate 				ap++;
715*0Sstevel@tonic-gate 				bp++;
716*0Sstevel@tonic-gate 			}
717*0Sstevel@tonic-gate 			if (bp != ruri->auth.ep || ap != uri->auth.ep) {
718*0Sstevel@tonic-gate 				/* Not same length */
719*0Sstevel@tonic-gate 				goto nexturi;
720*0Sstevel@tonic-gate 			}
721*0Sstevel@tonic-gate 		} else if (bp != NULL) {
722*0Sstevel@tonic-gate 			/* URI doesn't have auth and request URI does */
723*0Sstevel@tonic-gate 			goto nexturi;
724*0Sstevel@tonic-gate 		}
725*0Sstevel@tonic-gate 		if (uri->scheme != NULL) {
726*0Sstevel@tonic-gate 			if (ruri->scheme == NULL) {
727*0Sstevel@tonic-gate 				/*
728*0Sstevel@tonic-gate 				 * URI has scheme private qualifiers,
729*0Sstevel@tonic-gate 				 * request URI doesn't.
730*0Sstevel@tonic-gate 				 */
731*0Sstevel@tonic-gate 				goto nexturi;
732*0Sstevel@tonic-gate 			}
733*0Sstevel@tonic-gate 			if (! nl7c_http_cmp(uri->scheme, ruri->scheme)) {
734*0Sstevel@tonic-gate 				/* No match */
735*0Sstevel@tonic-gate 				goto nexturi;
736*0Sstevel@tonic-gate 			}
737*0Sstevel@tonic-gate 		} else if (ruri->scheme != NULL) {
738*0Sstevel@tonic-gate 			/*
739*0Sstevel@tonic-gate 			 * URI doesn't have scheme private qualifiers,
740*0Sstevel@tonic-gate 			 * request URI does.
741*0Sstevel@tonic-gate 			 */
742*0Sstevel@tonic-gate 			goto nexturi;
743*0Sstevel@tonic-gate 		}
744*0Sstevel@tonic-gate 		/*
745*0Sstevel@tonic-gate 		 * Have a match, check for expire or request no cache.
746*0Sstevel@tonic-gate 		 */
747*0Sstevel@tonic-gate 		if (uri->expire >= 0 && uri->expire <= lbolt || ruri->nocache) {
748*0Sstevel@tonic-gate 			/*
749*0Sstevel@tonic-gate 			 * URI has expired or request specified to not use
750*0Sstevel@tonic-gate 			 * the cached version, unlink the URI from the hash
751*0Sstevel@tonic-gate 			 * chain, release all locks, release the hash ref
752*0Sstevel@tonic-gate 			 * on the URI, and last look it up again.
753*0Sstevel@tonic-gate 			 */
754*0Sstevel@tonic-gate 			if (puri != NULL) {
755*0Sstevel@tonic-gate 				puri->hash = uri->hash;
756*0Sstevel@tonic-gate 			} else {
757*0Sstevel@tonic-gate 				hp->list = uri->hash;
758*0Sstevel@tonic-gate 			}
759*0Sstevel@tonic-gate 			mutex_exit(&hp->lock);
760*0Sstevel@tonic-gate 			atomic_add_32(&uri_hash_cnt[cur], -1);
761*0Sstevel@tonic-gate 			rw_exit(&uri_hash_access);
762*0Sstevel@tonic-gate 			nl7c_uri_expire++;
763*0Sstevel@tonic-gate 			REF_RELE(uri);
764*0Sstevel@tonic-gate 			goto again;
765*0Sstevel@tonic-gate 		}
766*0Sstevel@tonic-gate 		/*
767*0Sstevel@tonic-gate 		 * Ready URI for return, put a reference hold on the URI,
768*0Sstevel@tonic-gate 		 * if this URI is currently being processed (i.e. filled)
769*0Sstevel@tonic-gate 		 * then wait for the processing to be completed first, free
770*0Sstevel@tonic-gate 		 * up the request URI and return the matched URI.
771*0Sstevel@tonic-gate 		 */
772*0Sstevel@tonic-gate 		REF_HOLD(uri);
773*0Sstevel@tonic-gate 		mutex_enter(&uri->proclock);
774*0Sstevel@tonic-gate 		if (uri->proc != NULL) {
775*0Sstevel@tonic-gate 			/* The URI is being processed, wait for completion */
776*0Sstevel@tonic-gate 			mutex_exit(&hp->lock);
777*0Sstevel@tonic-gate 			rw_exit(&uri_hash_access);
778*0Sstevel@tonic-gate 			if (! nonblocking &&
779*0Sstevel@tonic-gate 			    cv_wait_sig(&uri->waiting, &uri->proclock)) {
780*0Sstevel@tonic-gate 				/*
781*0Sstevel@tonic-gate 				 * URI has been processed but things may
782*0Sstevel@tonic-gate 				 * have changed while we were away so do
783*0Sstevel@tonic-gate 				 * most everything again.
784*0Sstevel@tonic-gate 				 */
785*0Sstevel@tonic-gate 				mutex_exit(&uri->proclock);
786*0Sstevel@tonic-gate 				REF_RELE(uri);
787*0Sstevel@tonic-gate 				goto again;
788*0Sstevel@tonic-gate 			} else {
789*0Sstevel@tonic-gate 				/*
790*0Sstevel@tonic-gate 				 * A nonblocking socket or an interrupted
791*0Sstevel@tonic-gate 				 * cv_wait_sig() in the first case can't
792*0Sstevel@tonic-gate 				 * block waiting for the processing of the
793*0Sstevel@tonic-gate 				 * uri hash hit uri to complete, in both
794*0Sstevel@tonic-gate 				 * cases just return failure to lookup.
795*0Sstevel@tonic-gate 				 */
796*0Sstevel@tonic-gate 				mutex_exit(&uri->proclock);
797*0Sstevel@tonic-gate 				REF_RELE(uri);
798*0Sstevel@tonic-gate 				REF_RELE(ruri);
799*0Sstevel@tonic-gate 				return (NULL);
800*0Sstevel@tonic-gate 			}
801*0Sstevel@tonic-gate 		} else {
802*0Sstevel@tonic-gate 			mutex_exit(&uri->proclock);
803*0Sstevel@tonic-gate 		}
804*0Sstevel@tonic-gate 		uri->hit++;
805*0Sstevel@tonic-gate 		mutex_exit(&hp->lock);
806*0Sstevel@tonic-gate 		rw_exit(&uri_hash_access);
807*0Sstevel@tonic-gate 		REF_RELE(ruri);
808*0Sstevel@tonic-gate 		return (uri);
809*0Sstevel@tonic-gate 	nexturi:
810*0Sstevel@tonic-gate 		puri = uri;
811*0Sstevel@tonic-gate 	}
812*0Sstevel@tonic-gate 	mutex_exit(&hp->lock);
813*0Sstevel@tonic-gate 	if (cur != new && uri_hash_ab[new] != NULL) {
814*0Sstevel@tonic-gate 		/*
815*0Sstevel@tonic-gate 		 * Not found in current hash and have a new hash so
816*0Sstevel@tonic-gate 		 * check the new hash next.
817*0Sstevel@tonic-gate 		 */
818*0Sstevel@tonic-gate 		cur = new;
819*0Sstevel@tonic-gate 		goto nexthash;
820*0Sstevel@tonic-gate 	}
821*0Sstevel@tonic-gate add:
822*0Sstevel@tonic-gate 	if (! add) {
823*0Sstevel@tonic-gate 		/*
824*0Sstevel@tonic-gate 		 * Lookup only so free the
825*0Sstevel@tonic-gate 		 * request URI and return.
826*0Sstevel@tonic-gate 		 */
827*0Sstevel@tonic-gate 		rw_exit(&uri_hash_access);
828*0Sstevel@tonic-gate 		REF_RELE(ruri);
829*0Sstevel@tonic-gate 		return (NULL);
830*0Sstevel@tonic-gate 	}
831*0Sstevel@tonic-gate 	/*
832*0Sstevel@tonic-gate 	 * URI not hashed, finish intialization of the
833*0Sstevel@tonic-gate 	 * request URI, add it to the hash, return it.
834*0Sstevel@tonic-gate 	 */
835*0Sstevel@tonic-gate 	ruri->hit = 0;
836*0Sstevel@tonic-gate 	ruri->expire = -1;
837*0Sstevel@tonic-gate 	ruri->response.sz = 0;
838*0Sstevel@tonic-gate 	cv_init(&ruri->waiting, NULL, CV_DEFAULT, NULL);
839*0Sstevel@tonic-gate 	mutex_init(&ruri->proclock, NULL, MUTEX_DEFAULT, NULL);
840*0Sstevel@tonic-gate 	uri_add(ruri, RW_READER, nonblocking);
841*0Sstevel@tonic-gate 	/* uri_add() has done rw_exit(&uri_hash_access) */
842*0Sstevel@tonic-gate 	return (ruri);
843*0Sstevel@tonic-gate }
844*0Sstevel@tonic-gate 
845*0Sstevel@tonic-gate /*
846*0Sstevel@tonic-gate  * Reclaim URIs until max cache size threshold has been reached.
847*0Sstevel@tonic-gate  *
848*0Sstevel@tonic-gate  * A CLOCK based reclaim modified with a history (hit counter) counter.
849*0Sstevel@tonic-gate  */
850*0Sstevel@tonic-gate 
851*0Sstevel@tonic-gate static void
852*0Sstevel@tonic-gate nl7c_uri_reclaim(void)
853*0Sstevel@tonic-gate {
854*0Sstevel@tonic-gate 	uri_hash_t	*hp, *start, *pend;
855*0Sstevel@tonic-gate 	uri_desc_t	*uri;
856*0Sstevel@tonic-gate 	uri_desc_t	*puri;
857*0Sstevel@tonic-gate 	uint32_t	cur;
858*0Sstevel@tonic-gate 	uint32_t	new;
859*0Sstevel@tonic-gate 
860*0Sstevel@tonic-gate 	nl7c_uri_reclaim_calls++;
861*0Sstevel@tonic-gate again:
862*0Sstevel@tonic-gate 	rw_enter(&uri_hash_access, RW_WRITER);
863*0Sstevel@tonic-gate 	cur = uri_hash_which;
864*0Sstevel@tonic-gate 	new = cur ? 0 : 1;
865*0Sstevel@tonic-gate next:
866*0Sstevel@tonic-gate 	hp = uri_hash_lru[cur];
867*0Sstevel@tonic-gate 	start = hp;
868*0Sstevel@tonic-gate 	pend = &uri_hash_ab[cur][uri_hash_sz[cur]];
869*0Sstevel@tonic-gate 	while (nl7c_uri_bytes > nl7c_uri_max) {
870*0Sstevel@tonic-gate 		puri = NULL;
871*0Sstevel@tonic-gate 		for (uri = hp->list; uri != NULL; uri = uri->hash) {
872*0Sstevel@tonic-gate 			if (uri->hit != 0) {
873*0Sstevel@tonic-gate 				/*
874*0Sstevel@tonic-gate 				 * Decrement URI activity counter and skip.
875*0Sstevel@tonic-gate 				 */
876*0Sstevel@tonic-gate 				uri->hit--;
877*0Sstevel@tonic-gate 				puri = uri;
878*0Sstevel@tonic-gate 				continue;
879*0Sstevel@tonic-gate 			}
880*0Sstevel@tonic-gate 			if (uri->proc != NULL) {
881*0Sstevel@tonic-gate 				/*
882*0Sstevel@tonic-gate 				 * Currently being processed by a socket, skip.
883*0Sstevel@tonic-gate 				 */
884*0Sstevel@tonic-gate 				continue;
885*0Sstevel@tonic-gate 			}
886*0Sstevel@tonic-gate 			/*
887*0Sstevel@tonic-gate 			 * Found a candidate, no hit(s) since added or last
888*0Sstevel@tonic-gate 			 * reclaim pass, unlink from it's hash chain, update
889*0Sstevel@tonic-gate 			 * lru scan pointer, drop lock, ref release it.
890*0Sstevel@tonic-gate 			 */
891*0Sstevel@tonic-gate 			URI_HASH_UNLINK(cur, new, hp, puri, uri);
892*0Sstevel@tonic-gate 			if (cur == uri_hash_which) {
893*0Sstevel@tonic-gate 				if (++hp == pend) {
894*0Sstevel@tonic-gate 					/* Wrap pointer */
895*0Sstevel@tonic-gate 					hp = uri_hash_ab[cur];
896*0Sstevel@tonic-gate 				}
897*0Sstevel@tonic-gate 				uri_hash_lru[cur] = hp;
898*0Sstevel@tonic-gate 			}
899*0Sstevel@tonic-gate 			rw_exit(&uri_hash_access);
900*0Sstevel@tonic-gate 			REF_RELE(uri);
901*0Sstevel@tonic-gate 			nl7c_uri_reclaim_cnt++;
902*0Sstevel@tonic-gate 			goto again;
903*0Sstevel@tonic-gate 		}
904*0Sstevel@tonic-gate 		if (++hp == pend) {
905*0Sstevel@tonic-gate 			/* Wrap pointer */
906*0Sstevel@tonic-gate 			hp = uri_hash_ab[cur];
907*0Sstevel@tonic-gate 		}
908*0Sstevel@tonic-gate 		if (hp == start) {
909*0Sstevel@tonic-gate 			if (cur != new && uri_hash_ab[new] != NULL) {
910*0Sstevel@tonic-gate 				/*
911*0Sstevel@tonic-gate 				 * Done with the current hash and have a
912*0Sstevel@tonic-gate 				 * new hash so check the new hash next.
913*0Sstevel@tonic-gate 				 */
914*0Sstevel@tonic-gate 				cur = new;
915*0Sstevel@tonic-gate 				goto next;
916*0Sstevel@tonic-gate 			}
917*0Sstevel@tonic-gate 		}
918*0Sstevel@tonic-gate 	}
919*0Sstevel@tonic-gate 	rw_exit(&uri_hash_access);
920*0Sstevel@tonic-gate }
921*0Sstevel@tonic-gate 
922*0Sstevel@tonic-gate /*
923*0Sstevel@tonic-gate  * Called for a socket which is being freed prior to close, e.g. errored.
924*0Sstevel@tonic-gate  */
925*0Sstevel@tonic-gate 
926*0Sstevel@tonic-gate void
927*0Sstevel@tonic-gate nl7c_urifree(struct sonode *so)
928*0Sstevel@tonic-gate {
929*0Sstevel@tonic-gate 	uri_desc_t *uri = (uri_desc_t *)so->so_nl7c_uri;
930*0Sstevel@tonic-gate 
931*0Sstevel@tonic-gate 	so->so_nl7c_uri = NULL;
932*0Sstevel@tonic-gate 	if (uri->hash != URI_TEMP) {
933*0Sstevel@tonic-gate 		uri_delete(uri);
934*0Sstevel@tonic-gate 		mutex_enter(&uri->proclock);
935*0Sstevel@tonic-gate 		uri->proc = NULL;
936*0Sstevel@tonic-gate 		if (CV_HAS_WAITERS(&uri->waiting)) {
937*0Sstevel@tonic-gate 			cv_broadcast(&uri->waiting);
938*0Sstevel@tonic-gate 		}
939*0Sstevel@tonic-gate 		mutex_exit(&uri->proclock);
940*0Sstevel@tonic-gate 		nl7c_uri_free++;
941*0Sstevel@tonic-gate 	} else {
942*0Sstevel@tonic-gate 		/* No proclock as uri exclusively owned by so */
943*0Sstevel@tonic-gate 		uri->proc = NULL;
944*0Sstevel@tonic-gate 		nl7c_uri_temp_free++;
945*0Sstevel@tonic-gate 	}
946*0Sstevel@tonic-gate 	REF_RELE(uri);
947*0Sstevel@tonic-gate }
948*0Sstevel@tonic-gate 
949*0Sstevel@tonic-gate /*
950*0Sstevel@tonic-gate  * Called to copy some application response data.
951*0Sstevel@tonic-gate  */
952*0Sstevel@tonic-gate 
953*0Sstevel@tonic-gate volatile uint64_t nl7c_data_pfail = 0;
954*0Sstevel@tonic-gate volatile uint64_t nl7c_data_ntemp = 0;
955*0Sstevel@tonic-gate volatile uint64_t nl7c_data_ncntl = 0;
956*0Sstevel@tonic-gate 
957*0Sstevel@tonic-gate void
958*0Sstevel@tonic-gate nl7c_data(struct sonode *so, uio_t *uiop)
959*0Sstevel@tonic-gate {
960*0Sstevel@tonic-gate 	uri_desc_t	*uri = (uri_desc_t *)so->so_nl7c_uri;
961*0Sstevel@tonic-gate 	iovec_t		*iovp = uiop->uio_iov;
962*0Sstevel@tonic-gate 	int		resid = uiop->uio_resid;
963*0Sstevel@tonic-gate 	int		sz, len, cnt;
964*0Sstevel@tonic-gate 	char		*alloc;
965*0Sstevel@tonic-gate 	char		*data;
966*0Sstevel@tonic-gate 	char		*bp;
967*0Sstevel@tonic-gate 	uri_rd_t	*rdp;
968*0Sstevel@tonic-gate 	int		error = 0;
969*0Sstevel@tonic-gate 
970*0Sstevel@tonic-gate 	nl7c_uri_data++;
971*0Sstevel@tonic-gate 
972*0Sstevel@tonic-gate 	if (uri == NULL) {
973*0Sstevel@tonic-gate 		/* Socket & NL7C out of sync, disable NL7C */
974*0Sstevel@tonic-gate 		so->so_nl7c_flags = 0;
975*0Sstevel@tonic-gate 		nl7c_uri_NULL1++;
976*0Sstevel@tonic-gate 		return;
977*0Sstevel@tonic-gate 	}
978*0Sstevel@tonic-gate 
979*0Sstevel@tonic-gate 	if (so->so_nl7c_flags & NL7C_WAITWRITE)
980*0Sstevel@tonic-gate 		so->so_nl7c_flags &= ~NL7C_WAITWRITE;
981*0Sstevel@tonic-gate 
982*0Sstevel@tonic-gate 	if (uri->hash == URI_TEMP) {
983*0Sstevel@tonic-gate 		if (uri->resplen == -1)
984*0Sstevel@tonic-gate 			sz = MIN(resid, URI_TEMP_PARSE_SZ);
985*0Sstevel@tonic-gate 		else
986*0Sstevel@tonic-gate 			sz = 0;
987*0Sstevel@tonic-gate 	} else {
988*0Sstevel@tonic-gate 		sz = resid;
989*0Sstevel@tonic-gate 	}
990*0Sstevel@tonic-gate 	if (sz > 0) {
991*0Sstevel@tonic-gate 		alloc = kmem_alloc(sz, KM_SLEEP);
992*0Sstevel@tonic-gate 	} else {
993*0Sstevel@tonic-gate 		alloc = NULL;
994*0Sstevel@tonic-gate 	}
995*0Sstevel@tonic-gate 	if (uri->hash == URI_TEMP) {
996*0Sstevel@tonic-gate 		uri->count += resid;
997*0Sstevel@tonic-gate 		data = alloc;
998*0Sstevel@tonic-gate 	} else {
999*0Sstevel@tonic-gate 		URI_RD_ADD(uri, rdp, sz, -1);
1000*0Sstevel@tonic-gate 		if (rdp == NULL)
1001*0Sstevel@tonic-gate 			goto fail;
1002*0Sstevel@tonic-gate 		rdp->data.kmem = alloc;
1003*0Sstevel@tonic-gate 		data = alloc;
1004*0Sstevel@tonic-gate 		alloc = NULL;
1005*0Sstevel@tonic-gate 	}
1006*0Sstevel@tonic-gate 	bp = data;
1007*0Sstevel@tonic-gate 	for (len = sz; len > 0; len -= cnt) {
1008*0Sstevel@tonic-gate 		cnt = MIN(len, iovp->iov_len);
1009*0Sstevel@tonic-gate 		error = xcopyin(iovp->iov_base, bp, cnt);
1010*0Sstevel@tonic-gate 		if (error) {
1011*0Sstevel@tonic-gate 			goto fail;
1012*0Sstevel@tonic-gate 		}
1013*0Sstevel@tonic-gate 		bp += cnt;
1014*0Sstevel@tonic-gate 		iovp++;
1015*0Sstevel@tonic-gate 	}
1016*0Sstevel@tonic-gate 	bp = data;
1017*0Sstevel@tonic-gate 	if (uri->resplen == -1 &&
1018*0Sstevel@tonic-gate 	    ! nl7c_http_response(&bp, &bp[sz], uri, so) &&
1019*0Sstevel@tonic-gate 	    (bp == NULL || uri->hash != URI_TEMP || uri->resplen == -1)) {
1020*0Sstevel@tonic-gate 		/*
1021*0Sstevel@tonic-gate 		 * Parse not complete and parse failed or not TEMP
1022*0Sstevel@tonic-gate 		 * partial parse or TEMP partial parse and no resplen.
1023*0Sstevel@tonic-gate 		 */
1024*0Sstevel@tonic-gate 		if (bp == NULL)
1025*0Sstevel@tonic-gate 			nl7c_data_pfail++;
1026*0Sstevel@tonic-gate 		else if (uri->hash != URI_TEMP)
1027*0Sstevel@tonic-gate 			nl7c_data_ntemp++;
1028*0Sstevel@tonic-gate 		else if (uri->resplen == -1)
1029*0Sstevel@tonic-gate 			nl7c_data_ncntl++;
1030*0Sstevel@tonic-gate 		goto fail;
1031*0Sstevel@tonic-gate 	}
1032*0Sstevel@tonic-gate 	if (uri->resplen != -1 && uri->count >= uri->resplen) {
1033*0Sstevel@tonic-gate 		/* Got the response data, close the uri */
1034*0Sstevel@tonic-gate 		nl7c_close(so);
1035*0Sstevel@tonic-gate 	}
1036*0Sstevel@tonic-gate 	if (alloc != NULL) {
1037*0Sstevel@tonic-gate 		kmem_free(alloc, sz);
1038*0Sstevel@tonic-gate 	} else {
1039*0Sstevel@tonic-gate 		atomic_add_64(&nl7c_uri_bytes, sz);
1040*0Sstevel@tonic-gate 	}
1041*0Sstevel@tonic-gate 	return;
1042*0Sstevel@tonic-gate 
1043*0Sstevel@tonic-gate fail:
1044*0Sstevel@tonic-gate 	if (alloc != NULL) {
1045*0Sstevel@tonic-gate 		kmem_free(alloc, sz);
1046*0Sstevel@tonic-gate 	}
1047*0Sstevel@tonic-gate 	so->so_nl7c_flags = 0;
1048*0Sstevel@tonic-gate 	nl7c_urifree(so);
1049*0Sstevel@tonic-gate }
1050*0Sstevel@tonic-gate 
1051*0Sstevel@tonic-gate /*
1052*0Sstevel@tonic-gate  * Called to read data from file "*fp" at offset "*off" of length "*len"
1053*0Sstevel@tonic-gate  * for a maximum of "*max_rem" bytes.
1054*0Sstevel@tonic-gate  *
1055*0Sstevel@tonic-gate  * On success a pointer to the kmem_alloc()ed file data is returned, "*off"
1056*0Sstevel@tonic-gate  * and "*len" are updated for the acutal number of bytes read and "*max_rem"
1057*0Sstevel@tonic-gate  * is updated with the number of bytes remaining to be read.
1058*0Sstevel@tonic-gate  *
1059*0Sstevel@tonic-gate  * Else, "NULL" is returned.
1060*0Sstevel@tonic-gate  */
1061*0Sstevel@tonic-gate 
1062*0Sstevel@tonic-gate static char *
1063*0Sstevel@tonic-gate nl7c_readfile(file_t *fp, u_offset_t *off, int *len, int *max_rem)
1064*0Sstevel@tonic-gate {
1065*0Sstevel@tonic-gate 	vnode_t	*vp = fp->f_vnode;
1066*0Sstevel@tonic-gate 	int	flg = 0;
1067*0Sstevel@tonic-gate 	size_t	size = MIN(*len, *max_rem);
1068*0Sstevel@tonic-gate 	char	*data;
1069*0Sstevel@tonic-gate 	int	error;
1070*0Sstevel@tonic-gate 	uio_t	uio;
1071*0Sstevel@tonic-gate 	iovec_t	iov;
1072*0Sstevel@tonic-gate 
1073*0Sstevel@tonic-gate 	(void) VOP_RWLOCK(vp, flg, NULL);
1074*0Sstevel@tonic-gate 
1075*0Sstevel@tonic-gate 	if (*off > MAXOFFSET_T) {
1076*0Sstevel@tonic-gate 		VOP_RWUNLOCK(vp, flg, NULL);
1077*0Sstevel@tonic-gate 		return (NULL);
1078*0Sstevel@tonic-gate 	}
1079*0Sstevel@tonic-gate 
1080*0Sstevel@tonic-gate 	if (*off + size > MAXOFFSET_T)
1081*0Sstevel@tonic-gate 		size = (ssize32_t)(MAXOFFSET_T - *off);
1082*0Sstevel@tonic-gate 
1083*0Sstevel@tonic-gate 	data = kmem_alloc(size, KM_SLEEP);
1084*0Sstevel@tonic-gate 
1085*0Sstevel@tonic-gate 	iov.iov_base = data;
1086*0Sstevel@tonic-gate 	iov.iov_len = size;
1087*0Sstevel@tonic-gate 	uio.uio_loffset = *off;
1088*0Sstevel@tonic-gate 	uio.uio_iov = &iov;
1089*0Sstevel@tonic-gate 	uio.uio_iovcnt = 1;
1090*0Sstevel@tonic-gate 	uio.uio_resid = size;
1091*0Sstevel@tonic-gate 	uio.uio_segflg = UIO_SYSSPACE;
1092*0Sstevel@tonic-gate 	uio.uio_llimit = MAXOFFSET_T;
1093*0Sstevel@tonic-gate 	uio.uio_fmode = fp->f_flag;
1094*0Sstevel@tonic-gate 
1095*0Sstevel@tonic-gate 	error = VOP_READ(vp, &uio, fp->f_flag, fp->f_cred, NULL);
1096*0Sstevel@tonic-gate 	VOP_RWUNLOCK(vp, flg, NULL);
1097*0Sstevel@tonic-gate 	if (error) {
1098*0Sstevel@tonic-gate 		kmem_free(data, size);
1099*0Sstevel@tonic-gate 		return (NULL);
1100*0Sstevel@tonic-gate 	}
1101*0Sstevel@tonic-gate 	*max_rem = *len - size;
1102*0Sstevel@tonic-gate 	*len = size;
1103*0Sstevel@tonic-gate 	*off += size;
1104*0Sstevel@tonic-gate 	return (data);
1105*0Sstevel@tonic-gate }
1106*0Sstevel@tonic-gate 
1107*0Sstevel@tonic-gate /*
1108*0Sstevel@tonic-gate  * Called to copy application response sendfilev.
1109*0Sstevel@tonic-gate  *
1110*0Sstevel@tonic-gate  * Note, the value of kmem_bytes is a segmap max sized value greater
1111*0Sstevel@tonic-gate  * than or equal to TCP's tcp_slow_start_initial, there are several
1112*0Sstevel@tonic-gate  * issues with this scheme least of which is assuming that TCP is the
1113*0Sstevel@tonic-gate  * only IP transport we care about or that we hardcode the TCP value
1114*0Sstevel@tonic-gate  * but until ...
1115*0Sstevel@tonic-gate  */
1116*0Sstevel@tonic-gate 
1117*0Sstevel@tonic-gate void
1118*0Sstevel@tonic-gate nl7c_sendfilev(struct sonode *so, u_offset_t off, sendfilevec_t *sfvp, int sfvc)
1119*0Sstevel@tonic-gate {
1120*0Sstevel@tonic-gate 	uri_desc_t	*uri = (uri_desc_t *)so->so_nl7c_uri;
1121*0Sstevel@tonic-gate 	file_t		*fp = NULL;
1122*0Sstevel@tonic-gate 	vnode_t		*vp = NULL;
1123*0Sstevel@tonic-gate 	char		*data = NULL;
1124*0Sstevel@tonic-gate 	int		len;
1125*0Sstevel@tonic-gate 	int		count;
1126*0Sstevel@tonic-gate 	int		total_count = 0;
1127*0Sstevel@tonic-gate 	char		*bp;
1128*0Sstevel@tonic-gate 	uri_rd_t	*rdp;
1129*0Sstevel@tonic-gate 	int		max_rem;
1130*0Sstevel@tonic-gate 	int		error = 0;
1131*0Sstevel@tonic-gate 
1132*0Sstevel@tonic-gate 	nl7c_uri_sendfilev++;
1133*0Sstevel@tonic-gate 
1134*0Sstevel@tonic-gate 	if (uri == NULL) {
1135*0Sstevel@tonic-gate 		/* Socket & NL7C out of sync, disable NL7C */
1136*0Sstevel@tonic-gate 		so->so_nl7c_flags = 0;
1137*0Sstevel@tonic-gate 		nl7c_uri_NULL2++;
1138*0Sstevel@tonic-gate 		return;
1139*0Sstevel@tonic-gate 	}
1140*0Sstevel@tonic-gate 
1141*0Sstevel@tonic-gate 	if (so->so_nl7c_flags & NL7C_WAITWRITE)
1142*0Sstevel@tonic-gate 		so->so_nl7c_flags &= ~NL7C_WAITWRITE;
1143*0Sstevel@tonic-gate 
1144*0Sstevel@tonic-gate 	while (sfvc-- > 0) {
1145*0Sstevel@tonic-gate 		/*
1146*0Sstevel@tonic-gate 		 * off - the current sfv read file offset or user address.
1147*0Sstevel@tonic-gate 		 *
1148*0Sstevel@tonic-gate 		 * len - the current sfv kmem_alloc()ed buffer length, note
1149*0Sstevel@tonic-gate 		 *	 may be less than the actual sfv size.
1150*0Sstevel@tonic-gate 		 *
1151*0Sstevel@tonic-gate 		 * count - the actual current sfv size in bytes.
1152*0Sstevel@tonic-gate 		 *
1153*0Sstevel@tonic-gate 		 * data - the kmem_alloc()ed buffer of size "len".
1154*0Sstevel@tonic-gate 		 *
1155*0Sstevel@tonic-gate 		 * fp - the current sfv file_t pointer.
1156*0Sstevel@tonic-gate 		 *
1157*0Sstevel@tonic-gate 		 * vp - the current "*vp" vnode_t pointer.
1158*0Sstevel@tonic-gate 		 *
1159*0Sstevel@tonic-gate 		 * Note, for "data" and "fp" and "vp" a NULL value is used
1160*0Sstevel@tonic-gate 		 * when not allocated such that the common failure path "fail"
1161*0Sstevel@tonic-gate 		 * is used.
1162*0Sstevel@tonic-gate 		 */
1163*0Sstevel@tonic-gate 		off = sfvp->sfv_off;
1164*0Sstevel@tonic-gate 		len = sfvp->sfv_len;
1165*0Sstevel@tonic-gate 		count = len;
1166*0Sstevel@tonic-gate 		if (uri->hash == URI_TEMP) {
1167*0Sstevel@tonic-gate 			if (uri->resplen == -1)
1168*0Sstevel@tonic-gate 				len = MIN(len, URI_TEMP_PARSE_SZ);
1169*0Sstevel@tonic-gate 			else
1170*0Sstevel@tonic-gate 				len = 0;
1171*0Sstevel@tonic-gate 		}
1172*0Sstevel@tonic-gate 		if (len == 0) {
1173*0Sstevel@tonic-gate 			/*
1174*0Sstevel@tonic-gate 			 * TEMP uri with no data to sink, just count bytes.
1175*0Sstevel@tonic-gate 			 */
1176*0Sstevel@tonic-gate 			uri->count += count;
1177*0Sstevel@tonic-gate 		} else if (sfvp->sfv_fd == SFV_FD_SELF) {
1178*0Sstevel@tonic-gate 			/*
1179*0Sstevel@tonic-gate 			 * Process user memory, copyin().
1180*0Sstevel@tonic-gate 			 */
1181*0Sstevel@tonic-gate 			data = kmem_alloc(len, KM_SLEEP);
1182*0Sstevel@tonic-gate 
1183*0Sstevel@tonic-gate 			error = xcopyin((caddr_t)(uintptr_t)off, data, len);
1184*0Sstevel@tonic-gate 			if (error)
1185*0Sstevel@tonic-gate 				goto fail;
1186*0Sstevel@tonic-gate 
1187*0Sstevel@tonic-gate 			bp = data;
1188*0Sstevel@tonic-gate 			if (uri->resplen == -1 &&
1189*0Sstevel@tonic-gate 			    ! nl7c_http_response(&bp, &bp[len], uri, so) &&
1190*0Sstevel@tonic-gate 			    (bp == NULL || uri->hash != URI_TEMP ||
1191*0Sstevel@tonic-gate 			    (uri->hash == URI_TEMP && uri->resplen == -1))) {
1192*0Sstevel@tonic-gate 				/*
1193*0Sstevel@tonic-gate 				 * Parse not complete and parse failed or
1194*0Sstevel@tonic-gate 				 * not TEMP partial parse or TEMP partial
1195*0Sstevel@tonic-gate 				 * parse and no resplen.
1196*0Sstevel@tonic-gate 				 */
1197*0Sstevel@tonic-gate 				goto fail;
1198*0Sstevel@tonic-gate 			}
1199*0Sstevel@tonic-gate 
1200*0Sstevel@tonic-gate 			if (uri->hash == URI_TEMP) {
1201*0Sstevel@tonic-gate 				uri->count += len;
1202*0Sstevel@tonic-gate 				kmem_free(data, len);
1203*0Sstevel@tonic-gate 				data = NULL;
1204*0Sstevel@tonic-gate 			} else {
1205*0Sstevel@tonic-gate 				URI_RD_ADD(uri, rdp, len, -1);
1206*0Sstevel@tonic-gate 				if (rdp == NULL)
1207*0Sstevel@tonic-gate 					goto fail;
1208*0Sstevel@tonic-gate 				rdp->data.kmem = data;
1209*0Sstevel@tonic-gate 				data = NULL;
1210*0Sstevel@tonic-gate 				total_count += len;
1211*0Sstevel@tonic-gate 			}
1212*0Sstevel@tonic-gate 		} else {
1213*0Sstevel@tonic-gate 			/*
1214*0Sstevel@tonic-gate 			 * File descriptor, prefetch some bytes,
1215*0Sstevel@tonic-gate 			 * save vnode_t if any bytes left.
1216*0Sstevel@tonic-gate 			 */
1217*0Sstevel@tonic-gate 			if ((fp = getf(sfvp->sfv_fd)) == NULL)
1218*0Sstevel@tonic-gate 				goto fail;
1219*0Sstevel@tonic-gate 
1220*0Sstevel@tonic-gate 			if ((fp->f_flag & FREAD) == 0)
1221*0Sstevel@tonic-gate 				goto fail;
1222*0Sstevel@tonic-gate 
1223*0Sstevel@tonic-gate 			vp = fp->f_vnode;
1224*0Sstevel@tonic-gate 			if (vp->v_type != VREG)
1225*0Sstevel@tonic-gate 				goto fail;
1226*0Sstevel@tonic-gate 			VN_HOLD(vp);
1227*0Sstevel@tonic-gate 
1228*0Sstevel@tonic-gate 			/* Read max_rem bytes from file for prefetch */
1229*0Sstevel@tonic-gate 			if (nl7c_use_kmem) {
1230*0Sstevel@tonic-gate 				max_rem = len;
1231*0Sstevel@tonic-gate 			} else {
1232*0Sstevel@tonic-gate 				max_rem = MAXBSIZE * nl7c_file_prefetch;
1233*0Sstevel@tonic-gate 			}
1234*0Sstevel@tonic-gate 			data = nl7c_readfile(fp, &off, &len, &max_rem);
1235*0Sstevel@tonic-gate 			if (data == NULL)
1236*0Sstevel@tonic-gate 				goto fail;
1237*0Sstevel@tonic-gate 
1238*0Sstevel@tonic-gate 			releasef(sfvp->sfv_fd);
1239*0Sstevel@tonic-gate 			fp = NULL;
1240*0Sstevel@tonic-gate 
1241*0Sstevel@tonic-gate 			bp = data;
1242*0Sstevel@tonic-gate 			if (uri->resplen == -1 &&
1243*0Sstevel@tonic-gate 			    ! nl7c_http_response(&bp, &bp[len], uri, so) &&
1244*0Sstevel@tonic-gate 			    (bp == NULL || uri->hash != URI_TEMP ||
1245*0Sstevel@tonic-gate 			    uri->resplen == -1)) {
1246*0Sstevel@tonic-gate 				/*
1247*0Sstevel@tonic-gate 				 * Parse not complete and parse failed or
1248*0Sstevel@tonic-gate 				 * not TEMP partial parse or TEMP partial
1249*0Sstevel@tonic-gate 				 * parse and no resplen.
1250*0Sstevel@tonic-gate 				 */
1251*0Sstevel@tonic-gate 				goto fail;
1252*0Sstevel@tonic-gate 			}
1253*0Sstevel@tonic-gate 
1254*0Sstevel@tonic-gate 			if (uri->hash == URI_TEMP) {
1255*0Sstevel@tonic-gate 				/*
1256*0Sstevel@tonic-gate 				 * Temp uri, account for all sfv bytes and
1257*0Sstevel@tonic-gate 				 * free up any resources allocated above.
1258*0Sstevel@tonic-gate 				 */
1259*0Sstevel@tonic-gate 				uri->count += count;
1260*0Sstevel@tonic-gate 				kmem_free(data, len);
1261*0Sstevel@tonic-gate 				data = NULL;
1262*0Sstevel@tonic-gate 				VN_RELE(vp);
1263*0Sstevel@tonic-gate 				vp = NULL;
1264*0Sstevel@tonic-gate 			} else {
1265*0Sstevel@tonic-gate 				/*
1266*0Sstevel@tonic-gate 				 * Setup an uri_rd_t for the prefetch and
1267*0Sstevel@tonic-gate 				 * if any sfv data remains setup an another
1268*0Sstevel@tonic-gate 				 * uri_rd_t to map it, last free up any
1269*0Sstevel@tonic-gate 				 * resources allocated above.
1270*0Sstevel@tonic-gate 				 */
1271*0Sstevel@tonic-gate 				URI_RD_ADD(uri, rdp, len, -1);
1272*0Sstevel@tonic-gate 				if (rdp == NULL)
1273*0Sstevel@tonic-gate 					goto fail;
1274*0Sstevel@tonic-gate 				rdp->data.kmem = data;
1275*0Sstevel@tonic-gate 				data = NULL;
1276*0Sstevel@tonic-gate 				if (max_rem > 0) {
1277*0Sstevel@tonic-gate 					/* More file data so add it */
1278*0Sstevel@tonic-gate 					URI_RD_ADD(uri, rdp, max_rem, off);
1279*0Sstevel@tonic-gate 					if (rdp == NULL)
1280*0Sstevel@tonic-gate 						goto fail;
1281*0Sstevel@tonic-gate 					rdp->data.vnode = vp;
1282*0Sstevel@tonic-gate 				} else {
1283*0Sstevel@tonic-gate 					/* All file data fit in the prefetch */
1284*0Sstevel@tonic-gate 					VN_RELE(vp);
1285*0Sstevel@tonic-gate 				}
1286*0Sstevel@tonic-gate 				vp = NULL;
1287*0Sstevel@tonic-gate 				/* Only account for the kmem_alloc()ed bytes */
1288*0Sstevel@tonic-gate 				total_count += len;
1289*0Sstevel@tonic-gate 			}
1290*0Sstevel@tonic-gate 		}
1291*0Sstevel@tonic-gate 		sfvp++;
1292*0Sstevel@tonic-gate 	}
1293*0Sstevel@tonic-gate 	if (total_count > 0) {
1294*0Sstevel@tonic-gate 		atomic_add_64(&nl7c_uri_bytes, total_count);
1295*0Sstevel@tonic-gate 	}
1296*0Sstevel@tonic-gate 	if (uri->resplen != -1 && uri->count >= uri->resplen) {
1297*0Sstevel@tonic-gate 		/* Got the response data, close the uri */
1298*0Sstevel@tonic-gate 		nl7c_close(so);
1299*0Sstevel@tonic-gate 	}
1300*0Sstevel@tonic-gate 	return;
1301*0Sstevel@tonic-gate 
1302*0Sstevel@tonic-gate fail:
1303*0Sstevel@tonic-gate 	if (data != NULL)
1304*0Sstevel@tonic-gate 		kmem_free(data, len);
1305*0Sstevel@tonic-gate 
1306*0Sstevel@tonic-gate 	if (vp != NULL)
1307*0Sstevel@tonic-gate 		VN_RELE(vp);
1308*0Sstevel@tonic-gate 
1309*0Sstevel@tonic-gate 	if (fp != NULL)
1310*0Sstevel@tonic-gate 		releasef(sfvp->sfv_fd);
1311*0Sstevel@tonic-gate 
1312*0Sstevel@tonic-gate 	if (total_count > 0) {
1313*0Sstevel@tonic-gate 		atomic_add_64(&nl7c_uri_bytes, total_count);
1314*0Sstevel@tonic-gate 	}
1315*0Sstevel@tonic-gate 	so->so_nl7c_flags = 0;
1316*0Sstevel@tonic-gate 	nl7c_urifree(so);
1317*0Sstevel@tonic-gate }
1318*0Sstevel@tonic-gate 
1319*0Sstevel@tonic-gate /*
1320*0Sstevel@tonic-gate  * Called for a socket which is closing or when an application has
1321*0Sstevel@tonic-gate  * completed sending all the response data (i.e. for a persistent
1322*0Sstevel@tonic-gate  * connection called once for each completed application response).
1323*0Sstevel@tonic-gate  */
1324*0Sstevel@tonic-gate 
1325*0Sstevel@tonic-gate void
1326*0Sstevel@tonic-gate nl7c_close(struct sonode *so)
1327*0Sstevel@tonic-gate {
1328*0Sstevel@tonic-gate 	uri_desc_t *uri = (uri_desc_t *)so->so_nl7c_uri;
1329*0Sstevel@tonic-gate 
1330*0Sstevel@tonic-gate 	if (uri == NULL) {
1331*0Sstevel@tonic-gate 		/*
1332*0Sstevel@tonic-gate 		 * No URI being processed so might be a listen()er
1333*0Sstevel@tonic-gate 		 * if so do any cleanup, else nothing more to do.
1334*0Sstevel@tonic-gate 		 */
1335*0Sstevel@tonic-gate 		if (so->so_state & SS_ACCEPTCONN) {
1336*0Sstevel@tonic-gate 			(void) nl7c_close_addr(so);
1337*0Sstevel@tonic-gate 		}
1338*0Sstevel@tonic-gate 		return;
1339*0Sstevel@tonic-gate 	}
1340*0Sstevel@tonic-gate 	so->so_nl7c_uri = NULL;
1341*0Sstevel@tonic-gate 	if (uri->hash != URI_TEMP) {
1342*0Sstevel@tonic-gate 		mutex_enter(&uri->proclock);
1343*0Sstevel@tonic-gate 		uri->proc = NULL;
1344*0Sstevel@tonic-gate 		if (CV_HAS_WAITERS(&uri->waiting)) {
1345*0Sstevel@tonic-gate 			cv_broadcast(&uri->waiting);
1346*0Sstevel@tonic-gate 		}
1347*0Sstevel@tonic-gate 		mutex_exit(&uri->proclock);
1348*0Sstevel@tonic-gate 		nl7c_uri_close++;
1349*0Sstevel@tonic-gate 	} else {
1350*0Sstevel@tonic-gate 		/* No proclock as uri exclusively owned by so */
1351*0Sstevel@tonic-gate 		uri->proc = NULL;
1352*0Sstevel@tonic-gate 		nl7c_uri_temp_close++;
1353*0Sstevel@tonic-gate 	}
1354*0Sstevel@tonic-gate 	REF_RELE(uri);
1355*0Sstevel@tonic-gate 	if (nl7c_uri_max > 0 && nl7c_uri_bytes > nl7c_uri_max) {
1356*0Sstevel@tonic-gate 		nl7c_uri_reclaim();
1357*0Sstevel@tonic-gate 	}
1358*0Sstevel@tonic-gate }
1359*0Sstevel@tonic-gate 
1360*0Sstevel@tonic-gate /*
1361*0Sstevel@tonic-gate  * The uri_segmap_t ref_t inactive function called on the last REF_RELE(),
1362*0Sstevel@tonic-gate  * release the segmap mapping. Note, the uri_segmap_t will be freed by
1363*0Sstevel@tonic-gate  * REF_RELE() on return.
1364*0Sstevel@tonic-gate  */
1365*0Sstevel@tonic-gate 
1366*0Sstevel@tonic-gate void
1367*0Sstevel@tonic-gate uri_segmap_inactive(uri_segmap_t *smp)
1368*0Sstevel@tonic-gate {
1369*0Sstevel@tonic-gate 	if (!segmap_kpm) {
1370*0Sstevel@tonic-gate 		(void) segmap_fault(kas.a_hat, segkmap, smp->base,
1371*0Sstevel@tonic-gate 		    smp->len, F_SOFTUNLOCK, S_OTHER);
1372*0Sstevel@tonic-gate 	}
1373*0Sstevel@tonic-gate 	(void) segmap_release(segkmap, smp->base, SM_DONTNEED);
1374*0Sstevel@tonic-gate 	VN_RELE(smp->vp);
1375*0Sstevel@tonic-gate }
1376*0Sstevel@tonic-gate 
1377*0Sstevel@tonic-gate /*
1378*0Sstevel@tonic-gate  * The call-back for desballoc()ed mblk_t's, if a segmap mapped mblk_t
1379*0Sstevel@tonic-gate  * release the reference, one per deballoc() of a segmap page, release
1380*0Sstevel@tonic-gate  * the reference of the URI containing the uri_rd_t, last free kmem
1381*0Sstevel@tonic-gate  * free the uri_desb_t.
1382*0Sstevel@tonic-gate  */
1383*0Sstevel@tonic-gate 
1384*0Sstevel@tonic-gate static void
1385*0Sstevel@tonic-gate uri_desb_free(uri_desb_t *desb)
1386*0Sstevel@tonic-gate {
1387*0Sstevel@tonic-gate 	if (desb->segmap != NULL) {
1388*0Sstevel@tonic-gate 		REF_RELE(desb->segmap);
1389*0Sstevel@tonic-gate 	}
1390*0Sstevel@tonic-gate 	REF_RELE(desb->uri);
1391*0Sstevel@tonic-gate 	kmem_cache_free(uri_desb_kmc, desb);
1392*0Sstevel@tonic-gate }
1393*0Sstevel@tonic-gate 
1394*0Sstevel@tonic-gate /*
1395*0Sstevel@tonic-gate  * Segmap map up to a page of a uri_rd_t file descriptor.
1396*0Sstevel@tonic-gate  */
1397*0Sstevel@tonic-gate 
1398*0Sstevel@tonic-gate uri_segmap_t *
1399*0Sstevel@tonic-gate uri_segmap_map(uri_rd_t *rdp, int bytes)
1400*0Sstevel@tonic-gate {
1401*0Sstevel@tonic-gate 	uri_segmap_t	*segmap = kmem_cache_alloc(uri_segmap_kmc, KM_SLEEP);
1402*0Sstevel@tonic-gate 	int		len = MIN(rdp->sz, MAXBSIZE);
1403*0Sstevel@tonic-gate 
1404*0Sstevel@tonic-gate 	if (len > bytes)
1405*0Sstevel@tonic-gate 		len = bytes;
1406*0Sstevel@tonic-gate 
1407*0Sstevel@tonic-gate 	REF_INIT(segmap, 1, uri_segmap_inactive, uri_segmap_kmc);
1408*0Sstevel@tonic-gate 	segmap->len = len;
1409*0Sstevel@tonic-gate 	VN_HOLD(rdp->data.vnode);
1410*0Sstevel@tonic-gate 	segmap->vp = rdp->data.vnode;
1411*0Sstevel@tonic-gate 
1412*0Sstevel@tonic-gate 	segmap->base = segmap_getmapflt(segkmap, segmap->vp, rdp->off, len,
1413*0Sstevel@tonic-gate 	    segmap_kpm ? SM_FAULT : 0, S_READ);
1414*0Sstevel@tonic-gate 
1415*0Sstevel@tonic-gate 	if (segmap_fault(kas.a_hat, segkmap, segmap->base, len,
1416*0Sstevel@tonic-gate 	    F_SOFTLOCK, S_READ) != 0) {
1417*0Sstevel@tonic-gate 		REF_RELE(segmap);
1418*0Sstevel@tonic-gate 		return (NULL);
1419*0Sstevel@tonic-gate 	}
1420*0Sstevel@tonic-gate 	return (segmap);
1421*0Sstevel@tonic-gate }
1422*0Sstevel@tonic-gate 
1423*0Sstevel@tonic-gate /*
1424*0Sstevel@tonic-gate  * Chop up the kernel virtual memory area *data of size *sz bytes for
1425*0Sstevel@tonic-gate  * a maximum of *bytes bytes into an besballoc()ed mblk_t chain using
1426*0Sstevel@tonic-gate  * the given template uri_desb_t *temp of max_mblk bytes per.
1427*0Sstevel@tonic-gate  *
1428*0Sstevel@tonic-gate  * The values of *data, *sz, and *bytes are updated on return, the
1429*0Sstevel@tonic-gate  * mblk_t chain is returned.
1430*0Sstevel@tonic-gate  */
1431*0Sstevel@tonic-gate 
1432*0Sstevel@tonic-gate static mblk_t *
1433*0Sstevel@tonic-gate uri_desb_chop(
1434*0Sstevel@tonic-gate 	char 		**data,
1435*0Sstevel@tonic-gate 	size_t		*sz,
1436*0Sstevel@tonic-gate 	int 		*bytes,
1437*0Sstevel@tonic-gate 	uri_desb_t 	*temp,
1438*0Sstevel@tonic-gate 	int		max_mblk,
1439*0Sstevel@tonic-gate 	char		*eoh,
1440*0Sstevel@tonic-gate 	mblk_t		*persist
1441*0Sstevel@tonic-gate )
1442*0Sstevel@tonic-gate {
1443*0Sstevel@tonic-gate 	char		*ldata = *data;
1444*0Sstevel@tonic-gate 	size_t		lsz = *sz;
1445*0Sstevel@tonic-gate 	int		lbytes = bytes ? *bytes : lsz;
1446*0Sstevel@tonic-gate 	uri_desb_t	*desb;
1447*0Sstevel@tonic-gate 	mblk_t		*mp = NULL;
1448*0Sstevel@tonic-gate 	mblk_t		*nmp, *tmp, *pmp = NULL;
1449*0Sstevel@tonic-gate 	int		msz;
1450*0Sstevel@tonic-gate 
1451*0Sstevel@tonic-gate 	if (lbytes == 0 && lsz == 0)
1452*0Sstevel@tonic-gate 		return (NULL);
1453*0Sstevel@tonic-gate 
1454*0Sstevel@tonic-gate 	while (lbytes > 0 && lsz > 0) {
1455*0Sstevel@tonic-gate 		msz = MIN(lbytes, max_mblk);
1456*0Sstevel@tonic-gate 		msz = MIN(msz, lsz);
1457*0Sstevel@tonic-gate 		if (persist && eoh >= ldata && eoh < &ldata[msz]) {
1458*0Sstevel@tonic-gate 			msz = (eoh - ldata);
1459*0Sstevel@tonic-gate 			pmp = persist;
1460*0Sstevel@tonic-gate 			persist = NULL;
1461*0Sstevel@tonic-gate 		}
1462*0Sstevel@tonic-gate 		desb = kmem_cache_alloc(uri_desb_kmc, KM_SLEEP);
1463*0Sstevel@tonic-gate 		REF_HOLD(temp->uri);
1464*0Sstevel@tonic-gate 		if (temp->segmap) {
1465*0Sstevel@tonic-gate 			REF_HOLD(temp->segmap);
1466*0Sstevel@tonic-gate 		}
1467*0Sstevel@tonic-gate 		bcopy(temp, desb, sizeof (*desb));
1468*0Sstevel@tonic-gate 		desb->frtn.free_arg = (caddr_t)desb;
1469*0Sstevel@tonic-gate 		nmp = desballoc((uchar_t *)ldata, msz, BPRI_HI, &desb->frtn);
1470*0Sstevel@tonic-gate 		if (nmp == NULL) {
1471*0Sstevel@tonic-gate 			if (temp->segmap) {
1472*0Sstevel@tonic-gate 				REF_RELE(temp->segmap);
1473*0Sstevel@tonic-gate 			}
1474*0Sstevel@tonic-gate 			REF_RELE(temp->uri);
1475*0Sstevel@tonic-gate 			if (mp != NULL) {
1476*0Sstevel@tonic-gate 				freemsg(mp);
1477*0Sstevel@tonic-gate 			}
1478*0Sstevel@tonic-gate 			return (NULL);
1479*0Sstevel@tonic-gate 		}
1480*0Sstevel@tonic-gate 		nmp->b_wptr += msz;
1481*0Sstevel@tonic-gate 		if (mp != NULL) {
1482*0Sstevel@tonic-gate 			/*LINTED*/
1483*0Sstevel@tonic-gate 			ASSERT(tmp->b_cont == NULL);
1484*0Sstevel@tonic-gate 			/*LINTED*/
1485*0Sstevel@tonic-gate 			tmp->b_cont = nmp;
1486*0Sstevel@tonic-gate 		} else {
1487*0Sstevel@tonic-gate 			mp = nmp;
1488*0Sstevel@tonic-gate 		}
1489*0Sstevel@tonic-gate 		tmp = nmp;
1490*0Sstevel@tonic-gate 		ldata += msz;
1491*0Sstevel@tonic-gate 		lsz -= msz;
1492*0Sstevel@tonic-gate 		lbytes -= msz;
1493*0Sstevel@tonic-gate 		if (pmp) {
1494*0Sstevel@tonic-gate 			tmp->b_cont = pmp;
1495*0Sstevel@tonic-gate 			tmp = pmp;
1496*0Sstevel@tonic-gate 			pmp = NULL;
1497*0Sstevel@tonic-gate 		}
1498*0Sstevel@tonic-gate 	}
1499*0Sstevel@tonic-gate 	*data = ldata;
1500*0Sstevel@tonic-gate 	*sz = lsz;
1501*0Sstevel@tonic-gate 	if (bytes)
1502*0Sstevel@tonic-gate 		*bytes = lbytes;
1503*0Sstevel@tonic-gate 	mp->b_next = tmp;
1504*0Sstevel@tonic-gate 	return (mp);
1505*0Sstevel@tonic-gate }
1506*0Sstevel@tonic-gate 
1507*0Sstevel@tonic-gate /*
1508*0Sstevel@tonic-gate  * Experimential noqwait (i.e. no canput()/qwait() checks), just send
1509*0Sstevel@tonic-gate  * the entire mblk_t chain down without flow-control checks.
1510*0Sstevel@tonic-gate  */
1511*0Sstevel@tonic-gate 
1512*0Sstevel@tonic-gate static int
1513*0Sstevel@tonic-gate kstrwritempnoqwait(struct vnode *vp, mblk_t *mp)
1514*0Sstevel@tonic-gate {
1515*0Sstevel@tonic-gate 	struct stdata *stp;
1516*0Sstevel@tonic-gate 	int error = 0;
1517*0Sstevel@tonic-gate 
1518*0Sstevel@tonic-gate 	ASSERT(vp->v_stream);
1519*0Sstevel@tonic-gate 	stp = vp->v_stream;
1520*0Sstevel@tonic-gate 
1521*0Sstevel@tonic-gate 	/* Fast check of flags before acquiring the lock */
1522*0Sstevel@tonic-gate 	if (stp->sd_flag & (STWRERR|STRHUP|STPLEX)) {
1523*0Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
1524*0Sstevel@tonic-gate 		error = strgeterr(stp, STWRERR|STRHUP|STPLEX, 0);
1525*0Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
1526*0Sstevel@tonic-gate 		if (error != 0) {
1527*0Sstevel@tonic-gate 			if (!(stp->sd_flag & STPLEX) &&
1528*0Sstevel@tonic-gate 			    (stp->sd_wput_opt & SW_SIGPIPE)) {
1529*0Sstevel@tonic-gate 				tsignal(curthread, SIGPIPE);
1530*0Sstevel@tonic-gate 				error = EPIPE;
1531*0Sstevel@tonic-gate 			}
1532*0Sstevel@tonic-gate 			return (error);
1533*0Sstevel@tonic-gate 		}
1534*0Sstevel@tonic-gate 	}
1535*0Sstevel@tonic-gate 	putnext(stp->sd_wrq, mp);
1536*0Sstevel@tonic-gate 	return (0);
1537*0Sstevel@tonic-gate }
1538*0Sstevel@tonic-gate 
1539*0Sstevel@tonic-gate /*
1540*0Sstevel@tonic-gate  * Send the URI response uri_desc_t *uri out the socket_t *so.
1541*0Sstevel@tonic-gate  */
1542*0Sstevel@tonic-gate 
1543*0Sstevel@tonic-gate static void
1544*0Sstevel@tonic-gate uri_response(struct sonode *so, uri_desc_t *uri, int max_mblk)
1545*0Sstevel@tonic-gate {
1546*0Sstevel@tonic-gate 	uri_rd_t	*rdp = &uri->response;
1547*0Sstevel@tonic-gate 	vnode_t		*vp = SOTOV(so);
1548*0Sstevel@tonic-gate 	int		wsz;
1549*0Sstevel@tonic-gate 	mblk_t		*mp, *wmp, *persist;
1550*0Sstevel@tonic-gate 	int		write_bytes;
1551*0Sstevel@tonic-gate 	uri_rd_t	rd = {0};
1552*0Sstevel@tonic-gate 	uri_desb_t	desb;
1553*0Sstevel@tonic-gate 	uri_segmap_t	*segmap = NULL;
1554*0Sstevel@tonic-gate 	char		*segmap_data;
1555*0Sstevel@tonic-gate 	size_t		segmap_sz;
1556*0Sstevel@tonic-gate 	boolean_t	first = B_TRUE;
1557*0Sstevel@tonic-gate 
1558*0Sstevel@tonic-gate 	/* For first kstrwrite() enough data to get things going */
1559*0Sstevel@tonic-gate 	write_bytes = P2ROUNDUP((max_mblk * 4), MAXBSIZE * nl7c_file_prefetch);
1560*0Sstevel@tonic-gate 
1561*0Sstevel@tonic-gate 	/* Initialize template uri_desb_t */
1562*0Sstevel@tonic-gate 	desb.frtn.free_func = uri_desb_free;
1563*0Sstevel@tonic-gate 	desb.frtn.free_arg = NULL;
1564*0Sstevel@tonic-gate 	desb.uri = uri;
1565*0Sstevel@tonic-gate 
1566*0Sstevel@tonic-gate 	do {
1567*0Sstevel@tonic-gate 		wmp = NULL;
1568*0Sstevel@tonic-gate 		wsz = write_bytes;
1569*0Sstevel@tonic-gate 		do {
1570*0Sstevel@tonic-gate 			if (rd.sz == 0) {
1571*0Sstevel@tonic-gate 				bcopy(rdp, &rd, sizeof (rd));
1572*0Sstevel@tonic-gate 				rdp = rdp->next;
1573*0Sstevel@tonic-gate 			}
1574*0Sstevel@tonic-gate 			if (rd.off == -1) {
1575*0Sstevel@tonic-gate 				if (uri->eoh >= rd.data.kmem &&
1576*0Sstevel@tonic-gate 				    uri->eoh < &rd.data.kmem[rd.sz]) {
1577*0Sstevel@tonic-gate 					persist = nl7c_http_persist(so);
1578*0Sstevel@tonic-gate 				} else {
1579*0Sstevel@tonic-gate 					persist = NULL;
1580*0Sstevel@tonic-gate 				}
1581*0Sstevel@tonic-gate 				desb.segmap = NULL;
1582*0Sstevel@tonic-gate 				mp = uri_desb_chop(&rd.data.kmem, &rd.sz,
1583*0Sstevel@tonic-gate 				    &wsz, &desb, max_mblk, uri->eoh, persist);
1584*0Sstevel@tonic-gate 				if (mp == NULL)
1585*0Sstevel@tonic-gate 					goto invalidate;
1586*0Sstevel@tonic-gate 			} else {
1587*0Sstevel@tonic-gate 				if (segmap == NULL) {
1588*0Sstevel@tonic-gate 					segmap = uri_segmap_map(&rd,
1589*0Sstevel@tonic-gate 					    write_bytes);
1590*0Sstevel@tonic-gate 					if (segmap == NULL)
1591*0Sstevel@tonic-gate 						goto invalidate;
1592*0Sstevel@tonic-gate 					desb.segmap = segmap;
1593*0Sstevel@tonic-gate 					segmap_data = segmap->base;
1594*0Sstevel@tonic-gate 					segmap_sz = segmap->len;
1595*0Sstevel@tonic-gate 				}
1596*0Sstevel@tonic-gate 				mp = uri_desb_chop(&segmap_data, &segmap_sz,
1597*0Sstevel@tonic-gate 				    &wsz, &desb, max_mblk, NULL, NULL);
1598*0Sstevel@tonic-gate 				if (mp == NULL)
1599*0Sstevel@tonic-gate 					goto invalidate;
1600*0Sstevel@tonic-gate 				if (segmap_sz == 0) {
1601*0Sstevel@tonic-gate 					rd.sz -= segmap->len;
1602*0Sstevel@tonic-gate 					rd.off += segmap->len;
1603*0Sstevel@tonic-gate 					REF_RELE(segmap);
1604*0Sstevel@tonic-gate 					segmap = NULL;
1605*0Sstevel@tonic-gate 				}
1606*0Sstevel@tonic-gate 			}
1607*0Sstevel@tonic-gate 			if (wmp == NULL) {
1608*0Sstevel@tonic-gate 				wmp = mp;
1609*0Sstevel@tonic-gate 			} else {
1610*0Sstevel@tonic-gate 				wmp->b_next->b_cont = mp;
1611*0Sstevel@tonic-gate 				wmp->b_next = mp->b_next;
1612*0Sstevel@tonic-gate 				mp->b_next = NULL;
1613*0Sstevel@tonic-gate 			}
1614*0Sstevel@tonic-gate 		} while (wsz > 0 && (rd.sz > 0 || rdp != NULL));
1615*0Sstevel@tonic-gate 
1616*0Sstevel@tonic-gate 		wmp->b_next = NULL;
1617*0Sstevel@tonic-gate 		if (first) {
1618*0Sstevel@tonic-gate 			/* First kstrwrite(), use noqwait */
1619*0Sstevel@tonic-gate 			if (kstrwritempnoqwait(vp, wmp) != 0)
1620*0Sstevel@tonic-gate 				goto invalidate;
1621*0Sstevel@tonic-gate 			/*
1622*0Sstevel@tonic-gate 			 * For the rest of the kstrwrite()s use SO_SNDBUF
1623*0Sstevel@tonic-gate 			 * worth of data at a time, note these kstrwrite()s
1624*0Sstevel@tonic-gate 			 * may (will) block one or more times.
1625*0Sstevel@tonic-gate 			 */
1626*0Sstevel@tonic-gate 			first = B_FALSE;
1627*0Sstevel@tonic-gate 			if ((write_bytes = so->so_sndbuf) == 0)
1628*0Sstevel@tonic-gate 				write_bytes = vp->v_stream->sd_qn_maxpsz;
1629*0Sstevel@tonic-gate 			ASSERT(write_bytes > 0);
1630*0Sstevel@tonic-gate 			write_bytes = P2ROUNDUP(write_bytes, MAXBSIZE);
1631*0Sstevel@tonic-gate 		} else {
1632*0Sstevel@tonic-gate 			if (kstrwritemp(vp, wmp, 0) != 0)
1633*0Sstevel@tonic-gate 				goto invalidate;
1634*0Sstevel@tonic-gate 		}
1635*0Sstevel@tonic-gate 	} while (rd.sz > 0 || rdp != NULL);
1636*0Sstevel@tonic-gate 
1637*0Sstevel@tonic-gate 	return;
1638*0Sstevel@tonic-gate 
1639*0Sstevel@tonic-gate invalidate:
1640*0Sstevel@tonic-gate 	if (segmap) {
1641*0Sstevel@tonic-gate 		REF_RELE(segmap);
1642*0Sstevel@tonic-gate 	}
1643*0Sstevel@tonic-gate 	if (wmp)
1644*0Sstevel@tonic-gate 		freemsg(wmp);
1645*0Sstevel@tonic-gate 	uri_delete(uri);
1646*0Sstevel@tonic-gate }
1647*0Sstevel@tonic-gate 
1648*0Sstevel@tonic-gate /*
1649*0Sstevel@tonic-gate  * The pchars[] array is indexed by a char to determine if it's a
1650*0Sstevel@tonic-gate  * valid URI path component chararcter where:
1651*0Sstevel@tonic-gate  *
1652*0Sstevel@tonic-gate  *    pchar       = unreserved | escaped |
1653*0Sstevel@tonic-gate  *                  ":" | "@" | "&" | "=" | "+" | "$" | ","
1654*0Sstevel@tonic-gate  *
1655*0Sstevel@tonic-gate  *    unreserved  = alphanum | mark
1656*0Sstevel@tonic-gate  *
1657*0Sstevel@tonic-gate  *    alphanum    = alpha | digit
1658*0Sstevel@tonic-gate  *
1659*0Sstevel@tonic-gate  *    alpha       = lowalpha | upalpha
1660*0Sstevel@tonic-gate  *
1661*0Sstevel@tonic-gate  *    lowalpha    = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" |
1662*0Sstevel@tonic-gate  *                  "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" |
1663*0Sstevel@tonic-gate  *                  "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" |
1664*0Sstevel@tonic-gate  *                  "y" | "z"
1665*0Sstevel@tonic-gate  *
1666*0Sstevel@tonic-gate  *    upalpha     = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" |
1667*0Sstevel@tonic-gate  *                  "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" |
1668*0Sstevel@tonic-gate  *                  "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" |
1669*0Sstevel@tonic-gate  *                  "Y" | "Z"
1670*0Sstevel@tonic-gate  *
1671*0Sstevel@tonic-gate  *    digit       = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
1672*0Sstevel@tonic-gate  *                  "8" | "9"
1673*0Sstevel@tonic-gate  *
1674*0Sstevel@tonic-gate  *    mark        = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
1675*0Sstevel@tonic-gate  *
1676*0Sstevel@tonic-gate  *    escaped     = "%" hex hex
1677*0Sstevel@tonic-gate  *    hex         = digit | "A" | "B" | "C" | "D" | "E" | "F" |
1678*0Sstevel@tonic-gate  *                  "a" | "b" | "c" | "d" | "e" | "f"
1679*0Sstevel@tonic-gate  */
1680*0Sstevel@tonic-gate 
1681*0Sstevel@tonic-gate static char pchars[] = {
1682*0Sstevel@tonic-gate     0, 0, 0, 0, 0, 0, 0, 0,	/* 0x00 - 0x07 */
1683*0Sstevel@tonic-gate     0, 0, 0, 0, 0, 0, 0, 0,	/* 0x08 - 0x0F */
1684*0Sstevel@tonic-gate     0, 0, 0, 0, 0, 0, 0, 0,	/* 0x10 - 0x17 */
1685*0Sstevel@tonic-gate     0, 0, 0, 0, 0, 0, 0, 0,	/* 0x18 - 0x1F */
1686*0Sstevel@tonic-gate     0, 1, 0, 0, 1, 1, 1, 1,	/* 0x20 - 0x27 */
1687*0Sstevel@tonic-gate     0, 0, 1, 1, 1, 1, 1, 1,	/* 0x28 - 0x2F */
1688*0Sstevel@tonic-gate     1, 1, 1, 1, 1, 1, 1, 1,	/* 0x30 - 0x37 */
1689*0Sstevel@tonic-gate     1, 1, 1, 0, 0, 1, 0, 0,	/* 0x38 - 0x3F */
1690*0Sstevel@tonic-gate     1, 1, 1, 1, 1, 1, 1, 1,	/* 0x40 - 0x47 */
1691*0Sstevel@tonic-gate     1, 1, 1, 1, 1, 1, 1, 1,	/* 0x48 - 0x4F */
1692*0Sstevel@tonic-gate     1, 1, 1, 1, 1, 1, 1, 1,	/* 0x50 - 0x57 */
1693*0Sstevel@tonic-gate     1, 1, 1, 0, 0, 0, 0, 1,	/* 0x58 - 0x5F */
1694*0Sstevel@tonic-gate     0, 1, 1, 1, 1, 1, 1, 1,	/* 0x60 - 0x67 */
1695*0Sstevel@tonic-gate     1, 1, 1, 1, 1, 1, 1, 1,	/* 0x68 - 0x6F */
1696*0Sstevel@tonic-gate     1, 1, 1, 1, 1, 1, 1, 1,	/* 0x70 - 0x77 */
1697*0Sstevel@tonic-gate     1, 1, 1, 0, 0, 0, 1, 0	/* 0x78 - 0x7F */
1698*0Sstevel@tonic-gate };
1699*0Sstevel@tonic-gate 
1700*0Sstevel@tonic-gate #define	PCHARS_MASK 0x7F
1701*0Sstevel@tonic-gate 
1702*0Sstevel@tonic-gate /*
1703*0Sstevel@tonic-gate  * This is the main L7 request message parse, we are called each time
1704*0Sstevel@tonic-gate  * new data is availble for a socket, each time a single buffer of the
1705*0Sstevel@tonic-gate  * entire message to date is given.
1706*0Sstevel@tonic-gate  *
1707*0Sstevel@tonic-gate  * Here we parse the request looking for the URI, parse it, and if a
1708*0Sstevel@tonic-gate  * supported scheme call the scheme parser to commplete the parse of any
1709*0Sstevel@tonic-gate  * headers which may further qualify the identity of the requested object
1710*0Sstevel@tonic-gate  * then lookup it up in the URI hash.
1711*0Sstevel@tonic-gate  *
1712*0Sstevel@tonic-gate  * Return B_TRUE for more processing.
1713*0Sstevel@tonic-gate  *
1714*0Sstevel@tonic-gate  * Note, at this time the parser supports the generic message format as
1715*0Sstevel@tonic-gate  * specified in RFC 822 with potentional limitations as specified in RFC
1716*0Sstevel@tonic-gate  * 2616 for HTTP messages.
1717*0Sstevel@tonic-gate  *
1718*0Sstevel@tonic-gate  * Note, the caller supports an mblk_t chain, for now the parser(s)
1719*0Sstevel@tonic-gate  * require the complete header in a single mblk_t. This is the common
1720*0Sstevel@tonic-gate  * case and certainly for high performance environments, if at a future
1721*0Sstevel@tonic-gate  * date mblk_t chains are important the parse can be reved to process
1722*0Sstevel@tonic-gate  * mblk_t chains.
1723*0Sstevel@tonic-gate  */
1724*0Sstevel@tonic-gate 
1725*0Sstevel@tonic-gate boolean_t
1726*0Sstevel@tonic-gate nl7c_parse(struct sonode *so, boolean_t nonblocking, boolean_t *ret,
1727*0Sstevel@tonic-gate 	int max_mblk)
1728*0Sstevel@tonic-gate {
1729*0Sstevel@tonic-gate 	char	*cp = (char *)so->so_nl7c_rcv_mp->b_rptr;
1730*0Sstevel@tonic-gate 	char	*ep = (char *)so->so_nl7c_rcv_mp->b_wptr;
1731*0Sstevel@tonic-gate 	char	*get = "GET ";
1732*0Sstevel@tonic-gate 	char	c;
1733*0Sstevel@tonic-gate 	char	*uris;
1734*0Sstevel@tonic-gate 	uri_desc_t *uri;
1735*0Sstevel@tonic-gate 	uri_desc_t *ruri = NULL;
1736*0Sstevel@tonic-gate 
1737*0Sstevel@tonic-gate 	/*
1738*0Sstevel@tonic-gate 	 * Allocate and initialize minimumal state for the request
1739*0Sstevel@tonic-gate 	 * uri_desc_t, in the cache hit case this uri_desc_t will
1740*0Sstevel@tonic-gate 	 * be freed.
1741*0Sstevel@tonic-gate 	 */
1742*0Sstevel@tonic-gate 	uri = kmem_cache_alloc(uri_kmc, KM_SLEEP);
1743*0Sstevel@tonic-gate 	REF_INIT(uri, 1, uri_inactive, uri_kmc);
1744*0Sstevel@tonic-gate 	uri->hash = NULL;
1745*0Sstevel@tonic-gate 	uri->tail = NULL;
1746*0Sstevel@tonic-gate 	uri->scheme = NULL;
1747*0Sstevel@tonic-gate 	uri->count = 0;
1748*0Sstevel@tonic-gate 	if ((uri->reqmp = dupb(so->so_nl7c_rcv_mp)) == NULL) {
1749*0Sstevel@tonic-gate 		nl7c_uri_pass_dupbfail++;
1750*0Sstevel@tonic-gate 		goto pass;
1751*0Sstevel@tonic-gate 	}
1752*0Sstevel@tonic-gate 	/*
1753*0Sstevel@tonic-gate 	 * Set request time to current time.
1754*0Sstevel@tonic-gate 	 */
1755*0Sstevel@tonic-gate 	so->so_nl7c_rtime = gethrestime_sec();
1756*0Sstevel@tonic-gate 	/*
1757*0Sstevel@tonic-gate 	 * Parse the Request-Line for the URI.
1758*0Sstevel@tonic-gate 	 *
1759*0Sstevel@tonic-gate 	 * For backwards HTTP version compatable reasons skip any leading
1760*0Sstevel@tonic-gate 	 * CRLF (or CR or LF) line terminator(s) preceding Request-Line.
1761*0Sstevel@tonic-gate 	 */
1762*0Sstevel@tonic-gate 	while (cp < ep && (*cp == '\r' || *cp == '\n')) {
1763*0Sstevel@tonic-gate 		cp++;
1764*0Sstevel@tonic-gate 	}
1765*0Sstevel@tonic-gate 	while (cp < ep && *get == *cp) {
1766*0Sstevel@tonic-gate 		get++;
1767*0Sstevel@tonic-gate 		cp++;
1768*0Sstevel@tonic-gate 	}
1769*0Sstevel@tonic-gate 	if (*get != 0) {
1770*0Sstevel@tonic-gate 		if (cp == ep) {
1771*0Sstevel@tonic-gate 			nl7c_uri_more_get++;
1772*0Sstevel@tonic-gate 			goto more;
1773*0Sstevel@tonic-gate 		}
1774*0Sstevel@tonic-gate 		nl7c_uri_pass_getnot++;
1775*0Sstevel@tonic-gate 		goto pass;
1776*0Sstevel@tonic-gate 	}
1777*0Sstevel@tonic-gate 	/*
1778*0Sstevel@tonic-gate 	 * Skip over URI path char(s) and save start and past end pointers.
1779*0Sstevel@tonic-gate 	 */
1780*0Sstevel@tonic-gate 	uris = cp;
1781*0Sstevel@tonic-gate 	while (cp < ep && (c = *cp) != ' ' && c != '\r') {
1782*0Sstevel@tonic-gate 		if (c == '?') {
1783*0Sstevel@tonic-gate 			/* Don't cache but still may want to parse */
1784*0Sstevel@tonic-gate 			uri->hash = URI_TEMP;
1785*0Sstevel@tonic-gate 		}
1786*0Sstevel@tonic-gate 		cp++;
1787*0Sstevel@tonic-gate 	}
1788*0Sstevel@tonic-gate 	if (c != '\r' && cp == ep) {
1789*0Sstevel@tonic-gate 		nl7c_uri_more_eol++;
1790*0Sstevel@tonic-gate 		goto more;
1791*0Sstevel@tonic-gate 	}
1792*0Sstevel@tonic-gate 	/*
1793*0Sstevel@tonic-gate 	 * Request-Line URI parsed, pass the rest of the request on
1794*0Sstevel@tonic-gate 	 * to the the http scheme parse.
1795*0Sstevel@tonic-gate 	 */
1796*0Sstevel@tonic-gate 	uri->path.cp = uris;
1797*0Sstevel@tonic-gate 	uri->path.ep = cp;
1798*0Sstevel@tonic-gate 	if (! nl7c_http_request(&cp, ep, uri, so)) {
1799*0Sstevel@tonic-gate 		/*
1800*0Sstevel@tonic-gate 		 * Parse not successful, the pointer to the parse pointer
1801*0Sstevel@tonic-gate 		 * "cp" is overloaded such that ! NULL for more data and
1802*0Sstevel@tonic-gate 		 * NULL for pass on request.
1803*0Sstevel@tonic-gate 		 */
1804*0Sstevel@tonic-gate 		if (cp != NULL) {
1805*0Sstevel@tonic-gate 			nl7c_uri_more_http++;
1806*0Sstevel@tonic-gate 			goto more;
1807*0Sstevel@tonic-gate 		}
1808*0Sstevel@tonic-gate 		nl7c_uri_pass_http++;
1809*0Sstevel@tonic-gate 		goto pass;
1810*0Sstevel@tonic-gate 	}
1811*0Sstevel@tonic-gate 	if (uri->hash == URI_TEMP) {
1812*0Sstevel@tonic-gate 		if (so->so_nl7c_flags & NL7C_SOPERSIST) {
1813*0Sstevel@tonic-gate 			/* Temporary URI so skip hash processing */
1814*0Sstevel@tonic-gate 			nl7c_uri_request++;
1815*0Sstevel@tonic-gate 			nl7c_uri_temp++;
1816*0Sstevel@tonic-gate 			goto temp;
1817*0Sstevel@tonic-gate 		}
1818*0Sstevel@tonic-gate 		/* Not persistent so not interested in the response */
1819*0Sstevel@tonic-gate 		nl7c_uri_pass_temp++;
1820*0Sstevel@tonic-gate 		goto pass;
1821*0Sstevel@tonic-gate 	}
1822*0Sstevel@tonic-gate 	/*
1823*0Sstevel@tonic-gate 	 * If logging enabled save the request uri pointer and place
1824*0Sstevel@tonic-gate 	 * an additional reference on it for logging use after lookup().
1825*0Sstevel@tonic-gate 	 */
1826*0Sstevel@tonic-gate 	if (nl7c_logd_enabled) {
1827*0Sstevel@tonic-gate 		ruri = uri;
1828*0Sstevel@tonic-gate 		REF_HOLD(ruri);
1829*0Sstevel@tonic-gate 	}
1830*0Sstevel@tonic-gate 	/*
1831*0Sstevel@tonic-gate 	 * Check the URI hash for a cached response.
1832*0Sstevel@tonic-gate 	 */
1833*0Sstevel@tonic-gate 	if ((uri = uri_lookup(uri, B_TRUE, nonblocking)) == NULL) {
1834*0Sstevel@tonic-gate 		/*
1835*0Sstevel@tonic-gate 		 * Failed to lookup due to nonblocking wait required,
1836*0Sstevel@tonic-gate 		 * interrupted cv_wait_sig(), KM_NOSLEEP memory alloc
1837*0Sstevel@tonic-gate 		 * failure, ... Just pass on this request.
1838*0Sstevel@tonic-gate 		 */
1839*0Sstevel@tonic-gate 		nl7c_uri_pass_addfail++;
1840*0Sstevel@tonic-gate 		goto pass;
1841*0Sstevel@tonic-gate 	}
1842*0Sstevel@tonic-gate 	nl7c_uri_request++;
1843*0Sstevel@tonic-gate 	if (uri->response.sz > 0) {
1844*0Sstevel@tonic-gate 		/*
1845*0Sstevel@tonic-gate 		 * We have the response cached, update recv mblk rptr
1846*0Sstevel@tonic-gate 		 * to reflect the data consumed above, send the response
1847*0Sstevel@tonic-gate 		 * out the socket, release reference on uri from the
1848*0Sstevel@tonic-gate 		 * call to lookup_add(), set the *ret value to B_TRUE
1849*0Sstevel@tonic-gate 		 * for socket close and return B_FALSE to indcate no
1850*0Sstevel@tonic-gate 		 * more data needed.
1851*0Sstevel@tonic-gate 		 */
1852*0Sstevel@tonic-gate 		mblk_t	*mp = so->so_nl7c_rcv_mp;
1853*0Sstevel@tonic-gate 
1854*0Sstevel@tonic-gate 		/* If a saved ruri set above then log request */
1855*0Sstevel@tonic-gate 		if (ruri != NULL) {
1856*0Sstevel@tonic-gate 			ipaddr_t faddr;
1857*0Sstevel@tonic-gate 
1858*0Sstevel@tonic-gate 			if (so->so_family == AF_INET) {
1859*0Sstevel@tonic-gate 				/* Only support IPv4 addrs */
1860*0Sstevel@tonic-gate 				faddr = ((struct sockaddr_in *)
1861*0Sstevel@tonic-gate 				    so->so_faddr_sa) ->sin_addr.s_addr;
1862*0Sstevel@tonic-gate 			} else {
1863*0Sstevel@tonic-gate 				faddr = 0;
1864*0Sstevel@tonic-gate 			}
1865*0Sstevel@tonic-gate 			nl7c_logd_log(ruri, uri, so->so_nl7c_rtime, faddr);
1866*0Sstevel@tonic-gate 			REF_RELE(ruri);
1867*0Sstevel@tonic-gate 		}
1868*0Sstevel@tonic-gate 		nl7c_uri_hit++;
1869*0Sstevel@tonic-gate 		if (cp == (char *)mp->b_wptr) {
1870*0Sstevel@tonic-gate 			so->so_nl7c_rcv_mp = mp->b_cont;
1871*0Sstevel@tonic-gate 			mp->b_cont = NULL;
1872*0Sstevel@tonic-gate 			freeb(mp);
1873*0Sstevel@tonic-gate 		} else {
1874*0Sstevel@tonic-gate 			mp->b_rptr = (unsigned char *)cp;
1875*0Sstevel@tonic-gate 		}
1876*0Sstevel@tonic-gate 		uri_response(so, uri, max_mblk);
1877*0Sstevel@tonic-gate 		REF_RELE(uri);
1878*0Sstevel@tonic-gate 		*ret = B_TRUE;
1879*0Sstevel@tonic-gate 		return (B_FALSE);
1880*0Sstevel@tonic-gate 	}
1881*0Sstevel@tonic-gate 	if (ruri != NULL) {
1882*0Sstevel@tonic-gate 		REF_RELE(ruri);
1883*0Sstevel@tonic-gate 	}
1884*0Sstevel@tonic-gate 	/*
1885*0Sstevel@tonic-gate 	 * Don't have a response cached or may want to cache the
1886*0Sstevel@tonic-gate 	 * response from the webserver so store the uri pointer in
1887*0Sstevel@tonic-gate 	 * the so subsequent write-side calls ...
1888*0Sstevel@tonic-gate 	 */
1889*0Sstevel@tonic-gate 	nl7c_uri_miss++;
1890*0Sstevel@tonic-gate temp:
1891*0Sstevel@tonic-gate 	uri->proc = so;
1892*0Sstevel@tonic-gate 	so->so_nl7c_uri = uri;
1893*0Sstevel@tonic-gate 	so->so_nl7c_flags |= NL7C_WAITWRITE;
1894*0Sstevel@tonic-gate 	*ret = B_FALSE;
1895*0Sstevel@tonic-gate 	return (B_FALSE);
1896*0Sstevel@tonic-gate 
1897*0Sstevel@tonic-gate more:
1898*0Sstevel@tonic-gate 	/* More data is needed, note fragmented recv not supported */
1899*0Sstevel@tonic-gate 	nl7c_uri_more++;
1900*0Sstevel@tonic-gate 
1901*0Sstevel@tonic-gate pass:
1902*0Sstevel@tonic-gate 	/* Pass on this request */
1903*0Sstevel@tonic-gate 	nl7c_uri_pass++;
1904*0Sstevel@tonic-gate 	nl7c_uri_request++;
1905*0Sstevel@tonic-gate 	if (ruri != NULL) {
1906*0Sstevel@tonic-gate 		REF_RELE(ruri);
1907*0Sstevel@tonic-gate 	}
1908*0Sstevel@tonic-gate 	if (uri) {
1909*0Sstevel@tonic-gate 		REF_RELE(uri);
1910*0Sstevel@tonic-gate 	}
1911*0Sstevel@tonic-gate 	so->so_nl7c_flags = 0;
1912*0Sstevel@tonic-gate 	*ret = B_FALSE;
1913*0Sstevel@tonic-gate 	return (B_FALSE);
1914*0Sstevel@tonic-gate }
1915