obj-$(CONFIG_VDS) := vds.o
vds-y := vds_blk.o vds_efi.o vds_io.o vds_label.o vds_main.o vds_reg.o \
- vds_vtoc.o
+ vds_vtoc.o vds_devid.o
struct workqueue_struct *ioq;
struct list_head io_list;
wait_queue_head_t wait;
+ void *devid;
+ int efi_rsvd_partnum;
+ umode_t mode;
};
#define VDS_PORT_SEQ 0x1
#define VDS_DEBUG_BIO 0x200
#define VDS_DEBUG_FIO 0x400
#define VDS_DEBUG_BELOCK 0x800
+#define VDS_DEBUG_DEVID 0x1000
extern int vds_dbg;
extern int vds_dbg_ldc;
--- /dev/null
+/*
+ * vds_devid.c: LDOM Virtual Disk Server.
+ *
+ * Copyright (C) 2017 Oracle. All rights reserved.
+ */
+
+#include "vds.h"
+#include "vds_io.h"
+#include "vds_devid.h"
+
+static short devid_gen_number;
+
+static u32 vds_devid_cksum(struct dk_devid *dkdevid)
+{
+ u32 chksum, *ip;
+ int i;
+
+ chksum = 0;
+ ip = (void *)dkdevid;
+ for (i = 0; i < ((DEVID_BLKSIZE - sizeof(int)) / sizeof(int)); i++)
+ chksum ^= ip[i];
+
+ return (chksum);
+}
+
+int vds_devid_valid(struct dk_devid *dkdevid)
+{
+ struct devid_info *id;
+ u16 type;
+ u32 chksum;
+
+ /* validate the revision */
+ if ((dkdevid->dkd_rev_hi != DEVID_REV_MSB) ||
+ (dkdevid->dkd_rev_lo != DEVID_REV_LSB))
+ return DEVID_RET_INVALID;
+
+ /* compute checksum */
+ chksum = vds_devid_cksum(dkdevid);
+
+ /* compare the checksums */
+ if (DEVID_GETCHKSUM(dkdevid) != chksum)
+ return DEVID_RET_INVALID;
+
+ id = (struct devid_info *)dkdevid->dkd_devid;
+
+ if (id->did_magic_hi != DEVID_MAGIC_MSB)
+ return (DEVID_RET_INVALID);
+
+ if (id->did_magic_lo != DEVID_MAGIC_LSB)
+ return (DEVID_RET_INVALID);
+
+ if (id->did_rev_hi != DEVID_REV_MSB)
+ return (DEVID_RET_INVALID);
+
+ if (id->did_rev_lo != DEVID_REV_LSB)
+ return (DEVID_RET_INVALID);
+
+ type = DEVID_GETTYPE(id);
+ if ((type == DEVID_NONE) || (type > DEVID_MAXTYPE))
+ return (DEVID_RET_INVALID);
+
+ return (DEVID_RET_VALID);
+}
+
+/*
+ * Return the sizeof a device id. If called with NULL devid it returns
+ * the amount of space needed to determine the size.
+ */
+size_t vds_devid_sizeof(struct devid_info *id)
+{
+ if (id == NULL)
+ return (sizeof (*id) - sizeof (id->did_id));
+
+ return (sizeof (*id) + DEVID_GETLEN(id) - sizeof (id->did_id));
+}
+
+static int vds_devid_init(u16 devid_type, u16 nbytes, void *id,
+ struct devid_info *i_devid, u32 hostid)
+{
+ int sz = sizeof (*i_devid) + nbytes - sizeof (char);
+ int driver_len;
+ const char *driver_name;
+
+ switch (devid_type) {
+ case DEVID_ENCAP:
+ if (nbytes == 0)
+ return (-1);
+ if (id == NULL)
+ return (-1);
+ break;
+ case DEVID_FAB:
+ if (nbytes != 0)
+ return (-1);
+ if (id != NULL)
+ return (-1);
+ nbytes = sizeof (int) +
+ DEVID_TIMEVAL_SIZE + sizeof(short);
+ sz += nbytes;
+ break;
+ default:
+ return (-1);
+ }
+
+ i_devid->did_magic_hi = DEVID_MAGIC_MSB;
+ i_devid->did_magic_lo = DEVID_MAGIC_LSB;
+ i_devid->did_rev_hi = DEVID_REV_MSB;
+ i_devid->did_rev_lo = DEVID_REV_LSB;
+ DEVID_FORMTYPE(i_devid, devid_type);
+ DEVID_FORMLEN(i_devid, nbytes);
+
+ /* Fill in driver name hint */
+ driver_name = "vds";
+ driver_len = strlen(driver_name);
+ if (driver_len > DEVID_HINT_SIZE) {
+ /* Pick up last four characters of driver name */
+ driver_name += driver_len - DEVID_HINT_SIZE;
+ driver_len = DEVID_HINT_SIZE;
+ }
+
+ memcpy(i_devid->did_driver, driver_name, driver_len);
+
+ /* Fill in id field */
+ if (devid_type == DEVID_FAB) {
+ char *cp;
+ struct timeval now;
+ short gen;
+ u32 hi, lo;
+
+ gen = devid_gen_number++;
+
+ cp = i_devid->did_id;
+
+ *cp++ = hibyte(hiword(hostid));
+ *cp++ = lobyte(hiword(hostid));
+ *cp++ = hibyte(loword(hostid));
+ *cp++ = lobyte(loword(hostid));
+
+ do_gettimeofday(&now);
+
+ hi = now.tv_sec;
+ *cp++ = hibyte(hiword(hi));
+ *cp++ = lobyte(hiword(hi));
+ *cp++ = hibyte(loword(hi));
+ *cp++ = lobyte(loword(hi));
+ lo = now.tv_usec;
+ *cp++ = hibyte(hiword(lo));
+ *cp++ = lobyte(hiword(lo));
+ *cp++ = hibyte(loword(lo));
+ *cp++ = lobyte(loword(lo));
+
+ /* fill in the generation number */
+ *cp++ = hibyte(gen);
+ *cp++ = lobyte(gen);
+ vds_devid_dump((u8 *)i_devid, 26, (void *)i_devid,
+ "vds_devid_init:");
+ } else
+ memcpy(i_devid->did_id, id, nbytes);
+
+ return (0);
+}
+
+void vds_devid_dump(unsigned char *buf, int count, void *address, char *info)
+{
+ int i, j;
+ char bp[256];
+
+ if ((vds_dbg & VDS_DEBUG_DEVID) == 0)
+ return;
+
+ if (info != NULL)
+ pr_warn("%s\n", info);
+
+ memset(bp, 0, 256);
+
+ for (i = j = 0; i < count; i++, j++) {
+ if (j == 16) {
+ j = 0;
+ pr_warn("%s\n", bp);
+ memset(bp, 0, 256);
+ }
+ if (j == 0)
+ sprintf(&bp[strlen(bp)], "%p: ", address+i);
+ sprintf(&bp[strlen(bp)], "%02x ", buf[i]);
+ }
+ if (j != 0)
+ pr_warn("%s\n", bp);
+}
+
+static int vds_dskimg_get_devid_block(struct vds_port *port, size_t *blkp)
+{
+ struct vio_driver_state *vio = &port->vio;
+ unsigned long long spc, head, cyl;
+
+ vdsdbg(DEVID, "port->label_type=%x\n", port->label_type);
+
+ if (port->label_type == VDS_LABEL_EFI) {
+ vdsdbg(DEVID, "efi_rsvd_partnum=%x\n", port->efi_rsvd_partnum);
+ /*
+ * For an EFI disk, the devid is at the beginning of
+ * the reserved slice
+ */
+ if (port->efi_rsvd_partnum == -1) {
+ vdsdbg(DEVID, "EFI disk has no reserved slice\n");
+ return (-ENOSPC);
+ }
+ *blkp = port->part[port->efi_rsvd_partnum].start;
+ } else if (port->label_type == VDS_LABEL_VTOC) {
+ if (port->geom->alt_cyl < 2) {
+ vdsdbg(DEVID,
+ "not enough alt cylinders for devid (acyl=%u)\n",
+ port->geom->alt_cyl);
+ return (-ENOSPC);
+ }
+
+ /* the devid is in on the track next to the last cylinder */
+ cyl = port->geom->num_cyl + port->geom->alt_cyl - 2;
+ spc = port->geom->num_hd * port->geom->num_sec;
+ head = port->geom->num_hd - 1;
+
+ *blkp = (cyl * (spc - port->geom->apc)) +
+ (head * port->geom->num_sec) + 1;
+ } else {
+ /* unknown disk label */
+ return (-ENOENT);
+ }
+
+ vdsdbg(DEVID, "devid block: %ld\n", *blkp);
+
+ return 0;
+}
+
+static int vds_dskimg_read_devid(struct vds_port *port,
+ struct devid_info *devid)
+{
+ struct vio_driver_state *vio = &port->vio;
+ struct dk_devid *dkdevid;
+ size_t blk;
+ int sz;
+ int rv = 0;
+
+ rv = vds_dskimg_get_devid_block(port, &blk);
+ if (rv)
+ return rv;
+
+ dkdevid = kzalloc(DEVID_BLKSIZE, GFP_ATOMIC);
+
+ /* get the devid */
+ rv = vds_read(port, (void *)dkdevid, blk, DEVID_BLKSIZE);
+ if (rv) {
+ rv = -EIO;
+ goto done;
+ }
+
+ vds_devid_dump((u8 *)dkdevid, DEVID_BLKSIZE, (void *)dkdevid,
+ "dkdevid:");
+
+ /* validate the device id */
+ if (vds_devid_valid(dkdevid) != 0) {
+ vdsdbg(DEVID, "invalid devid found at block %lu\n", blk);
+ rv = -EINVAL;
+ goto done;
+ }
+
+ vdsdbg(DEVID, "devid read at block %lu\n", blk);
+
+ sz = vds_devid_sizeof((struct devid_info *)dkdevid->dkd_devid);
+ if ((sz > 0) && (sz <= DEVID_BLKSIZE)) {
+ memcpy(devid, dkdevid->dkd_devid, sz);
+ vds_devid_dump((u8 *)devid, sz, (void *)devid, "devid:");
+ }
+ rv = 0;
+done:
+ kfree(dkdevid);
+ return rv;
+
+}
+
+int vds_dskimg_write_devid(struct vds_port *port)
+{
+ struct vio_driver_state *vio = &port->vio;
+ struct dk_devid *dkdevid;
+ struct devid_info *devid = port->devid;
+ u32 chksum;
+ size_t blk;
+ int rv;
+
+ vdsdbg(DEVID, "%s: label_type=%x, devid=%p\n", port->path,
+ port->label_type, devid);
+
+ if (devid == NULL) {
+ /* nothing to write */
+ return 0;
+ }
+
+ rv = vds_dskimg_get_devid_block(port, &blk);
+ if (rv)
+ return -EIO;
+
+ dkdevid = kzalloc(DEVID_BLKSIZE, GFP_ATOMIC);
+
+ /* set revision */
+ dkdevid->dkd_rev_hi = DEVID_REV_MSB;
+ dkdevid->dkd_rev_lo = DEVID_REV_LSB;
+
+ /* copy devid */
+ memcpy(&dkdevid->dkd_devid, devid, vds_devid_sizeof(devid));
+
+ /* compute checksum */
+ chksum = vds_devid_cksum(dkdevid);
+
+ /* set checksum */
+ DEVID_SETCHKSUM(chksum, dkdevid);
+
+ vdsdbg(DEVID, "dkdevid: blk=%ld\n", blk);
+ vds_devid_dump((u8 *)dkdevid, DEVID_BLKSIZE, (void *)dkdevid, NULL);
+
+ /* store the devid */
+ rv = vds_write(port, (void *)dkdevid, blk, DEVID_BLKSIZE);
+ if (rv < 0) {
+ vdsdbg(DEVID, "Error writing devid block at %lu\n", blk);
+ rv = -EIO;
+ } else {
+ vdsdbg(DEVID, "devid written at block %lu\n", blk);
+ rv = 0;
+ }
+
+ kfree(dkdevid);
+ return rv;
+}
+
+int vds_dskimg_init_devid(struct vds_port *port)
+{
+ struct vio_driver_state *vio = &port->vio;
+ int status;
+
+ /* Setup devid for the disk image */
+
+ vdsdbg(DEVID, "%s: label_type=%x\n", port->path, port->label_type);
+
+ if (!S_ISREG(port->mode)) /* Handle disk image only */
+ return 0;
+
+ port->devid = kzalloc(DEVID_BLKSIZE, GFP_KERNEL);
+
+ status = vds_dskimg_read_devid(port, port->devid);
+
+ vdsdbg(DEVID, "read & validate disk image devid, status=%d\n",
+ status);
+ if (status == 0) {
+ /* a valid devid was found */
+ return 0;
+ }
+
+ if (status == -EIO) {
+ /*
+ * There was an error while trying to read the devid.
+ * So this disk image may have a devid but we are
+ * unable to read it.
+ */
+ vdsdbg(DEVID, "cannot read devid\n");
+ kfree(port->devid);
+ port->devid = NULL;
+ return status;
+ }
+
+ /* No valid device id was found so create one. */
+
+ vdsdbg(DEVID, "creating devid\n");
+
+ memset(port->devid, 0, DEVID_BLKSIZE);
+
+ if (vds_devid_init(DEVID_FAB, 0, NULL,
+ (struct devid_info *)port->devid, vds_hostid) != 0) {
+ vdsdbg(DEVID, "fail to create devid\n");
+ kfree(port->devid);
+ port->devid = NULL;
+ return -EINVAL;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * vds_devid.h: LDOM Virtual Disk Server.
+ *
+ * Copyright (C) 2017 Oracle. All rights reserved.
+ */
+
+/*
+ * Device id types
+ */
+#define DEVID_NONE 0
+#define DEVID_SCSI3_WWN 1
+#define DEVID_SCSI_SERIAL 2
+#define DEVID_FAB 3
+#define DEVID_ENCAP 4
+#define DEVID_ATA_SERIAL 5
+#define DEVID_SCSI3_VPD_T10 6
+#define DEVID_SCSI3_VPD_EUI 7
+#define DEVID_SCSI3_VPD_NAA 8
+#define DEVID_BLOCK 9
+#define DEVID_PCI_SERIAL 10
+#define DEVID_MAXTYPE 10
+
+
+/*
+ * Layout of stored fabricated device id (on-disk)
+ */
+#define DEVID_BLKSIZE (512)
+#define DEVID_SIZE (DEVID_BLKSIZE - ((sizeof(u8) * 7)))
+
+struct dk_devid {
+ u8 dkd_rev_hi; /* revision (MSB) */
+ u8 dkd_rev_lo; /* revision (LSB) */
+ u8 dkd_flags; /* flags (not used yet) */
+ u8 dkd_devid[DEVID_SIZE]; /* devid stored here */
+ u8 dkd_checksum3; /* checksum (MSB) */
+ u8 dkd_checksum2;
+ u8 dkd_checksum1;
+ u8 dkd_checksum0; /* checksum (LSB) */
+};
+
+#define DEVID_TIMEVAL_SIZE 8
+
+#ifdef __LITTLE_ENDIAN
+#define lobyte(X) (((unsigned char *)&(X))[0])
+#define hibyte(X) (((unsigned char *)&(X))[1])
+#define loword(X) (((unsigned short *)&(X))[0])
+#define hiword(X) (((unsigned short *)&(X))[1])
+#endif
+#ifdef __BIG_ENDIAN
+#define lobyte(X) (((unsigned char *)&(X))[1])
+#define hibyte(X) (((unsigned char *)&(X))[0])
+#define loword(X) (((unsigned short *)&(X))[1])
+#define hiword(X) (((unsigned short *)&(X))[0])
+#endif
+
+#define DEVID_GETCHKSUM(dkd) \
+ (((dkd)->dkd_checksum3 << 24) + \
+ ((dkd)->dkd_checksum2 << 16) + \
+ ((dkd)->dkd_checksum1 << 8) + \
+ ((dkd)->dkd_checksum0))
+
+#define DEVID_SETCHKSUM(c, dkd) \
+ do { \
+ (dkd)->dkd_checksum3 = hibyte(hiword((c))); \
+ (dkd)->dkd_checksum2 = lobyte(hiword((c))); \
+ (dkd)->dkd_checksum1 = hibyte(loword((c))); \
+ (dkd)->dkd_checksum0 = lobyte(loword((c))); \
+ } while (0)
+
+/*
+ * Device id - Internal definition.
+ */
+#define DEVID_MAGIC_MSB 0x69
+#define DEVID_MAGIC_LSB 0x64
+#define DEVID_REV_MSB 0x00
+#define DEVID_REV_LSB 0x01
+#define DEVID_HINT_SIZE 4
+
+struct devid_info {
+ u8 did_magic_hi; /* device id magic # (msb) */
+ u8 did_magic_lo; /* device id magic # (lsb) */
+ u8 did_rev_hi; /* device id revision # (msb) */
+ u8 did_rev_lo; /* device id revision # (lsb) */
+ u8 did_type_hi; /* device id type (msb) */
+ u8 did_type_lo; /* device id type (lsb) */
+ u8 did_len_hi; /* length of devid data (msb) */
+ u8 did_len_lo; /* length of devid data (lsb) */
+ char did_driver[DEVID_HINT_SIZE]; /* driver name - HINT */
+ char did_id[1]; /* start of device id data */
+};
+
+#define NBBY 8
+
+#define DEVID_GETTYPE(devid) ((u16) \
+ (((devid)->did_type_hi << NBBY) + \
+ (devid)->did_type_lo))
+
+#define DEVID_FORMTYPE(devid, type) (devid)->did_type_hi = \
+ ((type) >> NBBY) & 0xFF; \
+ (devid)->did_type_lo = \
+ (type) & 0xFF;
+
+#define DEVID_GETLEN(devid) ((u16) \
+ (((devid)->did_len_hi << NBBY) + \
+ (devid)->did_len_lo))
+
+#define DEVID_FORMLEN(devid, len) (devid)->did_len_hi = \
+ ((len) >> NBBY) & 0xFF; \
+ (devid)->did_len_lo = \
+ (len) & 0xFF;
+
+#define DEVID_RET_VALID 0
+#define DEVID_RET_INVALID (-1)
+
+struct efi_uuid {
+ u32 time_low;
+ u16 time_mid;
+ u16 time_hi_and_version;
+ u8 clk_node_addr[8];
+};
+
+typedef struct efi_uuid efi_uuid_t;
+
+#define EFI_RESERVED { 0x6a945a3b, 0x1dd2, 0x11b2, \
+ { 0x99, 0xa6, 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
+
+int vds_dskimg_init_devid(struct vds_port *port);
+int vds_dskimg_write_devid(struct vds_port *port);
+size_t vds_devid_sizeof(struct devid_info *id);
+void vds_devid_dump(unsigned char *buf, int count, void *address, char *info);
+
+extern u32 vds_hostid;
+extern void do_gettimeofday(struct timeval *tv);
/*
* vds_vtoc.c: LDOM Virtual Disk Server.
*
- * Copyright (C) 2014 Oracle. All rights reserved.
+ * Copyright (C) 2014, 2017 Oracle. All rights reserved.
*/
#include "vds.h"
#include "vds_io.h"
+#include "vds_devid.h"
+
#include <../block/partitions/check.h>
#include <../block/partitions/efi.h>
#include <linux/byteorder/generic.h>
(unsigned char *)gpt, le32_to_cpu(gpt->header_size));
}
+static bool efi_guid_found(efi_uuid_t *guidp, efi_uuid_t *uuidp)
+{
+ u32 time_low;
+ u16 time_hi_and_version, time_mid;
+
+ time_low = le32_to_cpu(uuidp->time_low);
+ time_mid = le16_to_cpu(uuidp->time_mid);
+ time_hi_and_version = le16_to_cpu(uuidp->time_hi_and_version);
+
+ if ((guidp->time_low == time_low) && (guidp->time_mid == time_mid) &&
+ (guidp->time_hi_and_version == time_hi_and_version)) {
+
+ if (memcmp(guidp->clk_node_addr, uuidp->clk_node_addr,
+ sizeof(guidp->clk_node_addr)) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
static void vds_efi_update_part(struct vds_port *port, gpt_entry *gpe)
{
int i;
u64 start, end;
+ efi_guid_t *guidp;
+ efi_uuid_t efi_reserved = EFI_RESERVED;
vds_label_clear_part(port);
if (start && end) {
port->part[i].start = start;
port->part[i].size = end - start + 1;
+
+ guidp = &gpe[i].partition_type_guid;
+ if (efi_guid_found((efi_uuid_t *)guidp, &efi_reserved))
+ port->efi_rsvd_partnum = i;
}
}
}
gpt_entry *gpe = NULL;
struct vio_driver_state *vio = &port->vio;
+ port->efi_rsvd_partnum = -1;
+
/*
* Validate GPT and update partition info.
*/
vdsmsg(err, "write EFI label failed: rv=%d\n", err);
} else if (lba == VDS_EFI_GPT) {
rv = vds_efi_validate(port);
- if (rv)
+ if (rv) {
/*
* To convert from EFI to VTOC, Solaris format(1M)
* clears the EFI signature, issues a GETGEOM command
* ignore invalid signature errors here just in case.
*/
vdsdbg(IOC, "read EFI label failed: rv=%d\n", rv);
+
+ } else if (S_ISREG(port->mode)) {
+ /*
+ * When the disk label changes then the location where
+ * the devid is stored on a disk image can change.
+ */
+ rv = vds_dskimg_write_devid(port);
+ if (rv) {
+ /* EFI was set, though devid write failed */
+ vdsdbg(DEVID,
+ "vds_efi_set: fail to write devid: rv=%d\n",
+ rv);
+ }
+ }
}
return err;
#include "vds.h"
#include "vds_io.h"
+#include "vds_devid.h"
#define VDS_MAX_XFER_SIZE (128 * 1024)
#define VDS_RETRIES 5
return rv;
}
+int vd_op_get_devid(struct vds_io *io)
+{
+ int rv;
+ struct vio_driver_state *vio = io->vio;
+ struct vds_port *port = to_vds_port(vio);
+ struct vio_disk_devid *devid_outp = NULL;
+ struct devid_info *devid;
+ int devid_len;
+
+ /* FIXME - add support for block special */
+ if (!S_ISREG(port->mode))
+ return 0;
+
+ if (port->devid == NULL) {
+ vdsdbg(DEVID, "VD_OP_GET_DEVID devid not found\n");
+ return (-ENXIO);
+ }
+
+ devid_outp = kzalloc(roundup(io->desc->size, 8), GFP_KERNEL);
+ if (devid_outp == NULL)
+ return (-ENOMEM);
+
+ devid = (struct devid_info *)port->devid;
+ vdsdbg(DEVID, "port->devid:");
+ vds_devid_dump((u8 *)devid, 26, (void *)devid, NULL);
+
+ devid_len = DEVID_GETLEN(devid);
+
+ devid_outp->type = DEVID_GETTYPE(devid);
+ devid_outp->len = devid_len;
+ memcpy(devid_outp->id, devid->did_id, devid_len);
+
+ vdsdbg(DEVID, "devid struct: type=0x%x, len=%d\n",
+ devid_outp->type, devid_outp->len);
+ vds_devid_dump((u8 *)devid_outp, sizeof(devid_outp),
+ (void *)devid_outp, "devid_outp:");
+ vds_devid_dump((u8 *)devid_outp->id, devid_outp->len,
+ (void *)devid_outp->id, "devid_outp->id:");
+
+ rv = vds_copy(vio, LDC_COPY_OUT, devid_outp, io->desc, 0, 0);
+
+ vdsdbg(DEVID, "VD_OP_GET_DEVID rv=%d\n", rv);
+
+ kfree(devid_outp);
+
+ return rv;
+}
+
int vd_op_get_efi(struct vds_io *io)
{
int rv;
return err;
}
+static int vds_be_init_devid(struct vds_port *port)
+{
+ int rv;
+
+ if (S_ISREG(port->mode)) {
+ rv = vds_dskimg_init_devid(port);
+ } else {
+ /*
+ * We should support devid for other backends. For now,
+ * we only support devid for disk images backed by a
+ * file.
+ */
+ rv = 0;
+ }
+
+ return rv;
+}
+
/*
* Backend operations.
*/
inode = path.dentry->d_inode;
mode = inode->i_mode;
+ port->mode = mode;
path_put(&path);
vds_be_wlock(port);
vds_label_init(port);
+ /*
+ * Failure to create a device id is not fatal and does not
+ * prevent the disk image from being attached.
+ */
+ (void) vds_be_init_devid(port);
+ rv = 0;
+
done:
if (be_lock == read)
vds_be_runlock(port);
port->be_ops->fini(port);
port->be_data = NULL;
}
+ kfree(port->devid);
+ port->devid = NULL;
vds_be_wunlock(port);
}
/*
* vds_io.h: LDOM Virtual Disk Server.
*
- * Copyright (C) 2014, 2015 Oracle. All rights reserved.
+ * Copyright (C) 2014, 2017 Oracle. All rights reserved.
*/
struct vds_port;
int vd_op_set_vtoc(struct vds_io *io);
int vd_op_get_geom(struct vds_io *io);
int vd_op_set_geom(struct vds_io *io);
+int vd_op_get_devid(struct vds_io *io);
int vd_op_get_efi(struct vds_io *io);
int vd_op_set_efi(struct vds_io *io);
int vd_op_flush(struct vds_io *io);
1 << VD_OP_SET_VTOC | \
1 << VD_OP_GET_DISKGEOM | \
1 << VD_OP_SET_DISKGEOM | \
+ 1 << VD_OP_GET_DEVID | \
1 << VD_OP_GET_EFI | \
1 << VD_OP_SET_EFI | \
1 << VD_OP_FLUSH)
int vds_dbg;
int vds_dbg_ldc;
int vds_dbg_vio;
+u32 vds_hostid;
module_param(vds_dbg, uint, 0664);
module_param(vds_dbg_ldc, uint, 0664);
{ VD_OP_SET_VTOC, WRITE, vd_op_set_vtoc },
{ VD_OP_GET_DISKGEOM, READ, vd_op_get_geom },
{ VD_OP_SET_DISKGEOM, WRITE, vd_op_set_geom },
+ { VD_OP_GET_DEVID, READ, vd_op_get_devid },
{ VD_OP_GET_EFI, READ, vd_op_get_efi },
{ VD_OP_SET_EFI, WRITE, vd_op_set_efi },
{ VD_OP_FLUSH, WRITE, vd_op_flush }
static int __init vds_init(void)
{
+ struct mdesc_handle *hp;
+ const u64 *val;
+ u64 node;
int rv;
rv = vds_io_init();
- if (!rv) {
- rv = vio_register_driver(&vds_port_driver);
- if (rv < 0)
- vds_io_fini();
+ if (rv)
+ return rv;
+
+ rv = vio_register_driver(&vds_port_driver);
+ if (rv < 0) {
+ vds_io_fini();
+ return rv;
+ }
+ hp = mdesc_grab();
+ node = mdesc_node_by_name(hp, MDESC_NODE_NULL, "platform");
+ if (node != MDESC_NODE_NULL) {
+ val = mdesc_get_property(hp, node, "hostid", NULL);
+ if (val != NULL)
+ vds_hostid = *val;
+ else
+ pr_warn("vds_init: Can't find hostid property.\n");
+ } else {
+ pr_warn("vds_init: Can't find platform node in machine-description.\n");
}
- return rv;
+ return 0;
}
static void __exit vds_exit(void)
#include "vds.h"
#include "vds_io.h"
#include "vds_vtoc.h"
+#include "vds_devid.h"
/*
* By Solaris convention, slice/partition 2 represents the entire disk;
{
int i, rv;
struct dk_label *label;
+ struct vio_driver_state *vio = &port->vio;
rv = vds_vtoc_get_label(port, &label);
if (!label)
port->label_type = VDS_LABEL_VTOC;
port->npart = label->dkl_vtoc.v_nparts;
vds_vtoc_update_part(port, label);
+ /*
+ * When the disk label changes then the location where
+ * the devid is stored on a disk image can change.
+ */
+ if (S_ISREG(port->mode)) {
+ rv = vds_dskimg_write_devid(port);
+ if (rv) {
+ vdsdbg(DEVID,
+ "vds_vtoc_set: fail to write devid\n");
+
+ /* vtoc was set, though devid write failed */
+ rv = 0;
+ }
+ }
}
/*