예제 #1
0
long 
SHM_MallocTest(void)
{
	int order;

	/*
 	* Check the static info array. Things will blow up terribly if it's
 	* incorrect. This is a late "compile time" check.....
 	*/

	for (order = 0; BLOCKSIZE(order); order++) 
	{
		if ((NBLOCKS(order) * BLOCKSIZE(order) + 
			sizeof(struct PageDescriptor)) > AREASIZE(order)) 
		{
			printf("Cannot use %d bytes out of %d in order = %d block mallocs\n",
			       (int) (NBLOCKS(order) * BLOCKSIZE(order) +
				      sizeof(struct PageDescriptor)),
			        (int) AREASIZE(order),
			       BLOCKSIZE(order));
			printf("ERROR in SHM\n");
		}
	}

	return 0;
}
예제 #2
0
파일: rdwr_efi.c 프로젝트: ryao/openzfs
int
efi_alloc_and_init(int fd, uint32_t nparts, struct dk_gpt **vtoc)
{
	diskaddr_t	capacity;
	uint_t		lbsize;
	uint_t		nblocks;
	size_t		length;
	struct dk_gpt	*vptr;
	struct uuid	uuid;

	if (read_disk_info(fd, &capacity, &lbsize) != 0) {
		if (efi_debug)
			(void) fprintf(stderr,
			    "couldn't read disk information\n");
		return (-1);
	}

	nblocks = NBLOCKS(nparts, lbsize);
	if ((nblocks * lbsize) < EFI_MIN_ARRAY_SIZE + lbsize) {
		/* 16K plus one block for the GPT */
		nblocks = EFI_MIN_ARRAY_SIZE / lbsize + 1;
	}

	if (nparts > MAX_PARTS) {
		if (efi_debug) {
			(void) fprintf(stderr,
			"the maximum number of partitions supported is %lu\n",
			    MAX_PARTS);
		}
		return (-1);
	}

	length = sizeof (struct dk_gpt) +
	    sizeof (struct dk_part) * (nparts - 1);

	if ((*vtoc = calloc(length, 1)) == NULL)
		return (-1);

	vptr = *vtoc;

	vptr->efi_version = EFI_VERSION_CURRENT;
	vptr->efi_lbasize = lbsize;
	vptr->efi_nparts = nparts;
	/*
	 * add one block here for the PMBR; on disks with a 512 byte
	 * block size and 128 or fewer partitions, efi_first_u_lba
	 * should work out to "34"
	 */
	vptr->efi_first_u_lba = nblocks + 1;
	vptr->efi_last_lba = capacity - 1;
	vptr->efi_altern_lba = capacity -1;
	vptr->efi_last_u_lba = vptr->efi_last_lba - nblocks;

	(void) uuid_generate((uchar_t *)&uuid);
	UUID_LE_CONVERT(vptr->efi_disk_uguid, uuid);
	return (0);
}
예제 #3
0
파일: kmalloc.c 프로젝트: rickcaudill/Pyro
void init_kmalloc( void )
{
	int order;
	
	memset( kmalloc_cache, 0, sizeof( kmalloc_cache ) );

/*
 * Check the static info array. Things will blow up terribly if it's
 * incorrect. This is a late "compile time" check.....
 */
	for ( order = 0; BLOCKSIZE( order ); order++ )
	{
		if ( ( NBLOCKS( order ) * BLOCKSIZE( order ) + sizeof( struct page_descriptor ) ) > AREASIZE( order ) )
		{
			printk( "Cannot use %d bytes out of %d in order = %d block mallocs\n", ( int )( NBLOCKS( order ) * BLOCKSIZE( order ) + sizeof( struct page_descriptor ) ), ( int )AREASIZE( order ), BLOCKSIZE( order ) );
			panic( "This only happens if someone messes with kmalloc" );
		}
	}
//      return start_mem;
}
예제 #4
0
long kmalloc_init (long start_mem,long end_mem)
{
	int order;

/* 
 * Check the static info array. Things will blow up terribly if it's
 * incorrect. This is a late "compile time" check.....
 */
for (order = 0;BLOCKSIZE(order);order++)
    {
    if ((NBLOCKS (order)*BLOCKSIZE(order) + sizeof (struct page_descriptor)) >
        PAGE_SIZE) 
        {
        printk ("Cannot use %d bytes out of %d in order = %d block mallocs\n",
                NBLOCKS (order) * BLOCKSIZE(order) + 
                        sizeof (struct page_descriptor),
                (int) PAGE_SIZE,
                BLOCKSIZE (order));
        panic ("This only happens if someone messes with kmalloc");
        }
    }
return start_mem;
}
예제 #5
0
void kfree_s (void *ptr,int size)
{
unsigned long flags;
int order;
register struct block_header *p=((struct block_header *)ptr) -1;
struct page_descriptor *page,*pg2;

page = PAGE_DESC (p);
order = page->order;
if ((order < 0) || 
    (order > sizeof (sizes)/sizeof (sizes[0])) ||
    (((long)(page->next)) & ~PAGE_MASK) ||
    (p->bh_flags != MF_USED))
    {
    printk ("kfree of non-kmalloced memory: %p, next= %p, order=%d\n",
                p, page->next, page->order);
    return;
    }
if (size &&
    size != p->bh_length)
    {
    printk ("Trying to free pointer at %p with wrong size: %d instead of %lu.\n",
        p,size,p->bh_length);
    return;
    }
size = p->bh_length;
p->bh_flags = MF_FREE; /* As of now this block is officially free */
save_flags(flags);
cli ();
p->bh_next = page->firstfree;
page->firstfree = p;
page->nfree ++;

if (page->nfree == 1)
   { /* Page went from full to one free block: put it on the freelist */
   if (page->next)
        {
        printk ("Page %p already on freelist dazed and confused....\n", page);
        }
   else
        {
        page->next = sizes[order].firstfree;
        sizes[order].firstfree = page;
        }
   }

/* If page is completely free, free it */
if (page->nfree == NBLOCKS (page->order))
    {
#if 0
    printk ("Freeing page %08x.\n", (long)page);
#endif
    if (sizes[order].firstfree == page)
        {
        sizes[order].firstfree = page->next;
        }
    else
        {
        for (pg2=sizes[order].firstfree;
                (pg2 != NULL) && (pg2->next != page);
                        pg2=pg2->next)
            /* Nothing */;
        if (pg2 != NULL)
            pg2->next = page->next;
        else
            printk ("Ooops. page %p doesn't show on freelist.\n", page);
        }
    free_page ((long)page);
    }
restore_flags(flags);

sizes[order].nfrees++;      /* Noncritical (monitoring) admin stuff */
sizes[order].nbytesmalloced -= size;
}
예제 #6
0
void * kmalloc (size_t size, int priority)
{
	unsigned long flags;
	int order,tries,i,sz;
	struct block_header *p;
	struct page_descriptor *page;

/* Sanity check... */
	if (intr_count && priority != GFP_ATOMIC) {
		static int count = 0;
		if (++count < 5) {
			printk("kmalloc called nonatomically from interrupt %08lx\n",
				((unsigned long *)&size)[-1]);
			priority = GFP_ATOMIC;
		}
	}
if (size > MAX_KMALLOC_K * 1024) 
     {
     printk ("kmalloc: I refuse to allocate %d bytes (for now max = %d).\n",
                size,MAX_KMALLOC_K*1024);
     return (NULL);
     }

order = get_order (size);
if (order < 0)
    {
    printk ("kmalloc of too large a block (%d bytes).\n",size);
    return (NULL);
    }

save_flags(flags);

/* It seems VERY unlikely to me that it would be possible that this 
   loop will get executed more than once. */
tries = MAX_GET_FREE_PAGE_TRIES; 
while (tries --)
    {
    /* Try to allocate a "recently" freed memory block */
    cli ();
    if ((page = sizes[order].firstfree) &&
        (p    =  page->firstfree))
        {
        if (p->bh_flags == MF_FREE)
            {
            page->firstfree = p->bh_next;
            page->nfree--;
            if (!page->nfree)
                {
                sizes[order].firstfree = page->next;
                page->next = NULL;
                }
            restore_flags(flags);

            sizes [order].nmallocs++;
            sizes [order].nbytesmalloced += size;
            p->bh_flags =  MF_USED; /* As of now this block is officially in use */
            p->bh_length = size;
            return p+1; /* Pointer arithmetic: increments past header */
            }
        printk ("Problem: block on freelist at %08lx isn't free.\n",(long)p);
        return (NULL);
        }
    restore_flags(flags);


    /* Now we're in trouble: We need to get a new free page..... */

    sz = BLOCKSIZE(order); /* sz is the size of the blocks we're dealing with */

    /* This can be done with ints on: This is private to this invocation */
    page = (struct page_descriptor *) __get_free_page (priority & GFP_LEVEL_MASK);
    if (!page) {
        static unsigned long last = 0;
        if (last + 10*HZ < jiffies) {
        	last = jiffies;
	        printk ("Couldn't get a free page.....\n");
	}
        return NULL;
    }
#if 0
    printk ("Got page %08x to use for %d byte mallocs....",(long)page,sz);
#endif
    sizes[order].npages++;

    /* Loop for all but last block: */
    for (i=NBLOCKS(order),p=BH (page+1);i > 1;i--,p=p->bh_next) 
        {
        p->bh_flags = MF_FREE;
        p->bh_next = BH ( ((long)p)+sz);
        }
    /* Last block: */
    p->bh_flags = MF_FREE;
    p->bh_next = NULL;

    page->order = order;
    page->nfree = NBLOCKS(order); 
    page->firstfree = BH(page+1);
#if 0
    printk ("%d blocks per page\n",page->nfree);
#endif
    /* Now we're going to muck with the "global" freelist for this size:
       this should be uniterruptible */
    cli ();
    /* 
     * sizes[order].firstfree used to be NULL, otherwise we wouldn't be
     * here, but you never know.... 
     */
    page->next = sizes[order].firstfree;
    sizes[order].firstfree = page;
    restore_flags(flags);
    }

/* Pray that printk won't cause this to happen again :-) */

printk ("Hey. This is very funny. I tried %d times to allocate a whole\n"
        "new page for an object only %d bytes long, but some other process\n"
        "beat me to actually allocating it. Also note that this 'error'\n"
        "message is soooo very long to catch your attention. I'd appreciate\n"
        "it if you'd be so kind as to report what conditions caused this to\n"
        "the author of this kmalloc: [email protected].\n"
        "(Executive summary: This can't happen)\n", 
                MAX_GET_FREE_PAGE_TRIES,
                size);
return NULL;
}
예제 #7
0
파일: rdwr_efi.c 프로젝트: ryao/openzfs
static int
efi_read(int fd, struct dk_gpt *vtoc)
{
	int			i, j;
	int			label_len;
	int			rval = 0;
	int			md_flag = 0;
	int			vdc_flag = 0;
	struct dk_minfo		disk_info;
	dk_efi_t		dk_ioc;
	efi_gpt_t		*efi;
	efi_gpe_t		*efi_parts;
	struct dk_cinfo		dki_info;
	uint32_t		user_length;
	boolean_t		legacy_label = B_FALSE;

	/*
	 * get the partition number for this file descriptor.
	 */
	if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) {
		if (efi_debug) {
			(void) fprintf(stderr, "DKIOCINFO errno 0x%x\n", errno);
		}
		switch (errno) {
		case EIO:
			return (VT_EIO);
		case EINVAL:
			return (VT_EINVAL);
		default:
			return (VT_ERROR);
		}
	}
	if ((strncmp(dki_info.dki_cname, "pseudo", 7) == 0) &&
	    (strncmp(dki_info.dki_dname, "md", 3) == 0)) {
		md_flag++;
	} else if ((strncmp(dki_info.dki_cname, "vdc", 4) == 0) &&
	    (strncmp(dki_info.dki_dname, "vdc", 4) == 0)) {
		/*
		 * The controller and drive name "vdc" (virtual disk client)
		 * indicates a LDoms virtual disk.
		 */
		vdc_flag++;
	}

	/* get the LBA size */
	if (ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info) == -1) {
		if (efi_debug) {
			(void) fprintf(stderr,
			    "assuming LBA 512 bytes %d\n",
			    errno);
		}
		disk_info.dki_lbsize = DEV_BSIZE;
	}
	if (disk_info.dki_lbsize == 0) {
		if (efi_debug) {
			(void) fprintf(stderr,
			    "efi_read: assuming LBA 512 bytes\n");
		}
		disk_info.dki_lbsize = DEV_BSIZE;
	}
	/*
	 * Read the EFI GPT to figure out how many partitions we need
	 * to deal with.
	 */
	dk_ioc.dki_lba = 1;
	if (NBLOCKS(vtoc->efi_nparts, disk_info.dki_lbsize) < 34) {
		label_len = EFI_MIN_ARRAY_SIZE + disk_info.dki_lbsize;
	} else {
		label_len = vtoc->efi_nparts * (int) sizeof (efi_gpe_t) +
		    disk_info.dki_lbsize;
		if (label_len % disk_info.dki_lbsize) {
			/* pad to physical sector size */
			label_len += disk_info.dki_lbsize;
			label_len &= ~(disk_info.dki_lbsize - 1);
		}
	}

	if ((dk_ioc.dki_data = calloc(label_len, 1)) == NULL)
		return (VT_ERROR);

	dk_ioc.dki_length = disk_info.dki_lbsize;
	user_length = vtoc->efi_nparts;
	efi = dk_ioc.dki_data;
	if (md_flag) {
		dk_ioc.dki_length = label_len;
		if (efi_ioctl(fd, DKIOCGETEFI, &dk_ioc) == -1) {
			switch (errno) {
			case EIO:
				return (VT_EIO);
			default:
				return (VT_ERROR);
			}
		}
	} else if ((rval = check_label(fd, &dk_ioc)) == VT_EINVAL) {
		/*
		 * No valid label here; try the alternate. Note that here
		 * we just read GPT header and save it into dk_ioc.data,
		 * Later, we will read GUID partition entry array if we
		 * can get valid GPT header.
		 */

		/*
		 * This is a workaround for legacy systems. In the past, the
		 * last sector of SCSI disk was invisible on x86 platform. At
		 * that time, backup label was saved on the next to the last
		 * sector. It is possible for users to move a disk from previous
		 * solaris system to present system. Here, we attempt to search
		 * legacy backup EFI label first.
		 */
		dk_ioc.dki_lba = disk_info.dki_capacity - 2;
		dk_ioc.dki_length = disk_info.dki_lbsize;
		rval = check_label(fd, &dk_ioc);
		if (rval == VT_EINVAL) {
			/*
			 * we didn't find legacy backup EFI label, try to
			 * search backup EFI label in the last block.
			 */
			dk_ioc.dki_lba = disk_info.dki_capacity - 1;
			dk_ioc.dki_length = disk_info.dki_lbsize;
			rval = check_label(fd, &dk_ioc);
			if (rval == 0) {
				legacy_label = B_TRUE;
				if (efi_debug)
					(void) fprintf(stderr,
					    "efi_read: primary label corrupt; "
					    "using EFI backup label located on"
					    " the last block\n");
			}
		} else {
			if ((efi_debug) && (rval == 0))
				(void) fprintf(stderr, "efi_read: primary label"
				    " corrupt; using legacy EFI backup label "
				    " located on the next to last block\n");
		}

		if (rval == 0) {
			dk_ioc.dki_lba = LE_64(efi->efi_gpt_PartitionEntryLBA);
			vtoc->efi_flags |= EFI_GPT_PRIMARY_CORRUPT;
			vtoc->efi_nparts =
			    LE_32(efi->efi_gpt_NumberOfPartitionEntries);
			/*
			 * Partition tables are between backup GPT header
			 * table and ParitionEntryLBA (the starting LBA of
			 * the GUID partition entries array). Now that we
			 * already got valid GPT header and saved it in
			 * dk_ioc.dki_data, we try to get GUID partition
			 * entry array here.
			 */
			/* LINTED */
			dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data
			    + disk_info.dki_lbsize);
			if (legacy_label)
				dk_ioc.dki_length = disk_info.dki_capacity - 1 -
				    dk_ioc.dki_lba;
			else
				dk_ioc.dki_length = disk_info.dki_capacity - 2 -
				    dk_ioc.dki_lba;
			dk_ioc.dki_length *= disk_info.dki_lbsize;
			if (dk_ioc.dki_length >
			    ((len_t)label_len - sizeof (*dk_ioc.dki_data))) {
				rval = VT_EINVAL;
			} else {
				/*
				 * read GUID partition entry array
				 */
				rval = efi_ioctl(fd, DKIOCGETEFI, &dk_ioc);
			}
		}

	} else if (rval == 0) {

		dk_ioc.dki_lba = LE_64(efi->efi_gpt_PartitionEntryLBA);
		/* LINTED */
		dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data
		    + disk_info.dki_lbsize);
		dk_ioc.dki_length = label_len - disk_info.dki_lbsize;
		rval = efi_ioctl(fd, DKIOCGETEFI, &dk_ioc);

	} else if (vdc_flag && rval == VT_ERROR && errno == EINVAL) {
		/*
		 * When the device is a LDoms virtual disk, the DKIOCGETEFI
		 * ioctl can fail with EINVAL if the virtual disk backend
		 * is a ZFS volume serviced by a domain running an old version
		 * of Solaris. This is because the DKIOCGETEFI ioctl was
		 * initially incorrectly implemented for a ZFS volume and it
		 * expected the GPT and GPE to be retrieved with a single ioctl.
		 * So we try to read the GPT and the GPE using that old style
		 * ioctl.
		 */
		dk_ioc.dki_lba = 1;
		dk_ioc.dki_length = label_len;
		rval = check_label(fd, &dk_ioc);
	}

	if (rval < 0) {
		free(efi);
		return (rval);
	}

	/* LINTED -- always longlong aligned */
	efi_parts = (efi_gpe_t *)(((char *)efi) + disk_info.dki_lbsize);

	/*
	 * Assemble this into a "dk_gpt" struct for easier
	 * digestibility by applications.
	 */
	vtoc->efi_version = LE_32(efi->efi_gpt_Revision);
	vtoc->efi_nparts = LE_32(efi->efi_gpt_NumberOfPartitionEntries);
	vtoc->efi_part_size = LE_32(efi->efi_gpt_SizeOfPartitionEntry);
	vtoc->efi_lbasize = disk_info.dki_lbsize;
	vtoc->efi_last_lba = disk_info.dki_capacity - 1;
	vtoc->efi_first_u_lba = LE_64(efi->efi_gpt_FirstUsableLBA);
	vtoc->efi_last_u_lba = LE_64(efi->efi_gpt_LastUsableLBA);
	vtoc->efi_altern_lba = LE_64(efi->efi_gpt_AlternateLBA);
	UUID_LE_CONVERT(vtoc->efi_disk_uguid, efi->efi_gpt_DiskGUID);

	/*
	 * If the array the user passed in is too small, set the length
	 * to what it needs to be and return
	 */
	if (user_length < vtoc->efi_nparts) {
		return (VT_EINVAL);
	}

	for (i = 0; i < vtoc->efi_nparts; i++) {

		UUID_LE_CONVERT(vtoc->efi_parts[i].p_guid,
		    efi_parts[i].efi_gpe_PartitionTypeGUID);

		for (j = 0;
		    j < sizeof (conversion_array)
		    / sizeof (struct uuid_to_ptag); j++) {

			if (bcmp(&vtoc->efi_parts[i].p_guid,
			    &conversion_array[j].uuid,
			    sizeof (struct uuid)) == 0) {
				vtoc->efi_parts[i].p_tag = j;
				break;
			}
		}
		if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED)
			continue;
		vtoc->efi_parts[i].p_flag =
		    LE_16(efi_parts[i].efi_gpe_Attributes.PartitionAttrs);
		vtoc->efi_parts[i].p_start =
		    LE_64(efi_parts[i].efi_gpe_StartingLBA);
		vtoc->efi_parts[i].p_size =
		    LE_64(efi_parts[i].efi_gpe_EndingLBA) -
		    vtoc->efi_parts[i].p_start + 1;
		for (j = 0; j < EFI_PART_NAME_LEN; j++) {
			vtoc->efi_parts[i].p_name[j] =
			    (uchar_t)LE_16(
			    efi_parts[i].efi_gpe_PartitionName[j]);
		}

		UUID_LE_CONVERT(vtoc->efi_parts[i].p_uguid,
		    efi_parts[i].efi_gpe_UniquePartitionGUID);
	}
	free(efi);

	return (dki_info.dki_partition);
}
예제 #8
0
파일: db.c 프로젝트: jflatow/jfdb
    if (blockSize <= gap->size) {
      // we found a big enough gap to hold the value
      // adjust the gap and return a block beginning where it was
      block = gap->block;
      gap->block += blockSize / JFDB_BLOCK_SIZE;
      gap->size -= blockSize;
      return (JFDB_Region) {
        .block = block,
        .size = size
      };
    }
  }

  // otherwise append to next block at the end of file
  // return a region no matter what, but db may have error
  block = NBLOCKS(cp->lengthVals);
  cp->lengthVals = block * JFDB_BLOCK_SIZE + size;
  if (ftruncate(db->vmap.fd, cp->lengthVals))
    JFDB_set_error(db, JFDB_EFILE, "failed to truncate vals");
  JFDB_mmap_file(db, JFDB_VALS, cp->lengthVals, 2);
  return (JFDB_Region) {
    .block = block,
    .size = size
  };
}

