示例#1
0
文件: zbc.c 项目: mmilburn/libzbc
/**
 * zbc_pwrite - write to a ZBC device
 * @dev:                (IN) ZBC device handle to write to
 * @zone:               (IN) The zone to write to
 * @buf:                (IN) Caller supplied buffer to write from
 * @lba_count:          (IN) Number of LBAs to write
 * @lba_ofst:           (IN) LBA Offset where to start writing in @zone
 *
 * This an the equivalent to pwrite(2) that operates on a ZBC device handle,
 * and uses LBA addressing for the buffer length. It attempts to writes in the
 * zone (@zone) at the offset (@lba_ofst).
 * The write pointer is updated in case of a succesful call.
 *
 * All errors returned by write(2) can be returned. On success, the number of
 * logical blocks written is returned.
 */
int32_t
zbc_pwrite(zbc_device_t *dev,
           zbc_zone_t *zone,
           const void *buf,
           uint32_t lba_count,
           uint64_t lba_ofst)
{
    ssize_t ret = -EFAULT;

    if ( dev && zone && buf ) {

	if ( lba_count ) {

	    /* Execute write */
	    ret = (dev->zbd_ops->zbd_pwrite)(dev, zone, buf, lba_count, lba_ofst);
	    if ( ret <= 0 ) {
		zbc_error("Write %u blocks at block %llu + %llu failed %zd (%s)\n",
			  lba_count,
			  (unsigned long long) zbc_zone_start_lba(zone),
			  (unsigned long long) lba_ofst,
			  -ret,
			  strerror(-ret));
	    }

	} else {

	    ret = 0;

	}

    }

    return( ret );

}
示例#2
0
/**
 * Change the value of a zone write pointer.
 */
static int
zbc_fake_set_write_pointer(struct zbc_device *dev,
                           uint64_t start_lba,
                           uint64_t wp_lba)
{
    zbc_fake_device_t *fdev = zbc_fake_to_file_dev(dev);
    struct zbc_zone *zone;
    int ret = -EIO;

    if ( ! fdev->zbd_meta ) {
        return -ENXIO;
    }

    zbc_fake_lock(fdev);

    zone = zbc_fake_find_zone(fdev, start_lba);
    if ( zone ) {

        /* Do nothing for conventional zones */
        if ( zbc_zone_sequential_req(zone) ) {

            if ( zbc_zone_is_open(zone) ) {
                zbc_zone_do_close(fdev, zone);
            }

            zone->zbz_write_pointer = wp_lba;
            if ( zbc_zone_wp_lba(zone) == zbc_zone_start_lba(zone) ) {
                zone->zbz_condition = ZBC_ZC_EMPTY;
            } else if ( zbc_zone_wp_within_zone(zone) ) {
                zone->zbz_condition = ZBC_ZC_CLOSED;
            } else {
                zone->zbz_condition = ZBC_ZC_FULL;
                zone->zbz_write_pointer = (uint64_t)-1;
            }

        }

        ret = 0;

    }

    zbc_fake_unlock(fdev);

    return ret;

}
示例#3
0
/**
 * Reset a zone write pointer.
 */
static void
zbc_zone_do_reset(zbc_fake_device_t *fdev,
                  struct zbc_zone *zone)
{

    if ( ! zbc_zone_empty(zone) ) {

        if ( zbc_zone_is_open(zone) ) {
            zbc_zone_do_close(fdev, zone);
        }

        zone->zbz_write_pointer = zbc_zone_start_lba(zone);
        zone->zbz_condition = ZBC_ZC_EMPTY;

    }

    return;

}
示例#4
0
/**
 * Test if a zone must be reported.
 */
static bool
zbc_fake_must_report_zone(struct zbc_zone *zone,
                          uint64_t start_lba,
                          enum zbc_reporting_options ro)
{
    enum zbc_reporting_options options = ro & (~ZBC_RO_PARTIAL);

    if ( (zbc_zone_length(zone) == 0)
         || (zbc_zone_start_lba(zone) < start_lba) ) {
        return false;
    }

    switch( options ) {
    case ZBC_RO_ALL:
        return true;
    case ZBC_RO_EMPTY:
        return zbc_zone_empty(zone);
    case ZBC_RO_IMP_OPEN:
        return zbc_zone_imp_open(zone);
    case ZBC_RO_EXP_OPEN:
        return zbc_zone_exp_open(zone);
    case ZBC_RO_CLOSED:
        return zbc_zone_closed(zone);
    case ZBC_RO_FULL:
        return zbc_zone_full(zone);
    case ZBC_RO_RDONLY:
        return zbc_zone_rdonly(zone);
    case ZBC_RO_OFFLINE:
        return zbc_zone_offline(zone);
    case ZBC_RO_RESET:
        return zbc_zone_need_reset(zone);
    case ZBC_RO_NON_SEQ:
        return zbc_zone_non_seq(zone);
    case ZBC_RO_NOT_WP:
        return zbc_zone_not_wp(zone);
    default:
	break;
    }

    return false;

}
示例#5
0
文件: gzbc.c 项目: bistack/libzbc
int
dz_reset_zone(dz_dev_t *dzd,
	      int zno)
{
    int ret = 0;

    if ( (zno >= 0) && (zno < (int)dzd->nr_zones) ) {
        ret = zbc_reset_write_pointer(dzd->dev, zbc_zone_start_lba(&dzd->zones[zno]));
    } else if ( zno == -1 ) {
        ret = zbc_reset_write_pointer(dzd->dev, -1);
    }

    if ( ret != 0 ) {
        ret = errno;
        fprintf(stderr, "zbc_reset_write_pointer failed %d (%s)\n",
                errno,
                strerror(errno));
    }

    return( ret );

}
示例#6
0
/**
 * Close a zone.
 */
static void
zbc_zone_do_close(zbc_fake_device_t *fdev,
                  struct zbc_zone *zone)
{

