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); }
/* * 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); }
/* * 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); }
/* * 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); }
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); }