/* * Sanity check volume block size. */ int zvol_check_volblocksize(const char *name, uint64_t volblocksize) { /* Record sizes above 128k need the feature to be enabled */ if (volblocksize > SPA_OLD_MAXBLOCKSIZE) { spa_t *spa; int error; if ((error = spa_open(name, &spa, FTAG)) != 0) return (error); if (!spa_feature_is_enabled(spa, SPA_FEATURE_LARGE_BLOCKS)) { spa_close(spa, FTAG); return (SET_ERROR(ENOTSUP)); } /* * We don't allow setting the property above 1MB, * unless the tunable has been changed. */ if (volblocksize > zfs_max_recordsize) return (SET_ERROR(EDOM)); spa_close(spa, FTAG); } if (volblocksize < SPA_MINBLOCKSIZE || volblocksize > SPA_MAXBLOCKSIZE || !ISP2(volblocksize)) return (SET_ERROR(EDOM)); return (0); }
/* * Process the buffer of nvlists, unpacking and storing each nvlist record * into 'records'. 'leftover' is set to the number of bytes that weren't * processed as there wasn't a complete record. */ static int zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover, nvlist_t ***records, uint_t *numrecords) { uint64_t reclen; nvlist_t *nv; int i; while (bytes_read > sizeof (reclen)) { /* get length of packed record (stored as little endian) */ for (i = 0, reclen = 0; i < sizeof (reclen); i++) reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i); if (bytes_read < sizeof (reclen) + reclen) break; /* unpack record */ if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0) return (ENOMEM); bytes_read -= sizeof (reclen) + reclen; buf += sizeof (reclen) + reclen; /* add record to nvlist array */ (*numrecords)++; if (ISP2(*numrecords + 1)) { *records = realloc(*records, *numrecords * 2 * sizeof (nvlist_t *)); } (*records)[*numrecords - 1] = nv; } *leftover = bytes_read; return (0); }
/* * Create a pool of mblks from which future vio_allocb() requests * will be serviced. * * NOTE: num_mblks has to non-zero and a power-of-2 * * Returns 0 on success or EINVAL if num_mblks is zero or not * a power of 2. */ int vio_create_mblks(uint64_t num_mblks, size_t mblk_size, vio_mblk_pool_t **poolp) { vio_mblk_pool_t *vmplp; vio_mblk_t *vmp; uint8_t *datap; int i; if (!(num_mblks) || (!ISP2(num_mblks))) { *poolp = 0; return (EINVAL); } vmplp = kmem_zalloc(sizeof (*vmplp), KM_SLEEP); vmplp->quelen = num_mblks; vmplp->quemask = num_mblks - 1; /* expects quelen is power-of-2 */ vmplp->mblk_size = mblk_size; mutex_init(&vmplp->hlock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(DDI_INTR_SOFTPRI_DEFAULT)); mutex_init(&vmplp->tlock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(DDI_INTR_SOFTPRI_DEFAULT)); vmplp->basep = kmem_zalloc(num_mblks * sizeof (vio_mblk_t), KM_SLEEP); vmplp->datap = kmem_zalloc(num_mblks * mblk_size, KM_SLEEP); vmplp->nextp = NULL; /* create a queue of pointers to free vio_mblk_t's */ vmplp->quep = kmem_zalloc(vmplp->quelen * sizeof (vio_mblk_t *), KM_SLEEP); vmplp->head = 0; vmplp->tail = 0; for (i = 0, datap = vmplp->datap; i < num_mblks; i++) { vmp = &(vmplp->basep[i]); vmp->vmplp = vmplp; vmp->datap = datap; vmp->reclaim.free_func = vio_freeb; vmp->reclaim.free_arg = (caddr_t)vmp; vmp->mp = desballoc(vmp->datap, mblk_size, BPRI_MED, &vmp->reclaim); if (vmp->mp == NULL) continue; /* put this vmp on the free stack */ vmplp->quep[vmplp->tail] = vmp; vmplp->tail = (vmplp->tail + 1) & vmplp->quemask; datap += mblk_size; } *poolp = vmplp; return (0); }
int zvol_check_volblocksize(uint64_t volblocksize) { if (volblocksize < SPA_MINBLOCKSIZE || volblocksize > SPA_MAXBLOCKSIZE || !ISP2(volblocksize)) return (EDOM); return (0); }
static void blksz_changed_cb(void *arg, uint64_t newval) { zfs_sb_t *zsb = arg; ASSERT3U(newval, <=, spa_maxblocksize(dmu_objset_spa(zsb->z_os))); ASSERT3U(newval, >=, SPA_MINBLOCKSIZE); ASSERT(ISP2(newval)); zsb->z_max_blksz = newval; }
int zvol_check_volblocksize(zfs_cmd_t *zc) { if (zc->zc_volblocksize < SPA_MINBLOCKSIZE || zc->zc_volblocksize > SPA_MAXBLOCKSIZE || !ISP2(zc->zc_volblocksize)) return (EDOM); return (0); }
static void blksz_changed_cb(void *arg, uint64_t newval) { zfs_sb_t *zsb = arg; if (newval < SPA_MINBLOCKSIZE || newval > SPA_MAXBLOCKSIZE || !ISP2(newval)) newval = SPA_MAXBLOCKSIZE; zsb->z_max_blksz = newval; }
static void blksz_changed_cb(void *arg, uint64_t newval) { zfsvfs_t *zfsvfs = arg; if (newval < SPA_MINBLOCKSIZE || newval > SPA_MAXBLOCKSIZE || !ISP2(newval)) newval = SPA_MAXBLOCKSIZE; zfsvfs->z_max_blksz = newval; zfsvfs->z_vfs->vfs_bsize = newval; }
static boolean_t pci_cfgacc_valid(pci_cfgacc_req_t *req) { int sz = req->size; if (IS_P2ALIGNED(req->offset, sz) && (req->offset + sz - 1 < PCIE_CFG_SPACE_SIZE) && ((sz & 0xf) && ISP2(sz))) return (B_TRUE); cmn_err(CE_WARN, "illegal PCI request: offset = %x, size = %d", req->offset, sz); return (B_FALSE); }
/* * hermon_cfg_wqe_sizes() * Context: Only called from attach() path context */ static void hermon_cfg_wqe_sizes(hermon_state_t *state, hermon_cfg_profile_t *cp) { uint_t max_size, log2; uint_t max_sgl, real_max_sgl; /* * Get the requested maximum number SGL per WQE from the Hermon * patchable variable */ max_sgl = hermon_wqe_max_sgl; /* * Use requested maximum number of SGL to calculate the max descriptor * size (while guaranteeing that the descriptor size is a power-of-2 * cachelines). We have to use the calculation for QP1 MLX transport * because the possibility that we might need to inline a GRH, along * with all the other headers and alignment restrictions, sets the * maximum for the number of SGLs that we can advertise support for. */ max_size = (HERMON_QP_WQE_MLX_QP1_HDRS + (max_sgl << 4)); log2 = highbit(max_size); if (ISP2(max_size)) { log2 = log2 - 1; } max_size = (1 << log2); max_size = min(max_size, state->hs_devlim.max_desc_sz_sq); /* * Then use the calculated max descriptor size to determine the "real" * maximum SGL (the number beyond which we would roll over to the next * power-of-2). */ real_max_sgl = (max_size - HERMON_QP_WQE_MLX_QP1_HDRS) >> 4; /* Then save away this configuration information */ cp->cp_wqe_max_sgl = max_sgl; cp->cp_wqe_real_max_sgl = real_max_sgl; /* SRQ SGL gets set to it's own patchable variable value */ cp->cp_srq_max_sgl = hermon_srq_max_sgl; }
void rds_hash_init() { int i; if (!ISP2(rds_bind_fanout_size)) { /* Not a power of two. Round up to nearest power of two */ for (i = 0; i < UINT_32_BITS; i++) { if (rds_bind_fanout_size < (1 << i)) break; } rds_bind_fanout_size = 1 << i; } rds_bind_fanout = kmem_zalloc(rds_bind_fanout_size * sizeof (rds_bf_t), KM_SLEEP); for (i = 0; i < rds_bind_fanout_size; i++) { mutex_init(&rds_bind_fanout[i].rds_bf_lock, NULL, MUTEX_DEFAULT, NULL); } }
static uint64_t zpios_dmu_object_create(run_args_t *run_args, objset_t *os) { struct dmu_tx *tx; uint64_t obj = 0ULL; uint64_t blksize = run_args->block_size; int rc; if (blksize < SPA_MINBLOCKSIZE || blksize > spa_maxblocksize(dmu_objset_spa(os)) || !ISP2(blksize)) { zpios_print(run_args->file, "invalid block size for pool: %d\n", (int)blksize); return (obj); } tx = dmu_tx_create(os); dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, OBJ_SIZE); rc = dmu_tx_assign(tx, TXG_WAIT); if (rc) { zpios_print(run_args->file, "dmu_tx_assign() failed: %d\n", rc); dmu_tx_abort(tx); return (obj); } obj = dmu_object_alloc(os, DMU_OT_UINT64_OTHER, 0, DMU_OT_NONE, 0, tx); rc = dmu_object_set_blocksize(os, obj, blksize, 0, tx); if (rc) { zpios_print(run_args->file, "dmu_object_set_blocksize to %d failed: %d\n", (int)blksize, rc); dmu_tx_abort(tx); return (obj); } dmu_tx_commit(tx); return (obj); }
/* Check pitch constriants for all chips & tiling formats */ static int i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) { int tile_width; /* Linear is always fine */ if (tiling_mode == I915_TILING_NONE) return 1; if (tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)) tile_width = 128; else tile_width = 512; if (stride == 0) return 0; /* 965+ just needs multiples of tile width */ if (IS_I965G(dev)) { if (stride & (tile_width - 1)) return 0; return 1; } /* Pre-965 needs power of two tile widths */ if (stride < tile_width) return 0; if (!ISP2(stride)) return 0; /* We don't handle the aperture area covered by the fence being bigger * than the object size. */ if (i915_get_fence_size(dev, size) != size) return 0; return 1; }
/*ARGSUSED*/ void * segkmem_alloc_lp(vmem_t *vmp, size_t *sizep, size_t align, int vmflag) { size_t size; kthread_t *t = curthread; segkmem_lpcb_t *lpcb = &segkmem_lpcb; ASSERT(sizep != NULL); size = *sizep; if (lpcb->lp_uselp && !(t->t_flag & T_PANIC) && !(vmflag & SEGKMEM_SHARELOCKED)) { size_t kmemlp_qnt = segkmem_kmemlp_quantum; size_t asize = P2ROUNDUP(size, kmemlp_qnt); void *addr = NULL; ulong_t *lpthrtp = &lpcb->lp_throttle; ulong_t lpthrt = *lpthrtp; int dowakeup = 0; int doalloc = 1; ASSERT(kmem_lp_arena != NULL); ASSERT(asize >= size); if (lpthrt != 0) { /* try to update the throttle value */ lpthrt = atomic_inc_ulong_nv(lpthrtp); if (lpthrt >= segkmem_lpthrottle_max) { lpthrt = atomic_cas_ulong(lpthrtp, lpthrt, segkmem_lpthrottle_max / 4); } /* * when we get above throttle start do an exponential * backoff at trying large pages and reaping */ if (lpthrt > segkmem_lpthrottle_start && !ISP2(lpthrt)) { lpcb->allocs_throttled++; lpthrt--; if (ISP2(lpthrt)) kmem_reap(); return (segkmem_alloc(vmp, size, vmflag)); } } if (!(vmflag & VM_NOSLEEP) && segkmem_heaplp_quantum >= (8 * kmemlp_qnt) && vmem_size(kmem_lp_arena, VMEM_FREE) <= kmemlp_qnt && asize < (segkmem_heaplp_quantum - kmemlp_qnt)) { /* * we are low on free memory in kmem_lp_arena * we let only one guy to allocate heap_lp * quantum size chunk that everybody is going to * share */ mutex_enter(&lpcb->lp_lock); if (lpcb->lp_wait) { /* we are not the first one - wait */ cv_wait(&lpcb->lp_cv, &lpcb->lp_lock); if (vmem_size(kmem_lp_arena, VMEM_FREE) < kmemlp_qnt) { doalloc = 0; } } else if (vmem_size(kmem_lp_arena, VMEM_FREE) <= kmemlp_qnt) { /* * we are the first one, make sure we import * a large page */ if (asize == kmemlp_qnt) asize += kmemlp_qnt; dowakeup = 1; lpcb->lp_wait = 1; } mutex_exit(&lpcb->lp_lock); } /* * VM_ABORT flag prevents sleeps in vmem_xalloc when * large pages are not available. In that case this allocation * attempt will fail and we will retry allocation with small * pages. We also do not want to panic if this allocation fails * because we are going to retry. */ if (doalloc) { addr = vmem_alloc(kmem_lp_arena, asize, (vmflag | VM_ABORT) & ~VM_PANIC); if (dowakeup) { mutex_enter(&lpcb->lp_lock); ASSERT(lpcb->lp_wait != 0); lpcb->lp_wait = 0; cv_broadcast(&lpcb->lp_cv); mutex_exit(&lpcb->lp_lock); } } if (addr != NULL) { *sizep = asize; *lpthrtp = 0; return (addr); } if (vmflag & VM_NOSLEEP) lpcb->nosleep_allocs_failed++; else lpcb->sleep_allocs_failed++; lpcb->alloc_bytes_failed += size; /* if large page throttling is not started yet do it */ if (segkmem_use_lpthrottle && lpthrt == 0) { lpthrt = atomic_cas_ulong(lpthrtp, lpthrt, 1); } } return (segkmem_alloc(vmp, size, vmflag)); }
void cpu_intrq_cleanup(struct cpu *cpu) { struct machcpu *mcpup = &cpu->cpu_m; int cpu_list_size; uint64_t cpu_q_size; uint64_t dev_q_size; uint64_t cpu_rq_size; uint64_t cpu_nrq_size; /* * Free mondo data for xcalls. */ if (mcpup->mondo_data) { contig_mem_free(mcpup->mondo_data, INTR_REPORT_SIZE); mcpup->mondo_data = NULL; mcpup->mondo_data_ra = NULL; } /* * Free per-cpu list of ncpu_guest_max for xcalls */ cpu_list_size = ncpu_guest_max * sizeof (uint16_t); if (cpu_list_size < INTR_REPORT_SIZE) cpu_list_size = INTR_REPORT_SIZE; /* * contig_mem_alloc() requires size to be a power of 2. * Increase size to a power of 2 if necessary. */ if (!ISP2(cpu_list_size)) { cpu_list_size = 1 << highbit(cpu_list_size); } if (mcpup->cpu_list) { contig_mem_free(mcpup->cpu_list, cpu_list_size); mcpup->cpu_list = NULL; mcpup->cpu_list_ra = NULL; } /* * Free sun4v interrupt and error queues. */ if (mcpup->cpu_q_va) { cpu_q_size = cpu_q_entries * INTR_REPORT_SIZE; contig_mem_free(mcpup->cpu_q_va, cpu_q_size); mcpup->cpu_q_va = NULL; mcpup->cpu_q_base_pa = NULL; mcpup->cpu_q_size = 0; } if (mcpup->dev_q_va) { dev_q_size = dev_q_entries * INTR_REPORT_SIZE; contig_mem_free(mcpup->dev_q_va, dev_q_size); mcpup->dev_q_va = NULL; mcpup->dev_q_base_pa = NULL; mcpup->dev_q_size = 0; } if (mcpup->cpu_rq_va) { cpu_rq_size = cpu_rq_entries * Q_ENTRY_SIZE; contig_mem_free(mcpup->cpu_rq_va, 2 * cpu_rq_size); mcpup->cpu_rq_va = NULL; mcpup->cpu_rq_base_pa = NULL; mcpup->cpu_rq_size = 0; } if (mcpup->cpu_nrq_va) { cpu_nrq_size = cpu_nrq_entries * Q_ENTRY_SIZE; contig_mem_free(mcpup->cpu_nrq_va, 2 * cpu_nrq_size); mcpup->cpu_nrq_va = NULL; mcpup->cpu_nrq_base_pa = NULL; mcpup->cpu_nrq_size = 0; } }
int cpu_intrq_setup(struct cpu *cpu) { struct machcpu *mcpup = &cpu->cpu_m; size_t size; /* * This routine will return with an error return if any * contig_mem_alloc() fails. It is expected that the caller will * call cpu_intrq_cleanup() (or cleanup_cpu_common() which will). * That will cleanly free only those blocks that were alloc'd. */ /* * Allocate mondo data for xcalls. */ mcpup->mondo_data = contig_mem_alloc(INTR_REPORT_SIZE); if (mcpup->mondo_data == NULL) { cmn_err(CE_NOTE, "cpu%d: cpu mondo_data allocation failed", cpu->cpu_id); return (ENOMEM); } /* * va_to_pa() is too expensive to call for every crosscall * so we do it here at init time and save it in machcpu. */ mcpup->mondo_data_ra = va_to_pa(mcpup->mondo_data); /* * Allocate a per-cpu list of ncpu_guest_max for xcalls */ size = ncpu_guest_max * sizeof (uint16_t); if (size < INTR_REPORT_SIZE) size = INTR_REPORT_SIZE; /* * contig_mem_alloc() requires size to be a power of 2. * Increase size to a power of 2 if necessary. */ if (!ISP2(size)) { size = 1 << highbit(size); } mcpup->cpu_list = contig_mem_alloc(size); if (mcpup->cpu_list == NULL) { cmn_err(CE_NOTE, "cpu%d: cpu cpu_list allocation failed", cpu->cpu_id); return (ENOMEM); } mcpup->cpu_list_ra = va_to_pa(mcpup->cpu_list); /* * Allocate sun4v interrupt and error queues. */ size = cpu_q_entries * INTR_REPORT_SIZE; mcpup->cpu_q_va = contig_mem_alloc(size); if (mcpup->cpu_q_va == NULL) { cmn_err(CE_NOTE, "cpu%d: cpu intrq allocation failed", cpu->cpu_id); return (ENOMEM); } mcpup->cpu_q_base_pa = va_to_pa(mcpup->cpu_q_va); mcpup->cpu_q_size = size; /* * Allocate device queues */ size = dev_q_entries * INTR_REPORT_SIZE; mcpup->dev_q_va = contig_mem_alloc(size); if (mcpup->dev_q_va == NULL) { cmn_err(CE_NOTE, "cpu%d: dev intrq allocation failed", cpu->cpu_id); return (ENOMEM); } mcpup->dev_q_base_pa = va_to_pa(mcpup->dev_q_va); mcpup->dev_q_size = size; /* * Allocate resumable queue and its kernel buffer */ size = cpu_rq_entries * Q_ENTRY_SIZE; mcpup->cpu_rq_va = contig_mem_alloc(2 * size); if (mcpup->cpu_rq_va == NULL) { cmn_err(CE_NOTE, "cpu%d: resumable queue allocation failed", cpu->cpu_id); return (ENOMEM); } mcpup->cpu_rq_base_pa = va_to_pa(mcpup->cpu_rq_va); mcpup->cpu_rq_size = size; /* zero out the memory */ bzero(mcpup->cpu_rq_va, 2 * size); /* * Allocate non-resumable queues */ size = cpu_nrq_entries * Q_ENTRY_SIZE; mcpup->cpu_nrq_va = contig_mem_alloc(2 * size); if (mcpup->cpu_nrq_va == NULL) { cmn_err(CE_NOTE, "cpu%d: nonresumable queue allocation failed", cpu->cpu_id); return (ENOMEM); } mcpup->cpu_nrq_base_pa = va_to_pa(mcpup->cpu_nrq_va); mcpup->cpu_nrq_size = size; /* zero out the memory */ bzero(mcpup->cpu_nrq_va, 2 * size); return (0); }
/* * Interrupt allocate/free functions */ int ddi_intr_alloc(dev_info_t *dip, ddi_intr_handle_t *h_array, int type, int inum, int count, int *actualp, int behavior) { ddi_intr_handle_impl_t *hdlp, tmp_hdl; int i, ret, cap = 0, curr_type, nintrs; uint_t pri, navail, curr_nintrs = 0; DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: name %s dip 0x%p " "type %x inum %x count %x behavior %x\n", ddi_driver_name(dip), (void *)dip, type, inum, count, behavior)); /* Validate parameters */ if ((dip == NULL) || (h_array == NULL) || (inum < 0) || (count < 1) || (actualp == NULL) || !DDI_INTR_BEHAVIOR_FLAG_VALID(behavior)) { DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: " "Invalid input args\n")); return (DDI_EINVAL); } /* Validate interrupt type */ if (!DDI_INTR_TYPE_FLAG_VALID(type) || !(i_ddi_intr_get_supported_types(dip) & type)) { DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x not " "supported\n", type)); return (DDI_EINVAL); } /* Validate inum not previously allocated */ if ((type == DDI_INTR_TYPE_FIXED) && (i_ddi_get_intr_handle(dip, inum) != NULL)) { DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: inum %d is already " "in use, cannot allocate again!!\n", inum)); return (DDI_EINVAL); } /* Get how many interrupts the device supports */ if ((nintrs = i_ddi_intr_get_supported_nintrs(dip, type)) == 0) { if (ddi_intr_get_nintrs(dip, type, &nintrs) != DDI_SUCCESS) { DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no " "interrupts found of type %d\n", type)); return (DDI_INTR_NOTFOUND); } } /* Get how many interrupts the device is already using */ if ((curr_type = i_ddi_intr_get_current_type(dip)) != 0) { DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x " "is already being used\n", curr_type)); curr_nintrs = i_ddi_intr_get_current_nintrs(dip); } /* Validate interrupt type consistency */ if ((curr_type != 0) && (type != curr_type)) { DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Requested " "interrupt type %x is different from interrupt type %x" "already in use\n", type, curr_type)); return (DDI_EINVAL); } /* Validate count does not exceed what device supports */ if (count > nintrs) { DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no of interrupts " "requested %d is more than supported %d\n", count, nintrs)); return (DDI_EINVAL); } else if ((count + curr_nintrs) > nintrs) { DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: count %d " "+ intrs in use %d exceeds supported %d intrs\n", count, curr_nintrs, nintrs)); return (DDI_EINVAL); } /* Validate power of 2 requirements for MSI */ if ((type == DDI_INTR_TYPE_MSI) && !ISP2(curr_nintrs + count)) { DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: " "MSI count %d is not a power of two\n", count)); return (DDI_EINVAL); } /* * Initialize the device's interrupt information structure, * and establish an association with IRM if it is supported. * * NOTE: IRM checks minimum support, and can return DDI_EAGAIN. */ if (curr_nintrs == 0) { i_ddi_intr_devi_init(dip); if (i_ddi_irm_insert(dip, type, count) == DDI_EAGAIN) { cmn_err(CE_WARN, "ddi_intr_alloc: " "cannot fit into interrupt pool\n"); return (DDI_EAGAIN); } } /* Synchronously adjust IRM associations for non-IRM aware drivers */ if (curr_nintrs && (i_ddi_irm_supported(dip, type) != DDI_SUCCESS)) (void) i_ddi_irm_modify(dip, count + curr_nintrs); /* Get how many interrupts are currently available */ navail = i_ddi_intr_get_current_navail(dip, type); /* Validate that requested number of interrupts are available */ if (curr_nintrs == navail) { DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: max # of intrs %d " "already allocated\n", navail)); return (DDI_EAGAIN); } if ((count + curr_nintrs) > navail) { DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: requested # of " "intrs %d exceeds # of available intrs %d\n", count, navail - curr_nintrs)); if (behavior == DDI_INTR_ALLOC_STRICT) { DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: " "DDI_INTR_ALLOC_STRICT flag is passed, " "return failure\n")); if (curr_nintrs == 0) i_ddi_intr_devi_fini(dip); else if (i_ddi_irm_supported(dip, type) != DDI_SUCCESS) (void) i_ddi_irm_modify(dip, curr_nintrs); return (DDI_EAGAIN); } count = navail - curr_nintrs; } /* Now allocate required number of interrupts */ bzero(&tmp_hdl, sizeof (ddi_intr_handle_impl_t)); tmp_hdl.ih_type = type; tmp_hdl.ih_inum = inum; tmp_hdl.ih_scratch1 = count; tmp_hdl.ih_scratch2 = (void *)(uintptr_t)behavior; tmp_hdl.ih_dip = dip; if (i_ddi_intr_ops(dip, dip, DDI_INTROP_ALLOC, &tmp_hdl, (void *)actualp) != DDI_SUCCESS) { DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: allocation " "failed\n")); i_ddi_intr_devi_fini(dip); return (*actualp ? DDI_EAGAIN : DDI_INTR_NOTFOUND); } if ((ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_GETPRI, &tmp_hdl, (void *)&pri)) != DDI_SUCCESS) { DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get priority " "failed\n")); goto fail; } DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: getting capability\n")); if ((ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_GETCAP, &tmp_hdl, (void *)&cap)) != DDI_SUCCESS) { DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get capability " "failed\n")); goto fail; } /* * Save current interrupt type, supported and current intr count. */ i_ddi_intr_set_current_type(dip, type); i_ddi_intr_set_supported_nintrs(dip, nintrs); i_ddi_intr_set_current_nintrs(dip, i_ddi_intr_get_current_nintrs(dip) + *actualp); /* Now, go and handle each "handle" */ for (i = inum; i < (inum + *actualp); i++) { hdlp = (ddi_intr_handle_impl_t *)kmem_zalloc( (sizeof (ddi_intr_handle_impl_t)), KM_SLEEP); rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL); h_array[i] = (struct __ddi_intr_handle *)hdlp; hdlp->ih_type = type; hdlp->ih_pri = pri; hdlp->ih_cap = cap; hdlp->ih_ver = DDI_INTR_VERSION; hdlp->ih_state = DDI_IHDL_STATE_ALLOC; hdlp->ih_dip = dip; hdlp->ih_inum = i; i_ddi_alloc_intr_phdl(hdlp); if (type & DDI_INTR_TYPE_FIXED) i_ddi_set_intr_handle(dip, hdlp->ih_inum, (ddi_intr_handle_t)hdlp); DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: hdlp = 0x%p\n", (void *)h_array[i])); } return (DDI_SUCCESS); fail: (void) i_ddi_intr_ops(tmp_hdl.ih_dip, tmp_hdl.ih_dip, DDI_INTROP_FREE, &tmp_hdl, NULL); i_ddi_intr_devi_fini(dip); return (ret); }
/* * XXX - right now we aren't attempting to fix anything that looks bad, * instead we just give up. */ void readBPB(int fd) { boot_sector_t ubpb; /* * The BPB is the first sector of the file system */ if (lseek64(fd, PartitionOffset, SEEK_SET) < 0) { mountSanityCheckFails(); perror(gettext("Cannot seek to start of disk partition")); (void) close(fd); exit(7); } if (Verbose) (void) fprintf(stderr, gettext("Reading BIOS parameter block\n")); if (read(fd, ubpb.buf, BPSEC) < BPSEC) { mountSanityCheckFails(); perror(gettext("Read BIOS parameter block")); (void) close(fd); exit(2); } if (ltohs(ubpb.mb.signature) != BOOTSECSIG) { mountSanityCheckFails(); (void) fprintf(stderr, gettext("Bad signature on BPB. Giving up.\n")); exit(2); } #ifdef _BIG_ENDIAN swap_pack_grabbpb(&TheBIOSParameterBlock, &(ubpb.bs)); #else (void) memcpy(&(TheBIOSParameterBlock.bpb), &(ubpb.bs.bs_front.bs_bpb), sizeof (TheBIOSParameterBlock.bpb)); (void) memcpy(&(TheBIOSParameterBlock.ebpb), &(ubpb.bs.bs_ebpb), sizeof (TheBIOSParameterBlock.ebpb)); #endif /* * In general, we would expect the bytes per sector to * equal 256 (BPSEC). I personally have yet to see a file * system where this isn't true but apparently some weird media * have different sector sizes. So we'll accept a couple of * other small multiples of 256 as valid sizes. */ if (TheBIOSParameterBlock.bpb.bytes_per_sector != BPSEC && TheBIOSParameterBlock.bpb.bytes_per_sector != 2 * BPSEC && TheBIOSParameterBlock.bpb.bytes_per_sector != 4 * BPSEC) { mountSanityCheckFails(); (void) fprintf(stderr, gettext("Bogus bytes per sector value. Giving up.\n")); exit(2); } if (!(ISP2(TheBIOSParameterBlock.bpb.sectors_per_cluster) && IN_RANGE(TheBIOSParameterBlock.bpb.sectors_per_cluster, 1, 128))) { mountSanityCheckFails(); (void) fprintf(stderr, gettext("Bogus sectors per cluster value. Giving up.\n")); (void) close(fd); exit(6); } if (TheBIOSParameterBlock.bpb.sectors_per_fat == 0) { #ifdef _BIG_ENDIAN swap_pack_grab32bpb(&TheBIOSParameterBlock, &(ubpb.bs)); #else (void) memcpy(&(TheBIOSParameterBlock.bpb32), &(ubpb.bs32.bs_bpb32), sizeof (TheBIOSParameterBlock.bpb32)); #endif IsFAT32 = 1; } if (!IsFAT32) { if ((TheBIOSParameterBlock.bpb.num_root_entries == 0) || ((TheBIOSParameterBlock.bpb.num_root_entries * sizeof (struct pcdir)) % TheBIOSParameterBlock.bpb.bytes_per_sector) != 0) { mountSanityCheckFails(); (void) fprintf(stderr, gettext("Bogus number of root entries. " "Giving up.\n")); exit(2); } } else { if (TheBIOSParameterBlock.bpb.num_root_entries != 0) { mountSanityCheckFails(); (void) fprintf(stderr, gettext("Bogus number of root entries. " "Giving up.\n")); exit(2); } } /* * In general, we would expect the number of FATs field to * equal 2. Our mkfs and Windows have this as a default * value. I suppose someone could override the default, * though, so we'll sort of arbitrarily accept any number * between 1 and 4 inclusive as reasonable values. * * XXX: Warn, but continue, if value is suspicious? (>2?) */ if (TheBIOSParameterBlock.bpb.num_fats > 4 || TheBIOSParameterBlock.bpb.num_fats < 1) { mountSanityCheckFails(); (void) fprintf(stderr, gettext("Bogus number of FATs. Giving up.\n")); exit(2); } computeFileAreaSize(); }
/* * Increase the file length * * IN: zp - znode of file to free data in. * end - new end-of-file * * RETURN: 0 on success, error code on failure */ static int zfs_extend(znode_t *zp, uint64_t end) { zfs_sb_t *zsb = ZTOZSB(zp); dmu_tx_t *tx; rl_t *rl; uint64_t newblksz; int error; /* * We will change zp_size, lock the whole file. */ rl = zfs_range_lock(zp, 0, UINT64_MAX, RL_WRITER); /* * Nothing to do if file already at desired length. */ if (end <= zp->z_size) { zfs_range_unlock(rl); return (0); } tx = dmu_tx_create(zsb->z_os); dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE); zfs_sa_upgrade_txholds(tx, zp); if (end > zp->z_blksz && (!ISP2(zp->z_blksz) || zp->z_blksz < zsb->z_max_blksz)) { /* * We are growing the file past the current block size. */ if (zp->z_blksz > ZTOZSB(zp)->z_max_blksz) { ASSERT(!ISP2(zp->z_blksz)); newblksz = MIN(end, SPA_MAXBLOCKSIZE); } else { newblksz = MIN(end, ZTOZSB(zp)->z_max_blksz); } dmu_tx_hold_write(tx, zp->z_id, 0, newblksz); } else { newblksz = 0; } error = dmu_tx_assign(tx, TXG_WAIT); if (error) { dmu_tx_abort(tx); zfs_range_unlock(rl); return (error); } if (newblksz) zfs_grow_blocksize(zp, newblksz, tx); zp->z_size = end; VERIFY(0 == sa_update(zp->z_sa_hdl, SA_ZPL_SIZE(ZTOZSB(zp)), &zp->z_size, sizeof (zp->z_size), tx)); zfs_range_unlock(rl); dmu_tx_commit(tx); return (0); }
int i; ASSERT3U(dn->dn_indblkshift, >=, 0); ASSERT3U(dn->dn_indblkshift, <=, SPA_MAXBLOCKSHIFT); if (dn->dn_datablkshift) { ASSERT3U(dn->dn_datablkshift, >=, SPA_MINBLOCKSHIFT); ASSERT3U(dn->dn_datablkshift, <=, SPA_MAXBLOCKSHIFT); ASSERT3U(1<<dn->dn_datablkshift, ==, dn->dn_datablksz); } ASSERT3U(dn->dn_nlevels, <=, 30); ASSERT3U(dn->dn_type, <=, DMU_OT_NUMTYPES); ASSERT3U(dn->dn_nblkptr, >=, 1); ASSERT3U(dn->dn_nblkptr, <=, DN_MAX_NBLKPTR); ASSERT3U(dn->dn_bonuslen, <=, DN_MAX_BONUSLEN); ASSERT3U(dn->dn_datablksz, ==, dn->dn_datablkszsec << SPA_MINBLOCKSHIFT); ASSERT3U(ISP2(dn->dn_datablksz), ==, dn->dn_datablkshift != 0); ASSERT3U((dn->dn_nblkptr - 1) * sizeof (blkptr_t) + dn->dn_bonuslen, <=, DN_MAX_BONUSLEN); for (i = 0; i < TXG_SIZE; i++) { ASSERT3U(dn->dn_next_nlevels[i], <=, dn->dn_nlevels); } } if (dn->dn_phys->dn_type != DMU_OT_NONE) ASSERT3U(dn->dn_phys->dn_nlevels, <=, dn->dn_nlevels); ASSERT(DMU_OBJECT_IS_SPECIAL(dn->dn_object) || dn->dn_dbuf != NULL); if (dn->dn_dbuf != NULL) { ASSERT3P(dn->dn_phys, ==, (dnode_phys_t *)dn->dn_dbuf->db.db_data + (dn->dn_object % (dn->dn_dbuf->db.db_size >> DNODE_SHIFT))); } if (drop_struct_lock)
static int smmap_common(caddr_t *addrp, size_t len, int prot, int flags, struct file *fp, offset_t pos) { struct vnode *vp; struct as *as = curproc->p_as; uint_t uprot, maxprot, type; int error; int in_crit = 0; if ((flags & ~(MAP_SHARED | MAP_PRIVATE | MAP_FIXED | _MAP_NEW | _MAP_LOW32 | MAP_NORESERVE | MAP_ANON | MAP_ALIGN | MAP_TEXT | MAP_INITDATA)) != 0) { /* | MAP_RENAME */ /* not implemented, let user know */ return (EINVAL); } if ((flags & MAP_TEXT) && !(prot & PROT_EXEC)) { return (EINVAL); } if ((flags & (MAP_TEXT | MAP_INITDATA)) == (MAP_TEXT | MAP_INITDATA)) { return (EINVAL); } #if defined(__sparc) /* * See if this is an "old mmap call". If so, remember this * fact and convert the flags value given to mmap to indicate * the specified address in the system call must be used. * _MAP_NEW is turned set by all new uses of mmap. */ if ((flags & _MAP_NEW) == 0) flags |= MAP_FIXED; #endif flags &= ~_MAP_NEW; type = flags & MAP_TYPE; if (type != MAP_PRIVATE && type != MAP_SHARED) return (EINVAL); if (flags & MAP_ALIGN) { if (flags & MAP_FIXED) return (EINVAL); /* alignment needs to be a power of 2 >= page size */ if (((uintptr_t)*addrp < PAGESIZE && (uintptr_t)*addrp != 0) || !ISP2((uintptr_t)*addrp)) return (EINVAL); } /* * Check for bad lengths and file position. * We let the VOP_MAP routine check for negative lengths * since on some vnode types this might be appropriate. */ if (len == 0 || (pos & (u_offset_t)PAGEOFFSET) != 0) return (EINVAL); maxprot = PROT_ALL; /* start out allowing all accesses */ uprot = prot | PROT_USER; if (fp == NULL) { ASSERT(flags & MAP_ANON); /* discard lwpchan mappings, like munmap() */ if ((flags & MAP_FIXED) && curproc->p_lcp != NULL) lwpchan_delete_mapping(curproc, *addrp, *addrp + len); as_rangelock(as); error = zmap(as, addrp, len, uprot, flags, pos); as_rangeunlock(as); /* * Tell machine specific code that lwp has mapped shared memory */ if (error == 0 && (flags & MAP_SHARED)) { /* EMPTY */ LWP_MMODEL_SHARED_AS(*addrp, len); } return (error); } else if ((flags & MAP_ANON) != 0) return (EINVAL); vp = fp->f_vnode; /* Can't execute code from "noexec" mounted filesystem. */ if ((vp->v_vfsp->vfs_flag & VFS_NOEXEC) != 0) maxprot &= ~PROT_EXEC; /* * These checks were added as part of large files. * * Return ENXIO if the initial position is negative; return EOVERFLOW * if (offset + len) would overflow the maximum allowed offset for the * type of file descriptor being used. */ if (vp->v_type == VREG) { if (pos < 0) return (ENXIO); if ((offset_t)len > (OFFSET_MAX(fp) - pos)) return (EOVERFLOW); } if (type == MAP_SHARED && (fp->f_flag & FWRITE) == 0) { /* no write access allowed */ maxprot &= ~PROT_WRITE; } /* * XXX - Do we also adjust maxprot based on protections * of the vnode? E.g. if no execute permission is given * on the vnode for the current user, maxprot probably * should disallow PROT_EXEC also? This is different * from the write access as this would be a per vnode * test as opposed to a per fd test for writability. */ /* * Verify that the specified protections are not greater than * the maximum allowable protections. Also test to make sure * that the file descriptor does allows for read access since * "write only" mappings are hard to do since normally we do * the read from the file before the page can be written. */ if (((maxprot & uprot) != uprot) || (fp->f_flag & FREAD) == 0) return (EACCES); /* * If the user specified an address, do some simple checks here */ if ((flags & MAP_FIXED) != 0) { caddr_t userlimit; /* * Use the user address. First verify that * the address to be used is page aligned. * Then make some simple bounds checks. */ if (((uintptr_t)*addrp & PAGEOFFSET) != 0) return (EINVAL); userlimit = flags & _MAP_LOW32 ? (caddr_t)USERLIMIT32 : as->a_userlimit; switch (valid_usr_range(*addrp, len, uprot, as, userlimit)) { case RANGE_OKAY: break; case RANGE_BADPROT: return (ENOTSUP); case RANGE_BADADDR: default: return (ENOMEM); } } if ((prot & (PROT_READ | PROT_WRITE | PROT_EXEC)) && nbl_need_check(vp)) { int svmand; nbl_op_t nop; nbl_start_crit(vp, RW_READER); in_crit = 1; error = nbl_svmand(vp, fp->f_cred, &svmand); if (error != 0) goto done; if ((prot & PROT_WRITE) && (type == MAP_SHARED)) { if (prot & (PROT_READ | PROT_EXEC)) { nop = NBL_READWRITE; } else { nop = NBL_WRITE; } } else { nop = NBL_READ; } if (nbl_conflict(vp, nop, 0, LONG_MAX, svmand, NULL)) { error = EACCES; goto done; } } /* discard lwpchan mappings, like munmap() */ if ((flags & MAP_FIXED) && curproc->p_lcp != NULL) lwpchan_delete_mapping(curproc, *addrp, *addrp + len); /* * Ok, now let the vnode map routine do its thing to set things up. */ error = VOP_MAP(vp, pos, as, addrp, len, uprot, maxprot, flags, fp->f_cred, NULL); if (error == 0) { /* * Tell machine specific code that lwp has mapped shared memory */ if (flags & MAP_SHARED) { /* EMPTY */ LWP_MMODEL_SHARED_AS(*addrp, len); } if (vp->v_type == VREG && (flags & (MAP_TEXT | MAP_INITDATA)) != 0) { /* * Mark this as an executable vnode */ mutex_enter(&vp->v_lock); vp->v_flag |= VVMEXEC; mutex_exit(&vp->v_lock); } } done: if (in_crit) nbl_end_crit(vp); return (error); }