    if ( zbc_zone_is_open(zone) ) {

        if ( zbc_zone_imp_open(zone) ) {
            fdev->zbd_meta->zbd_nr_imp_open_zones--;;
        } else if ( zbc_zone_exp_open(zone) ) {
            fdev->zbd_meta->zbd_nr_exp_open_zones--;
        }

        if ( zbc_zone_wp_lba(zone) == zbc_zone_start_lba(zone) ) {
            zone->zbz_condition = ZBC_ZC_EMPTY;
        } else {
            zone->zbz_condition = ZBC_ZC_CLOSED;
        }

    }

    return;

}
示例#7
0
/**
 * Write to the emulated device/file.
 */
static int32_t
zbc_fake_pwrite(struct zbc_device *dev,
                struct zbc_zone *z,
                const void *buf,
                uint32_t lba_count,
                uint64_t start_lba)
{
    zbc_fake_device_t *fdev = zbc_fake_to_file_dev(dev);
    struct zbc_zone *zone, *next_zone;
    uint64_t lba;
    off_t offset;
    size_t count;
    ssize_t ret = -EIO;

    if ( ! fdev->zbd_meta ) {
        return -ENXIO;
    }

    zbc_fake_lock(fdev);

    /* Find the target zone */
    zone = zbc_fake_find_zone(fdev, zbc_zone_start_lba(z));
    if ( ! zone ) {
        goto out;
    }

    /* Writes cannot span zones */
    if ( start_lba > zbc_zone_length(zone) ) {
        goto out;
    }

    lba = zbc_zone_next_lba(zone);
    next_zone = zbc_fake_find_zone(fdev, lba);
    start_lba += zone->zbz_start;

    if ( (start_lba + lba_count) > lba ) {
        if ( next_zone ) {
            dev->zbd_errno.sk = ZBC_E_ILLEGAL_REQUEST;
            dev->zbd_errno.asc_ascq = ZBC_E_WRITE_BOUNDARY_VIOLATION;
        } else {
            dev->zbd_errno.sk = ZBC_E_ILLEGAL_REQUEST;
            dev->zbd_errno.asc_ascq = ZBC_E_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
        }
        goto out;
    }

    if ( zbc_zone_sequential_req(zone) ) {

        /* Can only write at the write pointer */
        if ( start_lba != zbc_zone_wp_lba(zone) ) {
            dev->zbd_errno.sk = ZBC_E_ILLEGAL_REQUEST;
            dev->zbd_errno.asc_ascq = ZBC_E_UNALIGNED_WRITE_COMMAND;
            goto out;
        }

        /* Can only write an open zone */
        if ( ! zbc_zone_is_open(zone) ) {

            if ( fdev->zbd_meta->zbd_nr_exp_open_zones >= fdev->dev.zbd_info.zbd_max_nr_open_seq_req ) {
                /* Too many explicit open on-going */
                dev->zbd_errno.sk = ZBC_E_ABORTED_COMMAND;
                dev->zbd_errno.asc_ascq = ZBC_E_INSUFFICIENT_ZONE_RESOURCES;
                ret = -EIO;
                goto out;
            }

            /* Implicitely open the zone */
            if ( fdev->zbd_meta->zbd_nr_imp_open_zones >= fdev->dev.zbd_info.zbd_max_nr_open_seq_req ) {
                unsigned int i;
                for(i = 0; i < fdev->zbd_nr_zones; i++) {
                    if ( zbc_zone_imp_open(&fdev->zbd_zones[i]) ) {
                        zbc_zone_do_close(fdev, &fdev->zbd_zones[i]);
                        break;
                    }
                }
            }

            zone->zbz_condition = ZBC_ZC_IMP_OPEN;
            fdev->zbd_meta->zbd_nr_imp_open_zones++;

        }

    }

    /* XXX: check for overflows */
    count = (size_t)lba_count * dev->zbd_info.zbd_logical_block_size;
    offset = start_lba * dev->zbd_info.zbd_logical_block_size;

    ret = pwrite(dev->zbd_fd, buf, count, offset);
    if ( ret < 0 ) {

        ret = -errno;

    } else {

        ret /= dev->zbd_info.zbd_logical_block_size;

        if ( zbc_zone_sequential_req(zone) ) {

            /*
             * XXX: What protects us from a return value that's not LBA aligned?
             * (Except for hoping the OS implementation isn't insane..)
             */
            if ( (zbc_zone_wp_lba(zone) + lba_count) >= zbc_zone_next_lba(zone) ) {
                if ( zbc_zone_imp_open(zone) ) {
                    fdev->zbd_meta->zbd_nr_imp_open_zones--;
                } else {
                    fdev->zbd_meta->zbd_nr_exp_open_zones--;
                }
            }

            /* Advance write pointer */
            zbc_zone_wp_lba_inc(zone, lba_count);

        }

    }

out:

    zbc_fake_unlock(fdev);

    return ret;

}
示例#8
0
/**
 * Read from the emulated device/file.
 */
