Exemplo n.º 1
0
void
vdev_queue_io_done(zio_t *zio)
{
	vdev_queue_t *vq = &zio->io_vd->vdev_queue;

	if (zio_injection_enabled)
		delay(SEC_TO_TICK(zio_handle_io_delay(zio)));

	mutex_enter(&vq->vq_lock);

	vdev_queue_pending_remove(vq, zio);

	vq->vq_io_complete_ts = gethrtime();

	for (int i = 0; i < zfs_vdev_ramp_rate; i++) {
		zio_t *nio = vdev_queue_io_to_issue(vq, zfs_vdev_max_pending);
		if (nio == NULL)
			break;
		mutex_exit(&vq->vq_lock);
		if (nio->io_done == vdev_queue_agg_io_done) {
			zio_nowait(nio);
		} else {
			zio_vdev_io_reissue(nio);
			zio_execute(nio);
		}
		mutex_enter(&vq->vq_lock);
	}

	mutex_exit(&vq->vq_lock);
}
Exemplo n.º 2
0
/*
 * Convert internal cap statistics into values exported by cap kstat.
 * Note that the kstat is held throughout this function but caps_lock is not.
 */
static int
cap_kstat_update(kstat_t *ksp, int rw)
{
	struct cap_kstat *capsp = &cap_kstat;
	cpucap_t *cap = ksp->ks_private;
	clock_t	tick_sec = SEC_TO_TICK(1);
	char *zonename = cap->cap_zone->zone_name;

	if (rw == KSTAT_WRITE)
		return (EACCES);

	capsp->cap_value.value.ui64 =
	    ROUND_SCALE(cap->cap_value, cap_tick_cost);
	capsp->cap_baseline.value.ui64 =
	    ROUND_SCALE(cap->cap_base, cap_tick_cost);
	capsp->cap_effective.value.ui64 =
	    ROUND_SCALE(cap->cap_chk_value, cap_tick_cost);
	capsp->cap_burst_limit.value.ui64 =
	    ROUND_SCALE(cap->cap_burst_limit, tick_sec);
	capsp->cap_usage.value.ui64 =
	    ROUND_SCALE(cap->cap_usage, cap_tick_cost);
	capsp->cap_maxusage.value.ui64 =
	    ROUND_SCALE(cap->cap_maxusage, cap_tick_cost);
	capsp->cap_nwait.value.ui64 = cap->cap_waitq.wq_count;
	capsp->cap_below.value.ui64 = ROUND_SCALE(cap->cap_below, tick_sec);
	capsp->cap_above.value.ui64 = ROUND_SCALE(cap->cap_above, tick_sec);
	capsp->cap_above_base.value.ui64 =
	    ROUND_SCALE(cap->cap_above_base, tick_sec);
	capsp->cap_bursting.value.ui64 =
	    ROUND_SCALE(cap->cap_bursting, tick_sec);
	kstat_named_setstr(&capsp->cap_zonename, zonename);

	return (0);
}
Exemplo n.º 3
0
/*
 * Set zone's maximum burst time in seconds.  A burst time of 0 means that
 * the zone can run over its baseline indefinitely.
 */
int
cpucaps_zone_set_burst_time(zone_t *zone, rctl_qty_t base_val)
{
	cpucap_t *cap = NULL;
	hrtime_t value;

	ASSERT(base_val <= INT_MAX);
	/* Treat the default as 0 - no limit */
	if (base_val == INT_MAX)
		base_val = 0;
	if (base_val > INT_MAX)
		base_val = INT_MAX;

	if (CPUCAPS_OFF() || !ZONE_IS_CAPPED(zone))
		return (0);

	if (zone->zone_cpucap == NULL)
		cap = cap_alloc();

	mutex_enter(&caps_lock);

	if (cpucaps_busy) {
		mutex_exit(&caps_lock);
		return (EBUSY);
	}

	/*
	 * Double-check whether zone->zone_cpucap is NULL, now with caps_lock
	 * held. If it is still NULL, assign a newly allocated cpucap to it.
	 */
	if (zone->zone_cpucap == NULL) {
		zone->zone_cpucap = cap;
	} else if (cap != NULL) {
		cap_free(cap);
	}

	cap = zone->zone_cpucap;

	value = SEC_TO_TICK(base_val);
	if (value < 0)
		value = 0;

	cap->cap_burst_limit = value;

	mutex_exit(&caps_lock);

	return (0);
}
Exemplo n.º 4
0
/*
 * This function is called by main() to either load the backup kernel for panic
 * fast reboot, or to reserve low physical memory for fast reboot.
 */