static void JFDB_add_to_free_list(JFDB *db, JFDB_Region region) {
  uint32_t lower = region.block;
  uint32_t upper = region.block + NBLOCKS(region.size);
  if (lower < db->freeList.lower)
    db->freeList.lower = lower;
예제 #9
0
파일: rdwr_efi.c 프로젝트: andreiw/polaris
static int
efi_read(int fd, struct dk_gpt *vtoc)
{
	int			i, j;
	int			label_len;
	int			rval = 0;
	int			md_flag = 0;
	struct dk_minfo		disk_info;
	dk_efi_t		dk_ioc;
	efi_gpt_t		*efi;
	efi_gpe_t		*efi_parts;
	struct dk_cinfo		dki_info;
	uint32_t		user_length;

	/*
	 * get the partition number for this file descriptor.
	 */
	if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) {
		if (efi_debug)
		    (void) fprintf(stderr, "DKIOCINFO errno 0x%x\n", errno);
		switch (errno) {
		case EIO:
			return (VT_EIO);
		case EINVAL:
			return (VT_EINVAL);
		default:
			return (VT_ERROR);
		}
	}
	if ((strncmp(dki_info.dki_cname, "pseudo", 7) == 0) &&
	    (strncmp(dki_info.dki_dname, "md", 3) == 0)) {
		md_flag++;
	}
	/* get the LBA size */
	if (ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info) == -1) {
		if (efi_debug) {
			(void) fprintf(stderr,
			    "assuming LBA 512 bytes %d\n",
			    errno);
		}
		disk_info.dki_lbsize = DEV_BSIZE;
	}
	if (disk_info.dki_lbsize == 0) {
		if (efi_debug) {
			(void) fprintf(stderr,
			    "efi_read: assuming LBA 512 bytes\n");
		}
		disk_info.dki_lbsize = DEV_BSIZE;
	}
	/*
	 * Read the EFI GPT to figure out how many partitions we need
	 * to deal with.
	 */
	dk_ioc.dki_lba = 1;
	if (NBLOCKS(vtoc->efi_nparts, disk_info.dki_lbsize) < 34) {
		label_len = EFI_MIN_ARRAY_SIZE + disk_info.dki_lbsize;
	} else {
		label_len = vtoc->efi_nparts * (int) sizeof (efi_gpe_t) +
				    disk_info.dki_lbsize;
		if (label_len % disk_info.dki_lbsize) {
			/* pad to physical sector size */
			label_len += disk_info.dki_lbsize;
			label_len &= ~(disk_info.dki_lbsize - 1);
		}
	}

	if ((dk_ioc.dki_data = calloc(label_len, 1)) == NULL)
		return (VT_ERROR);

	dk_ioc.dki_length = label_len;
	user_length = vtoc->efi_nparts;
	efi = dk_ioc.dki_data;
	if (md_flag) {
		if (efi_ioctl(fd, DKIOCGETEFI, &dk_ioc) == -1) {
			switch (errno) {
			case EIO:
				return (VT_EIO);
			default:
				return (VT_ERROR);
			}
		}
	} else if ((rval = check_label(fd, &dk_ioc)) == VT_EINVAL) {
		/* no valid label here; try the alternate */
		dk_ioc.dki_lba = disk_info.dki_capacity - 1;
		dk_ioc.dki_length = disk_info.dki_lbsize;
		rval = check_label(fd, &dk_ioc);
		if (rval != 0) {
			/*
			 * This is a workaround for legacy systems.
			 *
			 * In the past, the last sector of SCSI disk was
			 * invisible on x86 platform. At that time, backup
			 * label was saved on the next to the last sector.
			 * It is possible for users to move a disk from
			 * previous solaris system to present system.
			 */
			dk_ioc.dki_lba = disk_info.dki_capacity - 2;
			dk_ioc.dki_length = disk_info.dki_lbsize;
			rval = check_label(fd, &dk_ioc);
			if (efi_debug && (rval == 0)) {
				(void) fprintf(stderr,
				    "efi_read: primary label corrupt; "
				    "using legacy EFI backup label\n");
			}
		}

		if (rval == 0) {
			if (efi_debug) {
				(void) fprintf(stderr,
				    "efi_read: primary label corrupt; "
				    "using backup\n");
			}
			dk_ioc.dki_lba = LE_64(efi->efi_gpt_PartitionEntryLBA);
			vtoc->efi_flags |= EFI_GPT_PRIMARY_CORRUPT;
			vtoc->efi_nparts =
			    LE_32(efi->efi_gpt_NumberOfPartitionEntries);
			/*
			 * partitions are between last usable LBA and
			 * backup partition header
			 */
			dk_ioc.dki_data++;
			dk_ioc.dki_length = disk_info.dki_capacity -
						    dk_ioc.dki_lba - 1;
			dk_ioc.dki_length *= disk_info.dki_lbsize;
			if (dk_ioc.dki_length > (len_t)label_len) {
				rval = VT_EINVAL;
			} else {
				rval = efi_ioctl(fd, DKIOCGETEFI, &dk_ioc);
			}
		}
	}
	if (rval < 0) {
		free(efi);
		return (rval);
	}

	/* partitions start in the next block */
	/* LINTED -- always longlong aligned */
	efi_parts = (efi_gpe_t *)(((char *)efi) + disk_info.dki_lbsize);

	/*
	 * Assemble this into a "dk_gpt" struct for easier
	 * digestibility by applications.
	 */
	vtoc->efi_version = LE_32(efi->efi_gpt_Revision);
	vtoc->efi_nparts = LE_32(efi->efi_gpt_NumberOfPartitionEntries);
	vtoc->efi_part_size = LE_32(efi->efi_gpt_SizeOfPartitionEntry);
	vtoc->efi_lbasize = disk_info.dki_lbsize;
	vtoc->efi_last_lba = disk_info.dki_capacity - 1;
	vtoc->efi_first_u_lba = LE_64(efi->efi_gpt_FirstUsableLBA);
	vtoc->efi_last_u_lba = LE_64(efi->efi_gpt_LastUsableLBA);
	UUID_LE_CONVERT(vtoc->efi_disk_uguid, efi->efi_gpt_DiskGUID);

	/*
	 * If the array the user passed in is too small, set the length
	 * to what it needs to be and return
	 */
	if (user_length < vtoc->efi_nparts) {
		return (VT_EINVAL);
	}

	for (i = 0; i < vtoc->efi_nparts; i++) {

	    UUID_LE_CONVERT(vtoc->efi_parts[i].p_guid,
		efi_parts[i].efi_gpe_PartitionTypeGUID);

	    for (j = 0;
		j < sizeof (conversion_array) / sizeof (struct uuid_to_ptag);
		j++) {

		    if (bcmp(&vtoc->efi_parts[i].p_guid,
			&conversion_array[j].uuid,
			sizeof (struct uuid)) == 0) {
			    vtoc->efi_parts[i].p_tag = j;
			    break;
		    }
	    }
	    if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED)
		    continue;
	    vtoc->efi_parts[i].p_flag =
		LE_16(efi_parts[i].efi_gpe_Attributes.PartitionAttrs);
	    vtoc->efi_parts[i].p_start =
		LE_64(efi_parts[i].efi_gpe_StartingLBA);
	    vtoc->efi_parts[i].p_size =
		LE_64(efi_parts[i].efi_gpe_EndingLBA) -
		    vtoc->efi_parts[i].p_start + 1;
	    for (j = 0; j < EFI_PART_NAME_LEN; j++) {
		vtoc->efi_parts[i].p_name[j] =
		    (uchar_t)LE_16(efi_parts[i].efi_gpe_PartitionName[j]);
	    }

	    UUID_LE_CONVERT(vtoc->efi_parts[i].p_uguid,
		efi_parts[i].efi_gpe_UniquePartitionGUID);
	}
	free(efi);

	return (dki_info.dki_partition);
}