static int32_t
zbc_fake_pread(struct zbc_device *dev,
               struct zbc_zone *z,
               void *buf,
               uint32_t lba_count,
               uint64_t start_lba)
{
    zbc_fake_device_t *fdev = zbc_fake_to_file_dev(dev);
    struct zbc_zone *zone, *next_zone;
    uint64_t lba;
    ssize_t ret = -EIO;
    off_t offset;
    size_t count;

    if ( ! fdev->zbd_meta ) {
        return -ENXIO;
    }

    zbc_fake_lock(fdev);

    /* Find the target zone */
    zone = zbc_fake_find_zone(fdev, zbc_zone_start_lba(z));
    if ( ! zone ) {
        goto out;
    }

    if ( start_lba > zbc_zone_length(zone) ) {
        goto out;
    }

    lba = zbc_zone_next_lba(zone);
    next_zone = zbc_fake_find_zone(fdev, lba);
    start_lba += zbc_zone_start_lba(zone);

    /* Note: unrestricted read will be added to the standard */
    /* and supported by a drive if the URSWRZ bit is set in  */
    /* VPD page. So this test will need to change.           */
    if ( zone->zbz_type == ZBC_ZT_SEQUENTIAL_REQ ) {

        /* Cannot read unwritten data */
        if ( (start_lba + lba_count) > lba ) {
            if ( next_zone ) {
                dev->zbd_errno.sk = ZBC_E_ILLEGAL_REQUEST;
                dev->zbd_errno.asc_ascq = ZBC_E_READ_BOUNDARY_VIOLATION;
            } else {
                dev->zbd_errno.sk = ZBC_E_ILLEGAL_REQUEST;
                dev->zbd_errno.asc_ascq = ZBC_E_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
            }
            goto out;
        }

        if ( (start_lba + lba_count) > zbc_zone_wp_lba(zone) ) {
            dev->zbd_errno.sk = ZBC_E_ILLEGAL_REQUEST;
            dev->zbd_errno.asc_ascq = ZBC_E_ATTEMPT_TO_READ_INVALID_DATA;
            goto out;
        }

    } else {

        /* Reads spanning other types of zones are OK. */

        if ( (start_lba + lba_count) > lba ) {

            uint64_t count = start_lba + lba_count - lba;

            while( count && next_zone ) {
                if ( zbc_zone_sequential_req(next_zone) ) {
                    dev->zbd_errno.sk = ZBC_E_ILLEGAL_REQUEST;
                    dev->zbd_errno.asc_ascq = ZBC_E_ATTEMPT_TO_READ_INVALID_DATA;
                    goto out;
                }
                if ( count > zbc_zone_length(next_zone) ) {
                    count -= zbc_zone_length(next_zone);
                }
                lba += zbc_zone_length(next_zone);
            }

        }

    }

    /* XXX: check for overflows */
    count = lba_count * dev->zbd_info.zbd_logical_block_size;
    offset = start_lba * dev->zbd_info.zbd_logical_block_size;

    ret = pread(dev->zbd_fd, buf, count, offset);
    if ( ret < 0 ) {
        ret = -errno;
    } else {
        ret /= dev->zbd_info.zbd_logical_block_size;
    }

out:

    zbc_fake_unlock(fdev);

    return ret;

}
示例#9
0
int main(int argc,
         char **argv)
{
    struct zbc_device_info info;
    unsigned long long lba = 0;
    struct zbc_device *dev;
    enum zbc_reporting_options ro = ZBC_RO_ALL;
    int i, ret = 1;
    zbc_zone_t *z, *zones = NULL;
    unsigned int nr_zones, nz = 0;
    int num = 0;
    char *path;

    /* Check command line */
    if ( argc < 2 ) {
usage:
        printf("Usage: %s [options] <dev>\n"
               "Options:\n"
               "    -v         : Verbose mode\n"
               "    -n         : Get only the number of zones\n"
               "    -nz <num>  : Get at most <num> zones\n"
               "    -lba <lba> : Specify zone start LBA (default is 0)\n"
               "    -ro <opt>  : Specify reporting option: \"all\", \"empty\",\n"
               "                 \"imp_open\", \"exp_open\", \"closed\", \"full\",\n"
               "                 \"rdonly\", \"offline\", \"reset\", \"non_seq\" or \"not_wp\".\n"
               "                 Default is \"all\"\n",
               argv[0]);
        return( 1 );
    }

    /* Parse options */
    for(i = 1; i < (argc - 1); i++) {

        if ( strcmp(argv[i], "-v") == 0 ) {

            zbc_set_log_level("debug");

        } else if ( strcmp(argv[i], "-n") == 0 ) {

            num = 1;

	} else if ( strcmp(argv[i], "-nz") == 0 ) {

            if ( i >= (argc - 1) ) {
                goto usage;
            }
            i++;

            nz = strtol(argv[i], NULL, 10);
	    if ( nz <= 0 ) {
		goto usage;
	    }

        } else if ( strcmp(argv[i], "-lba") == 0 ) {

            if ( i >= (argc - 1) ) {
                goto usage;
            }
            i++;

            lba = strtoll(argv[i], NULL, 10);

        } else if ( strcmp(argv[i], "-ro") == 0 ) {

            if ( i >= (argc - 1) ) {
                goto usage;
            }
            i++;

            if ( strcmp(argv[i], "all") == 0 ) {
                ro = ZBC_RO_ALL;
            } else if ( strcmp(argv[i], "empty") == 0 ) {
                ro = ZBC_RO_EMPTY;
            } else if ( strcmp(argv[i], "imp_open") == 0 ) {
                ro = ZBC_RO_IMP_OPEN;
            } else if ( strcmp(argv[i], "exp_open") == 0 ) {
                ro = ZBC_RO_EXP_OPEN;
            } else if ( strcmp(argv[i], "closed") == 0 ) {
                ro = ZBC_RO_CLOSED;
            } else if ( strcmp(argv[i], "full") == 0 ) {
                ro = ZBC_RO_FULL;
            } else if ( strcmp(argv[i], "rdonly") == 0 ) {
                ro = ZBC_RO_RDONLY;
            } else if ( strcmp(argv[i], "offline") == 0 ) {
                ro = ZBC_RO_OFFLINE;
            } else if ( strcmp(argv[i], "reset") == 0 ) {
                ro = ZBC_RO_RESET;
            } else if ( strcmp(argv[i], "non_seq") == 0 ) {
                ro = ZBC_RO_NON_SEQ;
            } else if ( strcmp(argv[i], "not_wp") == 0 ) {
                ro = ZBC_RO_NOT_WP;
            } else {
                fprintf(stderr, "Unknown zone reporting option \"%s\"\n",
                        argv[i]);
                goto usage;
            }

        } else if ( argv[i][0] == '-' ) {

            printf("Unknown option \"%s\"\n",
                   argv[i]);
            goto usage;

        } else {

            break;

        }

    }

    if ( i != (argc - 1) ) {
        goto usage;
    }

    /* Open device */
    path = argv[i];
    ret = zbc_open(path, O_RDONLY, &dev);
    if ( ret != 0 ) {
        return( 1 );
    }

    ret = zbc_get_device_info(dev, &info);
    if ( ret < 0 ) {
        fprintf(stderr,
                "zbc_get_device_info failed\n");
        goto out;
    }

    printf("Device %s: %s\n",
           path,
           info.zbd_vendor_id);
    printf("    %s interface, %s disk model\n",
           zbc_disk_type_str(info.zbd_type),
           zbc_disk_model_str(info.zbd_model));
    printf("    %llu logical blocks of %u B\n",
           (unsigned long long) info.zbd_logical_blocks,
           (unsigned int) info.zbd_logical_block_size);
    printf("    %llu physical blocks of %u B\n",
           (unsigned long long) info.zbd_physical_blocks,
           (unsigned int) info.zbd_physical_block_size);
    printf("    %.03F GB capacity\n",
           (double) (info.zbd_physical_blocks * info.zbd_physical_block_size) / 1000000000);

    /* Get the number of zones */
    ret = zbc_report_nr_zones(dev, lba, ro, &nr_zones);
    if ( ret != 0 ) {
	fprintf(stderr, "zbc_report_nr_zones at lba %llu, ro 0x%02x failed %d\n",
		(unsigned long long) lba,
		(unsigned int) ro,
		ret);
	ret = 1;
	goto out;
    }

    /* Print zone info */
    printf("    %u zones from LBA %llu, reporting option 0x%02x\n",
	   nr_zones,
	   lba,
	   ro);

    if ( num ) {
	goto out;
    }

    if ( (! nz) || (nz > nr_zones) ) {
	nz = nr_zones;
    }

    /* Allocate zone array */
    zones = (zbc_zone_t *) malloc(sizeof(zbc_zone_t) * nz);
    if ( ! zones ) {
	fprintf(stderr, "No memory\n");
	ret = 1;
	goto out;
    }
    memset(zones, 0, sizeof(zbc_zone_t) * nz);

    /* Get zone information */
    ret = zbc_report_zones(dev, lba, ro, zones, &nz);
    if ( ret != 0 ) {
	fprintf(stderr, "zbc_list_zones failed %d\n", ret);
	ret = 1;
	goto out;
    }

    printf("%u / %u zones:\n", nz, nr_zones);
    for(i = 0; i < (int)nz; i++) {
        z = &zones[i];
        if ( zbc_zone_conventional(z) ) {
            printf("Zone %05d: type 0x%x (%s), cond 0x%x (%s), LBA %llu, %llu sectors, wp N/A\n",
                   i,
                   zbc_zone_type(z),
                   zbc_zone_type_str(z),
                   zbc_zone_condition(z),
                   zbc_zone_condition_str(z),
                   zbc_zone_start_lba(z),
                   zbc_zone_length(z));
        } else {
            printf("Zone %05d: type 0x%x (%s), cond 0x%x (%s), need_reset %d, non_seq %d, LBA %llu, %llu sectors, wp %llu\n",
                   i,
                   zbc_zone_type(z),
                   zbc_zone_type_str(z),
                   zbc_zone_condition(z),
                   zbc_zone_condition_str(z),
                   zbc_zone_need_reset(z),
                   zbc_zone_non_seq(z),
                   zbc_zone_start_lba(z),
                   zbc_zone_length(z),
                   zbc_zone_wp_lba(z));
        }
    }

out:

    if ( zones ) {
        free(zones);
    }

    zbc_close(dev);

    return( ret );

}
示例#10
0
int
main(int argc,
     char **argv)
{
    struct zbc_device_info info;
    struct zbc_device *dev = NULL;
    unsigned long long elapsed;
    unsigned long long bcount = 0;
    unsigned long long fsize, brate;
    struct stat st;
    int zidx;
    int floop = 0, fd = -1, i, ret = 1;
    size_t iosize, ioalign;
    void *iobuf = NULL;
    uint32_t lba_count = 0;
    int iocount = 0, ionum = 0;
    struct zbc_zone *zones = NULL;
    struct zbc_zone *iozone = NULL;
    unsigned int nr_zones;
    char *path, *file = NULL;
    long long lba_ofst = 0;
    int flush = 0;

    /* Check command line */
    if ( argc < 4 ) {
usage:
        printf("Usage: %s [options] <dev> <zone no> <I/O size>\n"
               "  Write into a zone from the current write pointer until\n"
               "  the zone is full or the number of I/O specified is executed\n"
               "Options:\n"
               "    -v         : Verbose mode\n"
               "    -s         : (sync) Run zbc_flush after writing\n"
               "    -nio <num> : Limit the number of I/O executed to <num>\n"
               "    -f <file>  : Write the content of <file>\n"
               "    -loop      : If a file is specified, repeatedly write the\n"
               "                 file to the zone until the zone is full.\n"
               "    -lba       : lba offset, from given zone <zone no> starting lba, where to write.\n",
               argv[0]);
        return( 1 );
    }

    /* Parse options */
    for(i = 1; i < (argc - 1); i++) {

        if ( strcmp(argv[i], "-v") == 0 ) {

            zbc_set_log_level("debug");

	} else if ( strcmp(argv[i], "-s") == 0 ) {

            flush = 1;

        } else if ( strcmp(argv[i], "-nio") == 0 ) {

            if ( i >= (argc - 1) ) {
                goto usage;
            }
            i++;

            ionum = atoi(argv[i]);
            if ( ionum <= 0 ) {
                fprintf(stderr, "Invalid number of I/Os\n");
                return( 1 );
            }

        } else if ( strcmp(argv[i], "-f") == 0 ) {

            if ( i >= (argc - 1) ) {
                goto usage;
            }
            i++;

            file = argv[i];

        } else if ( strcmp(argv[i], "-loop") == 0 ) {

            floop = 1;

        } else if ( strcmp(argv[i], "-lba") == 0 ) {

            if ( i >= (argc - 1) ) {
                goto usage;
            }
            i++;

            lba_ofst = atoll(argv[i]);
            if ( lba_ofst < 0 ) {
                fprintf(stderr, "Invalid negative LBA offset\n");
                return( 1 );
            }

        } else if ( argv[i][0] == '-' ) {

            fprintf(stderr,
                    "Unknown option \"%s\"\n",
                    argv[i]);
            goto usage;

        } else {

            break;

        }

    }

    if ( i != (argc - 3) ) {
        goto usage;
    }

    /* Get parameters */
    path = argv[i];

    zidx = atoi(argv[i + 1]);
    if ( zidx < 0 ) {
	fprintf(stderr,
                "Invalid zone number %s\n",
		argv[i + 1]);
        ret = 1;
        goto out;
    }

    iosize = atol(argv[i + 2]);
    if ( ! iosize ) {
	fprintf(stderr,
                "Invalid I/O size %s\n",
		argv[i + 2]);
        ret = 1;
        goto out;
    }

    /* Setup signal handler */
    signal(SIGQUIT, zbc_write_zone_sigcatcher);
    signal(SIGINT, zbc_write_zone_sigcatcher);
    signal(SIGTERM, zbc_write_zone_sigcatcher);

    /* Open device */
    ret = zbc_open(path, O_WRONLY, &dev);
    if ( ret != 0 ) {
        return( 1 );
    }

    ret = zbc_get_device_info(dev, &info);
    if ( ret < 0 ) {
        fprintf(stderr,
                "zbc_get_device_info failed\n");
        goto out;
    }

    /* Get zone list */
    ret = zbc_list_zones(dev, 0, ZBC_RO_ALL, &zones, &nr_zones);
    if ( ret != 0 ) {
        fprintf(stderr, "zbc_list_zones failed\n");
        ret = 1;
        goto out;
    }

    /* Get target zone */
    if ( zidx >= (int)nr_zones ) {
        fprintf(stderr, "Target zone not found\n");
        ret = 1;
        goto out;
    }
    iozone = &zones[zidx];

    printf("Device %s: %s interface, %s disk model\n",
           path,
           zbc_disk_type_str(info.zbd_type),
           zbc_disk_model_str(info.zbd_model));
    printf("    %llu logical blocks of %u B\n",
           (unsigned long long) info.zbd_logical_blocks,
           (unsigned int) info.zbd_logical_block_size);
    printf("    %llu physical blocks of %u B\n",
           (unsigned long long) info.zbd_physical_blocks,
           (unsigned int) info.zbd_physical_block_size);

    printf("Target zone: Zone %d / %d, type 0x%x, cond 0x%x, need_reset %d, non_seq %d, LBA %llu, %llu sectors, wp %llu\n",
           zidx,
           nr_zones,
           iozone->zbz_type,
           iozone->zbz_condition,
           iozone->zbz_need_reset,
           iozone->zbz_non_seq,
           zbc_zone_start_lba(iozone),
           zbc_zone_length(iozone),
           zbc_zone_wp_lba(iozone));

    /* Check I/O size alignment */
    if ( zbc_zone_sequential_req(iozone) ) {
	ioalign = info.zbd_physical_block_size;
    } else {
	ioalign = info.zbd_logical_block_size;
    }
    if ( iosize % ioalign ) {
        fprintf(stderr,
                "Invalid I/O size %zu (must be aligned on %zu)\n",
                iosize,
		ioalign);
        ret = 1;
        goto out;
    }

    /* Get an I/O buffer */
    ret = posix_memalign((void **) &iobuf, ioalign, iosize);
    if ( ret != 0 ) {
        fprintf(stderr,
                "No memory for I/O buffer (%zu B)\n",
                iosize);
        ret = 1;
        goto out;
    }

    /* Open the file to write, if any */
    if ( file ) {

        fd = open(file, O_LARGEFILE | O_RDONLY);
        if ( fd < 0 ) {
            fprintf(stderr, "Open file \"%s\" failed %d (%s)\n",
                    file,
                    errno,
                    strerror(errno));
            ret = 1;
            goto out;
        }

        ret = fstat(fd, &st);
        if ( ret != 0 ) {
            fprintf(stderr, "Stat file \"%s\" failed %d (%s)\n",
                    file,
                    errno,
                    strerror(errno));
            ret = 1;
            goto out;
        }

        if ( S_ISREG(st.st_mode) ) {
            fsize = st.st_size;
        } else if ( S_ISBLK(st.st_mode) ) {
            ret = ioctl(fd, BLKGETSIZE64, &fsize);
            if ( ret != 0 ) {
                fprintf(stderr,
                        "ioctl BLKGETSIZE64 block device \"%s\" failed %d (%s)\n",
                        file,
                        errno,
                        strerror(errno));
                ret = 1;
                goto out;
            }
        } else {
            fprintf(stderr, "Unsupported file \"%s\" type\n",
                    file);
            ret = 1;
            goto out;
        }

        printf("Writting file \"%s\" (%llu B) to target zone %d, %zu B I/Os\n",
               file,
               fsize,
               zidx,
               iosize);

    } else if ( ! ionum ) {

        printf("Filling target zone %d, %zu B I/Os\n",
               zidx,
               iosize);

    } else {

        printf("Writting to target zone %d, %d I/Os of %zu B\n",
               zidx,
               ionum,
               iosize);

    }

    if ( ! zbc_zone_conventional(iozone) ) {
        lba_ofst = zbc_zone_wp_lba(iozone) - zbc_zone_start_lba(iozone);
    }

    elapsed = zbc_write_zone_usec();

    while( (! zbc_write_zone_abort)
           && (lba_ofst < (long long)zbc_zone_length(iozone)) ) {

        if ( file ) {

	    size_t ios;

            /* Read file */
            ret = read(fd, iobuf, iosize);
            if ( ret < 0 ) {
                fprintf(stderr, "Read file \"%s\" failed %d (%s)\n",
                        file,
                        errno,
                        strerror(errno));
                ret = 1;
                break;
            }

            ios = ret;
            if ( ios < iosize ) {
                if ( floop ) {
                    /* Rewind and read remaining of buffer */
                    lseek(fd, 0, SEEK_SET);
                    ret = read(fd, iobuf + ios, iosize - ios);
                    if ( ret < 0 ) {
                        fprintf(stderr, "Read file \"%s\" failed %d (%s)\n",
                                file,
                                errno,
                                strerror(errno));
                        ret = 1;
                        break;
                    }
                    ios += ret;
                } else if ( ios ) {
                    /* Clear end of buffer */
                    memset(iobuf + ios, 0, iosize - ios);
                }
            }

            if ( ! ios ) {
                /* EOF */
                break;
            }

        }

        /* Write to zone */
        lba_count = iosize / info.zbd_logical_block_size;
        if ( (lba_ofst + lba_count) > (long long)zbc_zone_length(iozone) ) {
            lba_count = zbc_zone_length(iozone) - lba_ofst;
        }

        if ( zbc_zone_conventional(iozone) ) {
            ret = zbc_pwrite(dev, iozone, iobuf, lba_count, lba_ofst);
	    if ( ret > 0 ) {
	        lba_ofst += ret;
	    }
        } else {
            ret = zbc_write(dev, iozone, iobuf, lba_count);
        }

        if ( ret <= 0 ) {
            ret = 1;
            break;
        }

        /* Update zone write pointer */
	lba_ofst += ret;
        if ( zbc_zone_sequential_req(iozone) ) {
            iozone->zbz_write_pointer += ret;
	} else if ( zbc_zone_sequential_pref(iozone) ) {
    	    ret = zbc_report_zones(dev, 0, ZBC_RO_ALL, zones, &nr_zones);
    	    if ( ret != 0 ) {
       	        fprintf(stderr, "zbc_report_zones failed\n");
       	        ret = 1;
       	        goto out;
    	    }
  	}

        bcount += ret * info.zbd_logical_block_size;
        iocount++;

        if ( (ionum > 0) && (iocount >= ionum) ) {
            break;
        }

    }

    elapsed = zbc_write_zone_usec() - elapsed;

    if ( elapsed ) {
        printf("Wrote %llu B (%d I/Os) in %llu.%03llu sec\n",
               bcount,
               iocount,
               elapsed / 1000000,
               (elapsed % 1000000) / 1000);
        printf("  IOPS %llu\n",
               iocount * 1000000 / elapsed);
        brate = bcount * 1000000 / elapsed;
        printf("  BW %llu.%03llu MB/s\n",
               brate / 1000000,
               (brate % 1000000) / 1000);
    } else {
        printf("Wrote %llu B (%d I/Os)\n",
               bcount,
               iocount);
    }

    if ( flush ) {
        printf("Flushing disk...\n");
	ret = zbc_flush(dev);
	if ( ret != 0 ) {
	    fprintf(stderr, "zbc_flush failed %d (%s)\n",
		    -ret,
		    strerror(-ret));
	    ret = 1;
	}
    }

out:

    if ( iobuf ) {
        free(iobuf);
    }

    if ( fd > 0 ) {
        close(fd);
    }

    if ( zones ) {
        free(zones);
    }

    zbc_close(dev);

    return( ret );

}
示例#11
0
int
main(int argc,
     char **argv)
{
    struct zbc_device_info info;
    unsigned long long lba = 0;
    struct zbc_device *dev;
    enum zbc_reporting_options ro = ZBC_RO_ALL;
    int i, ret = 1;
    zbc_zone_t *z, *zones = NULL;
    unsigned int nr_zones, nz = 0, prtl = 0;
    int num = 0;
    char *path;

    /* Check command line */
    if ( argc < 2 ) {
usage:
        printf("Usage: %s [options] <dev>\n"
               "Options:\n"
               "    -v         : Verbose mode\n"
               "    -lba <lba> : Specify zone start LBA (default is 0)\n"
               "    -ro <opt>  : Reporting Option\n"
               "    -p         : Partial bit\n",
               argv[0]);
        return( 1 );
    }

    /* Parse options */
    for(i = 1; i < (argc - 1); i++) {

        if ( strcmp(argv[i], "-v") == 0 ) {

            zbc_set_log_level("debug");

        } else if ( strcmp(argv[i], "-lba") == 0 ) {

            if ( i >= (argc - 1) ) {
                goto usage;
            }
            i++;

            lba = strtoll(argv[i], NULL, 10);

        } else if ( strcmp(argv[i], "-ro") == 0 ) {

            if ( i >= (argc - 1) ) {
                goto usage;
            }
            i++;

            ro = atoi(argv[i]);

            if ( ro < 0 ) {
                goto usage;
            }

        } else if ( strcmp(argv[i], "-p") == 0 ) {

            prtl = ZBC_RO_PARTIAL; 

        } else if ( argv[i][0] == '-' ) {

            printf("Unknown option \"%s\"\n",
                   argv[i]);
            goto usage;

        } else {

            break;

        }

    }

    if ( i != (argc - 1) ) {
        goto usage;
    }

    /* Merging ro */
    ro |= prtl;

    /* Open device */
    path = argv[i];
    ret = zbc_open(path, O_RDONLY, &dev);
    if ( ret != 0 ) {
        fprintf(stderr, "[TEST][ERROR],open device failed\n");
	printf("[TEST][ERROR][SENSE_KEY],open-device-failed\n");
	printf("[TEST][ERROR][ASC_ASCQ],open-device-failed\n");
        return( 1 );
    }

    ret = zbc_get_device_info(dev, &info);
    if ( ret < 0 ) {
        fprintf(stderr,
                "[TEST][ERROR],zbc_get_device_info failed\n");
        goto out;
    }

    /* Get the number of zones */
    ret = zbc_report_nr_zones(dev, lba, ro, &nr_zones);
    if ( ret != 0 ) {
	fprintf(stderr, "[TEST][ERROR],zbc_report_nr_zones at lba %llu, ro 0x%02x failed %d\n",
		(unsigned long long) lba,
		(unsigned int) ro,
		ret);
	ret = 1;
	goto out;
    }

    if ( num ) {
	goto out;
    }

    if ( (! nz) || (nz > nr_zones) ) {
	nz = nr_zones;
    }

    /* Allocate zone array */
    zones = (zbc_zone_t *) malloc(sizeof(zbc_zone_t) * nz);
    if ( ! zones ) {
	fprintf(stderr,
                "[TEST][ERROR],No memory\n");
	ret = 1;
	goto out;
    }
    memset(zones, 0, sizeof(zbc_zone_t) * nz);

    /* Get zone information */
    ret = zbc_report_zones(dev, lba, ro, zones, &nz);
    if ( ret != 0 ) {
	fprintf(stderr,
                "[TEST][ERROR],zbc_report_zones failed %d\n", ret);
	ret = 1;
	goto out;
    }

    for(i = 0; i < (int)nz; i++) {
        z = &zones[i];
        if ( zbc_zone_conventional(z) ) {
            printf("[ZONE_INFO],%05d,0x%x,0x%x,%llu,%llu,N/A\n",
                   i,
                   zbc_zone_type(z),
                   zbc_zone_condition(z),
                   zbc_zone_start_lba(z),
                   zbc_zone_length(z));
        } else {
            printf("[ZONE_INFO],%05d,0x%x,0x%x,%llu,%llu,%llu\n",
                   i,
                   zbc_zone_type(z),
                   zbc_zone_condition(z),
                   zbc_zone_start_lba(z),
                   zbc_zone_length(z),
                   zbc_zone_wp_lba(z));
        }
    }

out:

    if ( ret ) {

            zbc_errno_t zbc_err;
            const char *sk_name;
            const char *ascq_name;

            zbc_errno(dev, &zbc_err);
            sk_name = zbc_sk_str(zbc_err.sk);
            ascq_name = zbc_asc_ascq_str(zbc_err.asc_ascq);

            printf("[TEST][ERROR][SENSE_KEY],%s\n", sk_name);
            printf("[TEST][ERROR][ASC_ASCQ],%s\n", ascq_name);

    }

    if ( zones ) {
        free(zones);
    }

    zbc_close(dev);

    return( ret );

}
示例#12
0
int main(int argc,
         char **argv)
{
    struct zbc_device_info info;
    struct zbc_device *dev = NULL;
    unsigned long long elapsed;
    unsigned long long bcount = 0;
    unsigned long long brate;
    int zidx;
    int fd = -1, i, ret = 1;
    size_t iosize;
    void *iobuf = NULL;
    uint32_t lba_count;
    unsigned long long ionum = 0, iocount = 0;
    struct zbc_zone *zones = NULL;
    struct zbc_zone *iozone = NULL;
    unsigned int nr_zones;
    char *path, *file = NULL;
    long long lba_ofst = 0;
    long long lba_max = 0;
    int flags = O_RDONLY;

    /* Check command line */
    if ( argc < 4 ) {
usage:
        printf("Usage: %s [options] <dev> <zone no> <I/O size (B)>\n"
               "  Read a zone up to the current write pointer\n"
               "  or the number of I/O specified is executed\n"
               "Options:\n"
               "    -v         : Verbose mode\n"
               "    -dio       : Use direct I/Os for accessing the device\n"
               "    -nio <num> : Limit the number of I/O executed to <num>\n"
               "    -f <file>  : Write the content of the zone to <file>\n"
               "                 If <file> is \"-\", the zone content is\n"
               "                 written to the standard output\n"
               "     -lba      : lba offset from the starting lba of the zone <zone no>.\n",
               argv[0]);
        return( 1 );
    }

    /* Parse options */
    for(i = 1; i < (argc - 1); i++) {

        if ( strcmp(argv[i], "-v") == 0 ) {

            zbc_set_log_level("debug");

	} else if ( strcmp(argv[i], "-dio") == 0 ) {

	    flags |= O_DIRECT;

        } else if ( strcmp(argv[i], "-nio") == 0 ) {

            if ( i >= (argc - 1) ) {
                goto usage;
            }
            i++;

            ionum = atoi(argv[i]);
            if ( ionum <= 0 ) {
                fprintf(stderr, "Invalid number of I/Os\n");
                return( 1 );
            }

        } else if ( strcmp(argv[i], "-f") == 0 ) {

            if ( i >= (argc - 1) ) {
                goto usage;
            }
            i++;

            file = argv[i];

        } else if ( strcmp(argv[i], "-lba") == 0 ) {

            if ( i >= (argc - 1) ) {
                goto usage;
            }
            i++;

            lba_ofst = atoll(argv[i]);
            if ( lba_ofst < 0 ) {
                fprintf(stderr, "LBA offset has to be greater or equal to 0.\n");
                return( 1 );
            }

        } else if ( argv[i][0] == '-' ) {

            fprintf(stderr,
                    "Unknown option \"%s\"\n",
                    argv[i]);
            goto usage;

        } else {

            break;

        }

    }

    if ( i != (argc - 3) ) {
        goto usage;
    }

    /* Get parameters */
    path = argv[i];
    zidx = atoi(argv[i + 1]);
    if ( zidx < 0 ) {
	fprintf(stderr,
                "Invalid zone number %s\n",
		argv[i + 1]);
        ret = 1;
        goto out;
    }

    iosize = atol(argv[i + 2]);
    if ( ! iosize ) {
	fprintf(stderr,
                "Invalid I/O size %s\n",
		argv[i + 2]);
        ret = 1;
        goto out;
    }

    /* Setup signal handler */
    signal(SIGQUIT, zbc_read_zone_sigcatcher);
    signal(SIGINT, zbc_read_zone_sigcatcher);
    signal(SIGTERM, zbc_read_zone_sigcatcher);

    /* Open device */
    ret = zbc_open(path, flags, &dev);
    if ( ret != 0 ) {
        return( 1 );
    }

    ret = zbc_get_device_info(dev, &info);
    if ( ret < 0 ) {
        fprintf(stderr,
                "zbc_get_device_info failed\n");
        goto out;
    }

    /* Get zone list */
    ret = zbc_list_zones(dev, 0, ZBC_RO_ALL, &zones, &nr_zones);
    if ( ret != 0 ) {
        fprintf(stderr, "zbc_list_zones failed\n");
        ret = 1;
        goto out;
    }

    /* Get target zone */
    if ( (unsigned int)zidx >= nr_zones ) {
        fprintf(stderr, "Target zone not found\n");
        ret = 1;
        goto out;
    }
    iozone = &zones[zidx];

    printf("Device %s: %s\n",
           path,
           info.zbd_vendor_id);
    printf("    %s interface, %s disk model\n",
           zbc_disk_type_str(info.zbd_type),
           zbc_disk_model_str(info.zbd_model));
    printf("    %llu logical blocks of %u B\n",
           (unsigned long long) info.zbd_logical_blocks,
           (unsigned int) info.zbd_logical_block_size);
    printf("    %llu physical blocks of %u B\n",
           (unsigned long long) info.zbd_physical_blocks,
           (unsigned int) info.zbd_physical_block_size);
    printf("    %.03F GB capacity\n",
           (double) (info.zbd_physical_blocks * info.zbd_physical_block_size) / 1000000000);

    printf("Target zone: Zone %d / %d, type 0x%x (%s), cond 0x%x (%s), need_reset %d, "
	   "non_seq %d, LBA %llu, %llu sectors, wp %llu\n",
           zidx,
           nr_zones,
           zbc_zone_type(iozone),
           zbc_zone_type_str(zbc_zone_type(iozone)),
           zbc_zone_condition(iozone),
           zbc_zone_condition_str(zbc_zone_condition(iozone)),
           zbc_zone_need_reset(iozone),
           zbc_zone_non_seq(iozone),
           zbc_zone_start_lba(iozone),
           zbc_zone_length(iozone),
           zbc_zone_wp_lba(iozone));

    /* Check alignment and get an I/O buffer */
    if ( iosize % info.zbd_logical_block_size ) {
        fprintf(stderr,
                "Invalid I/O size %zu (must be aligned on %u)\n",
                iosize,
                (unsigned int) info.zbd_logical_block_size);
        ret = 1;
        goto out;
    }
    ret = posix_memalign((void **) &iobuf, sysconf(_SC_PAGESIZE), iosize);
    if ( ret != 0 ) {
        fprintf(stderr,
                "No memory for I/O buffer (%zu B)\n",
                iosize);
        ret = 1;
        goto out;
    }

    /* Open the file to write, if any */
    if ( file ) {

        if ( strcmp(file, "-") == 0 ) {

            fd = fileno(stdout);
            printf("Writting target zone %d to standard output, %zu B I/Os\n",
                   zidx,
                   iosize);

        } else {

            fd = open(file, O_CREAT | O_TRUNC | O_LARGEFILE | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP);
            if ( fd < 0 ) {
                fprintf(stderr, "Open file \"%s\" failed %d (%s)\n",
                        file,
                        errno,
                        strerror(errno));
                ret = 1;
                goto out;
            }

            printf("Writting target zone %d to file \"%s\", %zu B I/Os\n",
                   zidx,
                   file,
                   iosize);

        }

    } else if ( ! ionum ) {

        printf("Reading target zone %d, %zu B I/Os\n",
               zidx,
               iosize);

    } else {

        printf("Reading target zone %d, %llu I/Os of %zu B\n",
               zidx,
               ionum,
               iosize);

    }

    if ( zbc_zone_sequential_req(iozone)
	 && (! zbc_zone_full(iozone)) ) {
        lba_max = zbc_zone_wp_lba(iozone) - zbc_zone_start_lba(iozone);
    } else {
        lba_max = zbc_zone_length(iozone);
    }

    lba_count = iosize / info.zbd_logical_block_size;

    elapsed = zbc_read_zone_usec();

    while( (! zbc_read_zone_abort)
           && (lba_ofst < lba_max) ) {

        /* Read zone */
        if (  (lba_ofst + lba_count) > lba_max ) {
            lba_count = lba_max - lba_ofst;
        }

        ret = zbc_pread(dev, iozone, iobuf, lba_count, lba_ofst);
        if ( ret <= 0 ) {
	    fprintf(stderr, "zbc_pread failed %d (%s)\n",
		    -ret,
		    strerror(-ret));
            ret = 1;
            break;
        }
        lba_count = ret;

        if ( file ) {
            /* Write file */
            ret = write(fd, iobuf, lba_count * info.zbd_logical_block_size);
            if ( ret < 0 ) {
                fprintf(stderr, "Write file \"%s\" failed %d (%s)\n",
                        file,
                        errno,
                        strerror(errno));
                ret = 1;
                break;
            }
        }

        lba_ofst += lba_count;
        bcount += lba_count * info.zbd_logical_block_size;
        iocount++;
        ret = 0;

        /* If a number of IO was given as input then
         * lba_max = iozone + lba_ofst + ionum
         */
        if ( (ionum > 0) && (iocount >= ionum) ) {
            break;
        }

    }

    elapsed = zbc_read_zone_usec() - elapsed;

    if ( elapsed ) {
        printf("Read %llu B (%llu I/Os) in %llu.%03llu sec\n",
               bcount,
               iocount,
               elapsed / 1000000,
               (elapsed % 1000000) / 1000);
        printf("  IOPS %llu\n",
               iocount * 1000000 / elapsed);
        brate = bcount * 1000000 / elapsed;
        printf("  BW %llu.%03llu MB/s\n",
               brate / 1000000,
               (brate % 1000000) / 1000);
    } else {
        printf("Read %llu B (%llu I/Os)\n",
               bcount,
               iocount);
    }

out:

    if ( file && (fd > 0) ) {
        if ( fd != fileno(stdout) ) {
            close(fd);
        }
        if ( ret != 0 ) {
            unlink(file);
        }
    }

    if ( iobuf ) {
        free(iobuf);
    }

    if ( zones ) {
        free(zones);
    }

    zbc_close(dev);

    return( ret );

}