Exemple #1
0
/*
 * 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);
}
Exemple #3
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);
}
Exemple #4
0
int
zvol_check_volblocksize(uint64_t volblocksize)
{
	if (volblocksize < SPA_MINBLOCKSIZE ||
	    volblocksize > SPA_MAXBLOCKSIZE ||
	    !ISP2(volblocksize))
		return (EDOM);

	return (0);
}
Exemple #5
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;
}
Exemple #6
0
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);
}
Exemple #7
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;
}
Exemple #8
0
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;
}
Exemple #9
0
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);
}
Exemple #10
0
/*
 * 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;
}
Exemple #11
0
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);
	}
}
Exemple #12
0
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);
}
Exemple #13
0
/* 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;
}
Exemple #14
0
/*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));
}
Exemple #15
0
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;
	}
}
Exemple #16
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);
}
Exemple #17
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);
}
Exemple #18
0
/*
 *  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();
}
Exemple #19
0
/*
 * 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);
}
Exemple #20
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)
Exemple #21
0
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);
}