void
fastboot_post_startup()
{
	lbolt_at_boot = ddi_get_lbolt();

	/* Default to 10 minutes */
	if (fastreboot_onpanic_uptime == LONG_MAX)
		fastreboot_onpanic_uptime = SEC_TO_TICK(10 * 60);

	if (!fastreboot_capable)
		return;

	mutex_enter(&fastreboot_config_mutex);

	fastboot_get_bootprop();

	if (fastreboot_onpanic)
		fastboot_load_kernel(fastreboot_onpanic_cmdline);
	else if (reserve_mem_enabled)
		fastboot_reserve_mem(&newkernel);

	mutex_exit(&fastreboot_config_mutex);
}
Exemplo n.º 5
0
boolean_t
nl7c_http_response(char **cpp, char *ep, uri_desc_t *uri, struct sonode *so)
{
	http_t	*http = uri->scheme;
	char	*cp = *cpp;
	char	*hp;
	char	*scp, *sep;
	char	*HTTP = "HTTP/";
	int	status = 0;
	token_t	*match;
#ifdef	NOT_YET
	uint32_t major, minor;
#endif
	boolean_t nocache = B_FALSE;
	boolean_t persist = B_FALSE;

	ASSERT(http != NULL);

	if (http->parsed) {
		if (uri->respclen != URI_LEN_NOVALUE) {
			/* Chunked response */
			sep = ep;
			goto chunked;
		}
		/* Already parsed, nothing todo */
		return (B_TRUE);
	}

	/*
	 * Parse the HTTP/N.N version. Note, there's currently no use
	 * for the actual response major nor minor values as only the
	 * request values are used.
	 */
	while (cp < ep && *HTTP == *cp) {
		HTTP++;
		cp++;
	}
	if (*HTTP != 0) {
		if (cp == ep)
			goto more;
		goto bad;
	}
	if (cp == ep)
		goto more;

	if (*cp < '0' || *cp > '9')
		goto bad;
#ifdef	NOT_YET
	major = *cp++ - '0';
#else
	cp++;
#endif

	if (cp == ep)
		goto more;
	if (*cp++ != '.')
		goto bad;
	if (cp == ep)
		goto more;
	if (*cp < '0' || *cp > '9')
		goto bad;
#ifdef	NOT_YET
	minor = *cp++ - '0';
#else
	cp++;
#endif

	if (cp == ep)
		goto more;

got_version:

	/*
	 * Get the response code.
	 */
	if (*cp++ != ' ')
		goto bad;
	if (cp == ep)
		goto more;

	do {
		if (*cp == ' ')
			break;
		if (*cp < '0' || *cp > '9')
			goto bad;
		if (status)
			status *= 10;
		status += *cp++ - '0';
	} while (cp < ep);

	switch (status) {
	case 200:
		/*
		 * The only response status we continue to process.
		 */
		break;
	case 304:
		nl7c_http_response_304++;
		nocache = B_TRUE;
		uri->resplen = 0;
		goto pass;
	case 307:
		nl7c_http_response_307++;
		nocache = B_TRUE;
		uri->resplen = 0;
		goto pass;
	case 400:
		nl7c_http_response_400++;
		/*
		 * Special case some response status codes, just mark
		 * as nocache and no response length and pass on the
		 * request/connection.
		 */
		nocache = B_TRUE;
		uri->resplen = 0;
		goto pass;
	default:
		/*
		 * All other response codes result in a parse failure.
		 */
		goto bad;
	}

	/*
	 * Initialize persistent state based on request HTTP version.
	 */
	if (http->major == 1) {
		if (http->minor >= 1) {
			/* 1.1 persistent by default */
			persist = B_TRUE;
		} else {
			/* 1.0 isn't persistent by default */
			persist = B_FALSE;
		}
	} else if (http->major == 0) {
		/* Before 1.0 no persistent connections */
		persist = B_FALSE;
	} else {
		/* >= 2.0 not supported (yet) */
		goto bad;
	}

	/*
	 * Parse HTTP headers through the EOH
	 * (End Of Header, i.e. an empty line).
	 */
	for (sep = ep; cp < ep; ep = sep) {
		/* Get the next line */
		scp = cp;
		match = ttree_line_parse(res_tree, &cp, &ep, &hp, NULL);
		if (match != NULL) {
			if (match->act & QUALIFIER) {
				/*
				 * Header field text is used to qualify this
				 * request/response, based on qualifier type
				 * optionally convert and store *http.
				 */
				char	c;
				int	n = 0;
				time_t	secs;

				ASSERT(hp != NULL && ep != NULL);

				if (match->act & NUMERIC) {
					while (hp < ep) {
						c = *hp++;
						if (match->act & HEX) {
							hd2i(c, n);
							if (n == -1)
								goto bad;
						} else {
							if (! isdigit(c))
								goto bad;
							n *= 10;
							n += c - '0';
						}
					}
				} else if (match->act & DATE) {
					secs = http_date2time_t(hp, ep);
				}
				switch (match->tokid) {

				case Shdr_Cache_Control_Max_Age:
					break;

				case Shdr_Cache_Control_No_Cache:
					nocache = B_TRUE;
					break;

				case Shdr_Cache_Control_No_Store:
					nocache = B_TRUE;
					break;

				case Shdr_Connection_close:
					persist = B_FALSE;
					break;

				case Shdr_Connection_Keep_Alive:
					persist = B_TRUE;
					break;

				case Shdr_Chunked:
					uri->respclen = 0;
					uri->resplen = 0;
					nl7c_http_response_chunked++;
					break;

				case Shdr_Content_Length:
					if (uri->respclen == URI_LEN_NOVALUE)
						uri->resplen = n;
					break;

				case Shdr_Date:
					http->date = secs;
					break;

				case Shdr_ETag:
					http->etag.cp = hp;
					http->etag.ep = ep;
					break;

				case Shdr_Expires:
					http->expire = secs;
					break;

				case Shdr_Keep_Alive:
					persist = B_TRUE;
					break;

				case Shdr_Last_Modified:
					http->lastmod = secs;
					break;

				case Shdr_Set_Cookie:
					nocache = B_TRUE;
					break;

				case Shdr_Server:
					break;

				default:
					nocache = B_TRUE;
					break;
				};
			}
			if (match->act & FILTER) {
				/*
				 * Filter header, do a copyover the header
				 * text, guarenteed to be at least 1 byte.
				 */
				char	*cop = scp;
				int	n = (ep - cop) - 1;
				char	filter[] = "NL7C-Filtered";

				n = MIN(n, sizeof (filter) - 1);
				if (n > 0)
					bcopy(filter, cop, n);
				cop += n;
				ASSERT(cop < ep);
				*cop++ = ':';
				while (cop < ep)
					*cop++ = ' ';
			}
			if (match->act & NOCACHE) {
				nocache = B_TRUE;
			}
		} else if (hp == NULL) {
			uri->eoh = scp;
			goto done;
		} else if (ep == NULL) {
			goto more;
		}
	}
	/* No EOH found */
	goto more;

done:
	/* Parse completed */
	http->parsed = B_TRUE;
	/* Save the HTTP header length */
	http->headlen = (cp - *cpp);
	if (uri->respclen == URI_LEN_NOVALUE) {
		if (uri->resplen == URI_LEN_NOVALUE) {
			nl7c_http_response_pass1++;
			goto pass;
		}
	}
	/* Add header length to URI response length */
	uri->resplen += http->headlen;

	/* Set socket persist state */
	if (persist)
		so->so_nl7c_flags |= NL7C_SOPERSIST;
	else
		so->so_nl7c_flags &= ~NL7C_SOPERSIST;

	if (http->major == 1) {
		so->so_nl7c_flags &= ~NL7C_SCHEMEPRIV;
		if (http->minor >= 1) {
			if (! persist)
				so->so_nl7c_flags |= HTTP_CONN_CL;
		} else {
			if (persist)
				so->so_nl7c_flags |= HTTP_CONN_KA;
			else
				so->so_nl7c_flags |= HTTP_CONN_CL;
		}
	}

	if (nocache) {
		/*
		 * Response not to be cached, only post response
		 * processing code common to both non and cached
		 * cases above here and code for the cached case
		 * below.
		 *
		 * Note, chunked transfer processing is the last
		 * to be done.
		 */
		uri->nocache = B_TRUE;
		if (uri->respclen != URI_LEN_NOVALUE) {
			/* Chunked response */
			goto chunked;
		}
		/* Nothing more todo */
		goto parsed;
	}

	if (http->expire != -1 && http->date != -1) {
		if (http->expire <= http->date) {
			/* ??? just pass */
			nl7c_http_response_pass2++;
			goto pass;
		}
		/* Have a valid expire and date so calc an lbolt expire */
		uri->expire = lbolt + SEC_TO_TICK(http->expire - http->date);
	} else if (nl7c_uri_ttl != -1) {
		/* No valid expire speced and we have a TTL */
		uri->expire = lbolt + SEC_TO_TICK(nl7c_uri_ttl);
	}

chunked:
	/*
	 * Chunk transfer parser and processing, a very simple parser
	 * is implemented here for the common case were one, or more,
	 * complete chunk(s) are passed in (i.e. length header + body).
	 *
	 * All other cases are passed.
	 */
	scp = cp;
	while (uri->respclen != URI_LEN_NOVALUE && cp < sep) {
		if (uri->respclen == URI_LEN_CONSUMED) {
			/* Skip trailing "\r\n" */
			if (cp == sep)
				goto more;
			if (*cp++ != '\r')
				goto bad;
			if (cp == sep)
				goto more;
			if (*cp++ != '\n')
				goto bad;
			uri->respclen = 0;
		}
		if (uri->respclen == 0) {
			/* Parse a chunklen "[0-9A-Fa-f]+" */
			char	c;
			int	n = 0;

			if (cp == sep)
				goto more;
			nl7c_http_response_chunkparse++;
			while (cp < sep && (c = *cp++) != '\r') {
				hd2i(c, n);
				if (n == -1)
					goto bad;
			}
			if (cp == sep)
				goto more;
			if (*cp++ != '\n')
				goto bad;
			uri->respclen = n;
			if (n == 0) {
				/* Last chunk, skip trailing "\r\n" */
				if (cp == sep)
					goto more;
				if (*cp++ != '\r')
					goto bad;
				if (cp == sep)
					goto more;
				if (*cp++ != '\n')
					goto bad;
				uri->respclen = URI_LEN_NOVALUE;
				break;
			}
		}
		if (uri->respclen > 0) {
			/* Consume some bytes for the current chunk */
			uint32_t sz = (sep - cp);

			if (sz > uri->respclen)
				sz = uri->respclen;
			uri->respclen -= sz;
			cp += sz;
			if (uri->respclen == 0) {
				/* End of chunk, skip trailing "\r\n" */
				if (cp == sep) {
					uri->respclen = URI_LEN_CONSUMED;
					goto more;
				}
				if (*cp++ != '\r')
					goto bad;
				if (cp == sep)
					goto more;
				if (*cp++ != '\n')
					goto bad;
				if (cp == sep)
					goto more;
			}
		}
	}
	uri->resplen += (cp - scp);

parsed:
	*cpp = cp;
	return (B_TRUE);

pass:
	*cpp = NULL;
	return (B_TRUE);

bad:
	*cpp = NULL;
	return (B_FALSE);

more:
	uri->resplen += (cp - scp);
	*cpp = cp;
	return (B_FALSE);
}