diff mbox series

[v18,64/83] sg: device timestamp

Message ID 20210427215733.417746-66-dgilbert@interlog.com (mailing list archive)
State Deferred
Headers show
Series sg: add v4 interface, request sharing | expand

Commit Message

Douglas Gilbert April 27, 2021, 9:57 p.m. UTC
Add timestamp to each sg_device object that is written when the
object is created. The timestamp is the number nanoseconds since
the boot time of the machine.

The purpose is to allow the user to detect, via the extended
ioctl()s SG_SEIRV_DEV_TS_LOWER and SG_SEIRV_DEV_TS_UPPER, if
a given sg device object (e.g. /dev/sg3) may have possibly
changed. One worrisome scenario is when a device disappears
and a newly connected device takes the same sg device object
number (e.g. /dev/sg3) as the recently disappeared device.
Linux gives no guarantees that this type of behaviour will
_not_ happen. Recording the device creation timestamp is one
way an application can detect when this happens.

The uptime command in Linux shows, in humanly readable form,
how long a machine has been "up", that is the time that has
elapsed since the machine was started or "rebooted".

Signed-off-by: Douglas Gilbert <dgilbert@interlog.com>
---
 drivers/scsi/sg.c      | 8 ++++++++
 include/uapi/scsi/sg.h | 2 ++
 2 files changed, 10 insertions(+)
diff mbox series

Patch

diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index c401047cae70..dc85592112e2 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -308,6 +308,7 @@  struct sg_device { /* holds the state of each scsi generic device */
 	int max_sgat_elems;     /* adapter's max number of elements in sgat */
 	int max_sgat_sz;	/* max number of bytes in sgat list */
 	u32 index;		/* device index number */
+	u64 create_ns;		/* nanoseconds since bootup device created */
 	atomic_t open_cnt;	/* count of opens (perhaps < num(sfds) ) */
 	unsigned long fdev_bm[1];	/* see SG_FDEV_* defines above */
 	struct gendisk *disk;
@@ -4462,6 +4463,12 @@  sg_extended_read_value(struct sg_fd *sfp, struct sg_extended_info *seip)
 	case SG_SEIRV_MAX_RSV_REQS:
 		seip->read_value = SG_MAX_RSV_REQS;
 		break;
+	case SG_SEIRV_DEV_TS_LOWER:	/* timestamp is 64 bits */
+		seip->read_value = sfp->parentdp->create_ns & U32_MAX;
+		break;
+	case SG_SEIRV_DEV_TS_UPPER:
+		seip->read_value = (sfp->parentdp->create_ns >> 32) & U32_MAX;
+		break;
 	default:
 		SG_LOG(6, sfp, "%s: can't decode %d --> read_value\n",
 		       __func__, seip->read_value);
@@ -5530,6 +5537,7 @@  sg_add_device(struct device *cl_dev, struct class_interface *cl_intf)
 	} else
 		pr_warn("%s: sg_sys Invalid\n", __func__);
 
+	sdp->create_ns = ktime_get_boottime_ns();
 	sg_calc_sgat_param(sdp);
 	sdev_printk(KERN_NOTICE, scsidp, "Attached scsi generic sg%d "
 		    "type %d\n", sdp->index, scsidp->type);
diff --git a/include/uapi/scsi/sg.h b/include/uapi/scsi/sg.h
index a1f35fd34816..a3f3d244d2af 100644
--- a/include/uapi/scsi/sg.h
+++ b/include/uapi/scsi/sg.h
@@ -223,6 +223,8 @@  typedef struct sg_req_info {	/* used by SG_GET_REQUEST_TABLE ioctl() */
 #define SG_SEIRV_SUBMITTED	0x5	/* number of mrqs submitted+unread */
 #define SG_SEIRV_DEV_SUBMITTED	0x6	/* sum(submitted) on all dev's fds */
 #define SG_SEIRV_MAX_RSV_REQS	0x7	/* maximum reserve requests */
+#define SG_SEIRV_DEV_TS_LOWER	0x8	/* device timestamp's lower 32 bits */
+#define SG_SEIRV_DEV_TS_UPPER	0x9	/* device timestamp's upper 32 bits */
 
 /*
  * A pointer to the following structure is passed as the third argument to