diff --git a/dasdview/dasdview.c b/dasdview/dasdview.c index 2bf08ec8..d27f3f67 100644 --- a/dasdview/dasdview.c +++ b/dasdview/dasdview.c @@ -1741,7 +1741,7 @@ static void dasdview_print_vtoc_raw(dasdview_info_t *info) " rc=%d\n", rc); exit(-1); } - rc = lzds_dasd_read_rawvtoc(info->dasd); + rc = lzds_dasd_alloc_rawvtoc(info->dasd); if (rc == EINVAL) { zt_error_print("dasdview: Cannot read VTOC because disk does" " not contain valid VOL1 label.\n", diff --git a/include/lib/dasd_base.h b/include/lib/dasd_base.h index cf7be2ee..3505cdd9 100644 --- a/include/lib/dasd_base.h +++ b/include/lib/dasd_base.h @@ -170,6 +170,10 @@ struct hd_geometry { #define BIODASDDISABLE _IO(DASD_IOCTL_LETTER, 0) /* Enable the volume (for Linux) */ #define BIODASDENABLE _IO(DASD_IOCTL_LETTER, 1) +/* Reserve the device for the current LPAR */ +#define BIODASDRSRV _IO(DASD_IOCTL_LETTER, 2) +/* Release the device for the current LPAR */ +#define BIODASDRLSE _IO(DASD_IOCTL_LETTER, 3) /* Get information on a dasd device (enhanced) */ #define BIODASDINFO2 _IOR(DASD_IOCTL_LETTER, 3, dasd_information2_t) /* #define BIODASDFORMAT _IOW(IOCTL_LETTER,0,format_data_t) , deprecated */ @@ -203,5 +207,7 @@ int dasd_get_geo(const char *device, struct hd_geometry *geo); int dasd_get_info(const char *device, dasd_information2_t *info); int dasd_is_ro(const char *device, bool *ro); int dasd_reread_partition_table(const char *device, int ntries); +int dasd_disk_reserve(const char *device); +int dasd_disk_release(const char *device); #endif /* LIB_DASD_BASE_H */ diff --git a/include/lib/libzds.h b/include/lib/libzds.h index 355bf779..6ae767b5 100644 --- a/include/lib/libzds.h +++ b/include/lib/libzds.h @@ -112,6 +112,8 @@ */ #define LIB_LIBZDS_H +#include "lib/util_base.h" +#include "lib/util_list.h" #include "vtoc.h" @@ -328,11 +330,74 @@ struct pds_member_entry { */ struct zdsroot; +/** + * @struct raw_vtoc + * @brief The VTOC is a directory of data sets on one DASD + * + * As the VTOC is the data area on the DASD that describes all data sets, + * this library will often have to refer to the various records in the VTOC. + * To make this more efficient, we will read the whole VTOC once and identify + * all elements (DSCBs). The raw data of the VTOC tracks and the index to the + * DSCBs is stored. + */ +struct raw_vtoc { + /** @brief The raw track data */ + char *rawdata; + /** @brief This size of the raw track data in bytes */ + unsigned long long rawdatasize; + /** @brief An array with pointers to the various DSCBs in the rawdata */ + char **vtocindex; + /** @brief Number of entries in the index */ + unsigned int vtocindexcount; + /** @brief Number of records per VTOC track + * + * @note While the DS4DEVDT field in the format 4 DSCB names the number + * if DSCBs per VTOC track, we count the records, which is DS4DEVDT + 1 + * for record 0. + */ + unsigned int vtoc_rec_per_track; + /** @brief The track number at which the vtoc begins on the DASD */ + unsigned int vtoctrackoffset; + /** @brief Start record of VTOC. + * + * The rawdata contains full tracks. This is the number of the first + * record that actually belongs to the VTOC + */ + unsigned int vtocrecno; + /** @brief The DASD this vtoc was read from */ + struct dasd *dasd; + /** @brief Detailed error messages in case of a problem */ + struct errorlog *log; +}; + /** * @struct dasd * @brief Represents one physical device, may have a vtoc */ -struct dasd; +struct dasd { + /** @brief List head used to store a list of DASDs in struct zdsroot */ + struct util_list_node list; + /** @brief Name of the block device, e.g. /dev/dasde */ + char *device; + /** @brief File descriptor for the block device. + * + * The device is kept open for as along as the library uses it. + * This lets the system know that the device is still in use. + */ + int inusefd; + /* @brief where to find the volume label */ + unsigned int label_block; + /** @brief Device geometry. How many cylinders does the DASD have. */ + unsigned int cylinders; + /** @brief Device geometry. How many heads does the DASD have. */ + unsigned int heads; + /** @brief The VTOC data that has been read from this device */ + struct raw_vtoc *rawvtoc; + /** @brief The volume label that has been read from this device */ + volume_label_t *vlabel; + /** @brief Detailed error messages in case of a problem */ + struct errorlog *log; +}; /** * @struct dasditerator @@ -350,12 +415,6 @@ struct dasditerator; */ struct dasdhandle; -/** - * @struct raw_vtoc - * @brief The VTOC is a directory of data sets on one dasd - */ -struct raw_vtoc; - /** * @struct dscbiterator * @brief allows to iterate over all DSCBs in a vtoc @@ -572,7 +631,13 @@ int lzds_dasd_get_vlabel(struct dasd *dasd, struct volume_label **vlabel); * @brief Read the vtoc data from device. The data as stored as part * of the struct dasd. */ -int lzds_dasd_read_rawvtoc(struct dasd *dasd); +int lzds_dasd_read_rawvtoc(struct dasd *dasd, struct raw_vtoc *vtoc); + +/** + * @brief Read the vtoc data from device. The data as stored as part + * of the struct dasd. + */ +int lzds_dasd_alloc_rawvtoc(struct dasd *dasd); /** * @brief Get the previously read raw_vtoc data. @@ -787,6 +852,8 @@ int lzds_zdsroot_extract_datasets_from_dasd(struct zdsroot *root, struct dasd *dasd); +void lzds_dslist_free(struct zdsroot *root); + /** @} */ /* end of group libzds_functions_high */ diff --git a/libdasd/dasd_ioctl.c b/libdasd/dasd_ioctl.c index bbfb3848..bf97ce5b 100644 --- a/libdasd/dasd_ioctl.c +++ b/libdasd/dasd_ioctl.c @@ -261,3 +261,42 @@ int dasd_reread_partition_table(const char *device, int ntries) return err; } + +/* + * Reserve DASD disk. + * + * @param[in] device node device node's name + * + * @retval 0 in case of success + * @retval errno in case of failure + * + */ +int dasd_disk_reserve(const char *device) +{ + int fd; + + fd = dasd_open_device(device, O_RDONLY); + RUN_IOCTL(fd, BIODASDRSRV, NULL); + dasd_close_device(fd); + + return 0; +} + +/* + * Release DASD disk + * + * @param[in] device node device node's name + * + * @retval 0 in case of success + * @retval errno in case of failure + */ +int dasd_disk_release(const char *device) +{ + int fd; + + fd = dasd_open_device(device, O_RDONLY); + RUN_IOCTL(fd, BIODASDRLSE, NULL); + dasd_close_device(fd); + + return 0; +} diff --git a/libzds/libzds.c b/libzds/libzds.c index 2430962e..9032b5b1 100644 --- a/libzds/libzds.c +++ b/libzds/libzds.c @@ -22,8 +22,6 @@ #include "lib/dasd_base.h" #include "lib/libzds.h" #include "lib/u2s.h" -#include "lib/util_base.h" -#include "lib/util_list.h" #include "lib/vtoc.h" /** @cond PRIVATE */ @@ -70,42 +68,6 @@ struct errormsg { char text[ERRORMSG]; }; -/** - * As the VTOC is the data area on the DASD that describes all data sets, - * this library will often have to refer to the various records in the VTOC. - * To make this more efficiant, we will read the whole VTOC once and identify - * all elements (DSCBs). The raw data of the VTOC tracks and the index to the - * DSCBs is stored. - */ -struct raw_vtoc { - /** @brief The raw track data */ - char *rawdata; - /** @brief This size of the raw track data in bytes */ - unsigned long long rawdatasize; - /** @brief An array with pointers to the various DSCBs in the rawdata */ - char **vtocindex; - /** @brief Number of entries in the index */ - unsigned int vtocindexcount; - /** @brief Number of records per VTOC track - * - * @note While the DS4DEVDT field in the format 4 DSCB names the number - * if DSCBs per VTOC track, we count the records, which is DS4DEVDT + 1 - * for record 0. - */ - unsigned int vtoc_rec_per_track; - /** @brief The track number in which the vtoc begins on the DASD */ - unsigned int vtoctrackoffset; - /** @brief Start record of VTOC. - * - * The rawdata contains full tracks. This is the number of the first - * record that actually belongs to the VTOC */ - unsigned int vtocrecno; - /** @brief The DASD this vtoc was read from */ - struct dasd *dasd; - /** @brief Detailed error messages in case of a problem */ - struct errorlog *log; -}; - struct dscbiterator { /** @brief The raw_vtoc this iterator refers to */ struct raw_vtoc *rawvtoc; @@ -113,31 +75,6 @@ struct dscbiterator { unsigned int i; }; -struct dasd { - /** @brief List head used to store a list of DASDs in struct zdsroot */ - struct util_list_node list; - /** @brief Name of the block device, e.g. /dev/dasde */ - char *device; - /** @brief File descriptor for the block device. - * - * The device is kept open for as along as the library uses it. - * This lets the system know that the device is still in use. - */ - int inusefd; - /* @brief where to find the volume label */ - unsigned int label_block; - /** @brief Device geometry. How many cylinders does the DASD have. */ - unsigned int cylinders; - /** @brief Device geometry. How many heads does the DASD have. */ - unsigned int heads; - /** @brief The VTOC data that has been read from this device */ - struct raw_vtoc *rawvtoc; - /** @brief The volume label that has been read from this device */ - volume_label_t *vlabel; - /** @brief Detailed error messages in case of a problem */ - struct errorlog *log; -}; - struct dasdhandle { /** @brief The struct dasd this context relates to */ struct dasd *dasd; @@ -412,6 +349,29 @@ int lzds_zdsroot_alloc(struct zdsroot **root) return 0; } + +/** + * It should be noted that this frees all structures that are owned by the + * root structure as well. For example, a pointer to a struct dasd that + * has been returned by lzds_zdsroot_add_device is not valid anymore. + * + * @param[in] root Reference to the zdsroot structure that is to be freed. + */ +void lzds_dslist_free(struct zdsroot *root) +{ + struct dataset *ds, *nextds; + int i; + + util_list_iterate_safe(root->datasetlist, ds, nextds) { + util_list_remove(root->datasetlist, ds); + dataset_free_memberlist(ds); + for (i = 0; i < MAXVOLUMESPERDS; ++i) + free(ds->dsp[i]); + errorlog_free(ds->log); + free(ds); + } +} + /** * It should be noted that this frees all structures that are owned by the * root structure as well. For example, a pointer to a struct dasd that @@ -422,8 +382,6 @@ int lzds_zdsroot_alloc(struct zdsroot **root) void lzds_zdsroot_free(struct zdsroot *root) { struct dasd *dasd, *nextdasd; - struct dataset *ds, *nextds; - int i; if (!root) return; @@ -433,15 +391,7 @@ void lzds_zdsroot_free(struct zdsroot *root) dasd_free(dasd); } util_list_free(root->dasdlist); - - util_list_iterate_safe(root->datasetlist, ds, nextds) { - util_list_remove(root->datasetlist, ds); - dataset_free_memberlist(ds); - for (i = 0; i < MAXVOLUMESPERDS; ++i) - free(ds->dsp[i]); - errorlog_free(ds->log); - free(ds); - } + lzds_dslist_free(root); util_list_free(root->datasetlist); errorlog_free(root->log); free(root); @@ -1443,7 +1393,7 @@ int lzds_raw_vtoc_get_dscb_from_cchhb(struct raw_vtoc *rv, cchhb_t *p, * - EPROTO The VTOC data is not in a valid format. * - EIO Other I/O error */ -int lzds_dasd_read_rawvtoc(struct dasd *dasd) +int lzds_dasd_read_rawvtoc(struct dasd *dasd, struct raw_vtoc *rawvtoc) { unsigned long long vtoctrckno, vtocrecno; unsigned int vtoctrack_start, vtoctrack_end, vtocindexsize; @@ -1455,26 +1405,11 @@ int lzds_dasd_read_rawvtoc(struct dasd *dasd) format4_label_t *f4; unsigned long long rawvtocsize; - struct raw_vtoc *rawvtoc = NULL; volume_label_t *vlabel = NULL; char *trackdata = NULL; char vol1[] = {0xe5, 0xd6, 0xd3, 0xf1, 0x00}; /* "VOL1" in EBCDIC */ errorlog_clear(dasd->log); - /* cleanup the old rawvtoc structures before we read new ones */ - rawvtoc = dasd->rawvtoc; - dasd->rawvtoc = NULL; - if (rawvtoc) { - free(rawvtoc->rawdata); - free(rawvtoc->vtocindex); - free(rawvtoc); - } - - rawvtoc = malloc(sizeof(*rawvtoc)); - if (!rawvtoc) - return ENOMEM; - memset(rawvtoc, 0, sizeof(*rawvtoc)); - rawvtoc->dasd = dasd; rc = lzds_dasd_get_vlabel(dasd, &vlabel); if (rc) { @@ -1611,13 +1546,49 @@ int lzds_dasd_read_rawvtoc(struct dasd *dasd) ++i; } - dasd->rawvtoc = rawvtoc; return 0; cleanup: - free(rawvtoc->vtocindex); free(trackdata); - free(rawvtoc); + return rc; +} + +/** + * @param[in] dasd The struct dasd that represents the device we want to read + * the VTOC from. + * @return 0 on success, otherwise one of the following error codes: + * - ENOMEM Could not allocate internal structure due to lack of memory. + * - EINVAL The volume label has not yet been read or it is not valid. + * - EPROTO The VTOC data is not in a valid format. + * - EIO Other I/O error + */ +int lzds_dasd_alloc_rawvtoc(struct dasd *dasd) +{ + struct raw_vtoc *rawvtoc = NULL; + int rc; + + /* cleanup the old rawvtoc structures before we read new ones */ + rawvtoc = dasd->rawvtoc; + dasd->rawvtoc = NULL; + if (rawvtoc) { + free(rawvtoc->rawdata); + free(rawvtoc->vtocindex); + free(rawvtoc); + } + + rawvtoc = malloc(sizeof(*rawvtoc)); + if (!rawvtoc) + return ENOMEM; + memset(rawvtoc, 0, sizeof(*rawvtoc)); + rawvtoc->dasd = dasd; + + rc = lzds_dasd_read_rawvtoc(dasd, rawvtoc); + if (rc) { + free(rawvtoc->vtocindex); + free(rawvtoc); + } else { + dasd->rawvtoc = rawvtoc; + } return rc; } @@ -2261,6 +2232,7 @@ out1: static int dataset_merge_dataset(struct dataset *baseds, struct dataset *newds) { int k, l, dspcount; + for (k = 0; k < MAXVOLUMESPERDS; ++k) { /* if both datasets have a part in position k, * then something is wrong */ @@ -2280,18 +2252,20 @@ static int dataset_merge_dataset(struct dataset *baseds, struct dataset *newds) * Since dsp[0] may not be set yet, we loop over the * base dsp array until we find an entry. */ - for (l = 0; l < MAXVOLUMESPERDS; ++l) - if (baseds->dsp[l]) { - if (memcmp(baseds->dsp[l]->f1->DS1DSSN, - newds->dsp[k]->f1->DS1DSSN, - MAXVOLSER)) - return errorlog_add_message( - &baseds->log, NULL, EPROTO, - "merge dataset: part %d has incompatible" - " base volume serial\n", k); - else - break; - } + for (l = 0; l < MAXVOLUMESPERDS; ++l) { + if (!baseds->dsp[l]) + continue; + if (memcmp(baseds->dsp[l]->f1->DS1DSSN, + newds->dsp[k]->f1->DS1DSSN, + MAXVOLSER)) + return errorlog_add_message( + &baseds->log, NULL, EPROTO, + "merge dataset: part %d has incompatible base volume serial\n", + k); + else + break; + } + baseds->dsp[k] = newds->dsp[k]; baseds->dspcount++; diff --git a/zdsfs/zdsfs.c b/zdsfs/zdsfs.c index 6f75bc36..92069d90 100644 --- a/zdsfs/zdsfs.c +++ b/zdsfs/zdsfs.c @@ -53,6 +53,8 @@ struct zdsfs_info { }; static struct zdsfs_info zdsfsinfo; +static int zdsfs_create_meta_data_buffer(struct zdsfs_info *); +static int zdsfs_verify_datasets(void); struct zdsfs_file_info { struct dshandle *dsh; @@ -193,6 +195,48 @@ static int zdsfs_getattr(const char *path, struct stat *stbuf) return 0; } +static void zdsfs_read_device(struct dasd *newdasd, const char *device) +{ + struct errorlog *log; + int rc; + + rc = dasd_disk_reserve(device); + if (rc) { + fprintf(stderr, "error when reserving device %s: %s\n", + device, strerror(rc)); + lzds_dasd_get_errorlog(newdasd, &log); + lzds_errorlog_fprint(log, stderr); + exit(1); + } + rc = lzds_dasd_alloc_rawvtoc(newdasd); + if (rc) { + fprintf(stderr, "error when reading VTOC from device %s: %s\n", + device, strerror(rc)); + lzds_dasd_get_errorlog(newdasd, &log); + lzds_errorlog_fprint(log, stderr); + exit(1); + } + rc = lzds_zdsroot_extract_datasets_from_dasd(zdsfsinfo.zdsroot, + newdasd); + if (rc) { + fprintf(stderr, + "error when extracting data sets from dasd %s: %s\n", + device, strerror(rc)); + lzds_zdsroot_get_errorlog(zdsfsinfo.zdsroot, &log); + lzds_errorlog_fprint(log, stderr); + exit(1); + } + rc = dasd_disk_release(device); + if (rc) { + fprintf(stderr, "error when releasing device %s: %s\n", + device, strerror(rc)); + lzds_dasd_get_errorlog(newdasd, &log); + lzds_errorlog_fprint(log, stderr); + exit(1); + } +} + + static int zdsfs_statfs(const char *UNUSED(path), struct statvfs *statvfs) { struct dasditerator *dasdit; @@ -239,6 +283,33 @@ static int zdsfs_statfs(const char *UNUSED(path), struct statvfs *statvfs) return 0; } + +static int zdsfs_update_vtoc(void) +{ + struct dasditerator *dasdit; + struct dasd *dasd; + int rc; + + lzds_dslist_free(zdsfsinfo.zdsroot); + rc = lzds_zdsroot_alloc_dasditerator(zdsfsinfo.zdsroot, &dasdit); + if (rc) + return -ENOMEM; + + while (!lzds_dasditerator_get_next_dasd(dasdit, &dasd)) + zdsfs_read_device(dasd, dasd->device); + + lzds_dasditerator_free(dasdit); + rc = zdsfs_verify_datasets(); + if (rc) + return rc; + + rc = zdsfs_create_meta_data_buffer(&zdsfsinfo); + if (rc) + return rc; + + return 0; +} + static int zdsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t UNUSED(offset), struct fuse_file_info *UNUSED(fi)) { @@ -252,6 +323,10 @@ static int zdsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, int rc; int ispds, issupported; + rc = zdsfs_update_vtoc(); + if (rc) + return rc; + /* we have two type of directories * type one: the root directory contains all data sets */ @@ -328,6 +403,9 @@ static int zdsfs_open(const char *path, struct fuse_file_info *fi) goto error1; if (strcmp(path, "/"METADATAFILE) == 0) { + rc = zdsfs_update_vtoc(); + if (rc) + return rc; zfi->dsh = NULL; zfi->is_metadata_file = 1; zfi->metaread = 0; @@ -595,6 +673,7 @@ static int zdsfs_verify_datasets(void) if (rc) return ENOMEM; while (!lzds_dsiterator_get_next_dataset(dsit, &ds)) { + lzds_dataset_get_name(ds, &dsname); lzds_dataset_get_is_complete(ds, &iscomplete); if (!iscomplete) { lzds_dataset_get_name(ds, &dsname); @@ -821,23 +900,7 @@ static void zdsfs_process_device(const char *device) lzds_errorlog_fprint(log, stderr); exit(1); } - rc = lzds_dasd_read_rawvtoc(newdasd); - if (rc) { - fprintf(stderr, "error when reading VTOC from device %s:" - " %s\n", device, strerror(rc)); - lzds_dasd_get_errorlog(newdasd, &log); - lzds_errorlog_fprint(log, stderr); - exit(1); - } - rc = lzds_zdsroot_extract_datasets_from_dasd(zdsfsinfo.zdsroot, - newdasd); - if (rc) { - fprintf(stderr, "error when extracting data sets from dasd %s:" - " %s\n", device, strerror(rc)); - lzds_zdsroot_get_errorlog(zdsfsinfo.zdsroot, &log); - lzds_errorlog_fprint(log, stderr); - exit(1); - } + zdsfs_read_device(newdasd, device); } static void zdsfs_process_device_file(const char *devfile)