NVMe path failover update
cover NVMe path failover update
Hi all,
the current NVMe support is fairly rudimentary, and we've had reports about spurious path failures under high load.
Which is a bit disappointing, seeing that high load is exactly what NVMe is about ...
So here's a patchset to clean up the situation somewhat.
In particular:
- I've fixed up the discovery to fall in line with the other transports, like filling out the sg_id fields (so that we're not greeted with weird hashes in the topology output)
- I've added a 'none' checker, which doesn't do anything but rather returns the passed-in path state. Thing is, NVMe keeps the 'state' attribute in sync with the actual operation, so we can rely on that to reflect the current state of the connection. As we're evaluating this state via the path_offline() call prior to calling any checker there's no need for a checker whatsoever, and we can use the 'state' attribute as-is. Which is what the 'none' checker does.
Incidentally, we _might_ get away with using the 'none' checker for FC, too; but this is to be tested.
As usual, comments and reviews are welcome.
Hannes Reinecke (4):
discovery: sanitize NVMe discovery
libmultipath/discovery: modify NVMe path states
Add 'none' checker
hwtable: set 'none' as default checker for NVMe
libmultipath/checkers.c | 22 +++++++++++++------ libmultipath/checkers.h | 3 ++- libmultipath/discovery.c | 54 +++++++++++++++++++++++++++------------------- libmultipath/discovery.h | 2 +- libmultipath/hwtable.c | 2 +- multipath/multipath.conf.5 | 3 +++ multipathd/main.c | 2 +- 7 files changed, 56 insertions(+), 32 deletions(-)
Signature · 1 line
1.8.5.6
PATCH 1/4 discovery: sanitize NVMe discovery
Bring the output of NVMe discovery inline with the other transports, and set the sg_id mappings to avoid ugly '#' outputs.
--- libmultipath/discovery.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-)
libmultipath/discovery.c +25 -16
@@ -1194,28 +1194,37 @@ scsi_sysfs_pathinfo (struct path * pp, vector hwtable)static int nvme_sysfs_pathinfo (struct path * pp,vector hwtable) { -struct udev_device *parent, *nvme =NULL ; +struct udev_device *parent; +const char *attr_path =NULL ; - parent = pp->udev; -while (parent) { -const char *subsys =udev_device_get_subsystem (parent); + attr_path =udev_device_get_sysname (pp->udev); +if (!attr_path) +return 1 ; -if (subsys && !strncmp (subsys,"nvme" ,4 )) { - nvme = parent; -break ; - } - parent =udev_device_get_parent (parent); - } -if (!nvme) +if (sscanf (attr_path,"nvme%dn%d" , + &pp->sg_id.host_no, + &pp->sg_id.scsi_id) !=2 ) +return 1 ; + pp->sg_id.channel =0 ; + pp->sg_id.lun =0 ; + + parent =udev_device_get_parent (pp->udev); +if (!parent)return 1 ;snprintf (pp->vendor_id,SCSI_VENDOR_SIZE ,"NVME" ); -snprintf (pp->product_id,SCSI_PRODUCT_SIZE ,"%s" ,udev_device_get_sysattr_value (nvme,"model" )); -snprintf (pp->serial,SERIAL_SIZE ,"%s" ,udev_device_get_sysattr_value (nvme,"serial" )); -snprintf (pp->rev,SCSI_REV_SIZE ,"%s" ,udev_device_get_sysattr_value (nvme,"firmware_rev" )); +snprintf (pp->product_id,SCSI_PRODUCT_SIZE ,"%s" , +udev_device_get_sysattr_value (parent,"model" )); +snprintf (pp->serial,SERIAL_SIZE ,"%s" , +udev_device_get_sysattr_value (parent,"serial" )); +snprintf (pp->rev,SCSI_REV_SIZE ,"%s" , +udev_device_get_sysattr_value (parent,"firmware_rev" )); + +condlog (3 ,"%s: vendor = %s" , pp->dev, pp->vendor_id); +condlog (3 ,"%s: product = %s" , pp->dev, pp->product_id); +condlog (3 ,"%s: serial = %s" , pp->dev, pp->serial); +condlog (3 ,"%s: rev = %s" , pp->dev, pp->rev); -condlog (3 ,"%s: vendor:%s product:%s serial:%s rev:%s" , pp->dev, - pp->vendor_id, pp->product_id, pp->serial, pp->rev); pp->hwe =find_hwe (hwtable, pp->vendor_id, pp->product_id,NULL );return 0 ;
Signature · 1 line
1.8.5.6
Re: [PATCH 1/4] discovery: sanitize NVMe discovery
Quoted 6 lines · Hannes Reinecke
Bring the output of NVMe discovery inline with the other transports, and set the
sg_idmappings to avoid ugly '#' outputs.Signed-off-by Hannes Reinecke <[email protected]>---
libmultipath/discovery.c scsi_sysfs_pathinfo (struct path * pp, vector hwtable) · line 1210
Quoted 9 lines
libmultipath/discovery.c +7
-2- } -if (!nvme) +if (sscanf (attr_path,"nvme%dn%d" , + &pp->sg_id.host_no, + &pp->sg_id.scsi_id) !=2 ) +return 1 ; + pp->sg_id.channel =0 ; + pp->sg_id.lun =0 ; +
As seen in PATCH0/4, it's better to use nvme_id fields which shows the true topology of NVMe/NVMf storage something like this: host NQN ->portid->subsytem NQN -> controller ID ->namespace id .
The NQN is too long may be we could select the last few bytes.
However, your current method looks fine. And some suggestions:
(1)How about assigning sg_id.channel to controller id of target (seen in the /sys/class/nvme/nvme0/nvme0n1/device/cntlid)
(2)And assigning sg_id.lun to namespace ID of target(seen in the :/sys/class/nvme/nvme0/nvme0n1/nsid)
Re: [PATCH 1/4] discovery: sanitize NVMe discovery
Quoted 25 lines · Guan Junxiong
Quoted 6 lines · Hannes Reinecke
Bring the output of NVMe discovery inline with the other transports, and set the
sg_idmappings to avoid ugly '#' outputs.Signed-off-by Hannes Reinecke <[email protected]>---
libmultipath/discovery.c scsi_sysfs_pathinfo (struct path * pp, vector hwtable) · line 1210
Quoted 9 lines
libmultipath/discovery.c +7
-2- } -if (!nvme) +if (sscanf (attr_path,"nvme%dn%d" , + &pp->sg_id.host_no, + &pp->sg_id.scsi_id) !=2 ) +return 1 ; + pp->sg_id.channel =0 ; + pp->sg_id.lun =0 ; +As seen in PATCH0/4, it's better to use
nvme_idfields which shows the true topology of NVMe/NVMf storage something like this: host NQN ->portid->subsytem NQN -> controller ID ->namespace id .
The NQN is too long may be we could select the last few bytes.
Quoted 7 lines
However, your current method looks fine. And some suggestions:
(1)How about assigning sg_id.channel to controller id of target (seen in the
/sys/class/nvme/nvme0/nvme0n1/device/cntlid)
(2)And assigning sg_id.lun to namespace ID of target(seen in the :/sys/class/nvme/nvme0/nvme0n1/nsid)
Sure, good idea. The above patch was just a stop-gap measure to get rid of the '#' in the topology output.
Will be updating the patch.
Cheers,
Hannes
Signature · 10 lines
Dr. Hannes Reinecke Teamlead Storage & Networking [email protected] +49 911 74053 688 SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton HRB 21284 (AG Nürnberg) -- dm-devel mailing list [email protected] https://www.redhat.com/mailman/listinfo/dm-devel
PATCH 2/4 libmultipath/discovery: modify NVMe path states
In reply to Hannes ReineckeThe NVMe path states 'resetting' and 'reconnecting' indicate that the controller could not talk to the namespace, which translates into a path down state, not a path pending state.
Path pending should only be used for short lived intermediate states like 'new' or 'deleting'.
--- libmultipath/discovery.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
libmultipath/discovery.c +1 -2
@@ -1449,8 +1449,7 @@ path_offline (struct path * pp) } pp->offline =0 ;if (!strncmp (buff,"new" ,3 ) || - !strncmp (buff,"reconnecting" ,12 ) || - !strncmp (buff,"resetting" ,9 )) + !strncmp (buff,"deleting" ,8 ))return PATH_PENDING ;else if (!strncmp (buff,"live" ,4 ))return PATH_UP ;
Signature · 1 line
1.8.5.6
Re: [PATCH 2/4] libmultipath/discovery: modify NVMe path states
Quoted 6 lines · Hannes Reinecke
The NVMe path states 'resetting' and 'reconnecting' indicate that the controller could not talk to the namespace, which translates into a path down state, not a path pending state.
Path pending should only be used for short lived intermediate states like 'new' or 'deleting'.
I agree with the statements --Path pending should only be used for short
lived intermediate states. But it's better to schedule path state checking so soon as possible in the next second for "resetting" and "reconnecting" states because those two states is transient in a short time.
How about introducing a new state for multipath: PATH_TRANSITING to distinguish PATH_PENDING?
PATH_TRANSITING should also schedule path state checking so soon as possible in the next second.
Thanks
Guan
Quoted 20 lines
Signed-off-by Hannes Reinecke <[email protected]>--- libmultipath/discovery.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)libmultipath/discovery.c +1
-2@@ -1449,8 +1449,7 @@ path_offline (struct path * pp) } pp->offline =0 ;if (!strncmp (buff,"new" ,3 ) || - !strncmp (buff,"reconnecting" ,12 ) || - !strncmp (buff,"resetting" ,9 )) + !strncmp (buff,"deleting" ,8 ))return PATH_PENDING ;else if (!strncmp (buff,"live" ,4 ))return PATH_UP ;
Re: [PATCH 2/4] libmultipath/discovery: modify NVMe path states
Quoted 8 lines · Guan Junxiong
Quoted 5 lines · Hannes Reinecke
The NVMe path states 'resetting' and 'reconnecting' indicate that the controller could not talk to the namespace, which translates into a path down state, not a path pending state.
Path pending should only be used for short lived intermediate states like 'new' or 'deleting'.
Quoted 7 lines
I agree with the statements --Path pending should only be used for short lived intermediate states. But it's better to schedule path state checking so soon as possible in the next second for "resetting" and "reconnecting" states because those two states is transient in a short time.
How about introducing a new state for multipath:PATH_TRANSITINGto distinguishPATH_PENDING?
I beg to disagree.
'reconnecting' is telling us that the controller is trying to reconnect to the namespace, which will continue until KATO expires IIRC. Which can well be several seconds, plus this actually _is_ a path down state (path down signals that the transport layer lost connection to the remote system, which is exactly what this error is).
And 'resetting' is the controller entering reset after KATO expired, so most definitely a path down event.
And this took several minutes on the machine I've tested with, so it's anything but fast.
Or to put it another way round: if we treat these events as PATH_PENDING, which events would then signal a PATH_DOWN? We only have
new
live
reconnecting
resetting
deleting
dead
to choose from ...
Cheers,
Hannes
Signature · 10 lines
Dr. Hannes Reinecke Teamlead Storage & Networking [email protected] +49 911 74053 688 SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton HRB 21284 (AG Nürnberg) -- dm-devel mailing list [email protected] https://www.redhat.com/mailman/listinfo/dm-devel
PATCH 3/4 Add 'none' checker
In reply to Hannes ReineckeFor NVMe we don't have a good way of checking the path state, so add a new checker 'none' which doesn't do any checking, but rely on the internal sysfs state for path checking.
--- libmultipath/checkers.c | 22 ++++++++++++++++------ libmultipath/checkers.h | 3 ++- libmultipath/discovery.c | 10 ++++++---- libmultipath/discovery.h | 2 +- multipath/multipath.conf.5 | 3 +++ multipathd/main.c | 2 +- 6 files changed, 29 insertions(+), 13 deletions(-)
libmultipath/checkers.c +16 -6
@@ -19,6 +19,7 @@ char *checker_state_names[] = {"timeout" ,"removed" ,"delayed" , + "none", };static LIST_HEAD (checkers);
@@ -102,6 +103,8 @@ struct checker * add_checker (char *multipath_dir, char * name)if (!c)return NULL ;snprintf (c->name,CHECKER_NAME_LEN ,"%s" , name); +if (!strncmp (c->name,NONE ,4 )) + goto done;snprintf (libname,LIB_CHECKER_NAMELEN ,"%s/libcheck%s.so" , multipath_dir, name);if (stat (libname,&stbuf) <0 ) {
@@ -145,7 +148,7 @@ struct checker * add_checker (char *multipath_dir, char * name)condlog (0 ,"A dynamic linking error occurred: (%s)" , errstr);if (!c->repair) goto out; - +done: c->fd =-1 ; c->sync =1 ;list_add (&c->node, &checkers);
@@ -195,14 +198,16 @@ int checker_init (struct checker * c, void ** mpctxt_addr)if (!c)return 1 ; c->mpcontext = mpctxt_addr; -return c->init (c); +if (c->init) +return c->init (c); +return 0 ; }void checker_put (struct checker * dst) {struct checker * src; -if (!dst || !dst->check) +if (!dst || !strlen (dst->name))return ; src =checker_lookup (dst->name);if (dst->free)
@@ -221,11 +226,11 @@ void checker_repair (struct checker * c)MSG (c,"checker disabled" );return ; } - - c->repair (c); +if (c->repair) + c->repair (c); } -int checker_check (struct checker * c) +int checker_check (struct checker * c,int path_state) {int r;
@@ -237,6 +242,9 @@ int checker_check (struct checker * c)MSG (c,"checker disabled" );return PATH_UNCHECKED ; } +if (!strncmp (c->name,NONE ,4 )) +return path_state; +if (c->fd <0 ) {MSG (c,"no usable fd" );return PATH_WILD ;
@@ -250,6 +258,8 @@ int checker_selected (struct checker * c) {if (!c)return 0 ; +if (!strncmp (c->name,NONE ,4 )) +return 1 ;return (c->check) ?1 :0 ; }
libmultipath/checkers.h +2 -1
@@ -85,6 +85,7 @@ enum path_check_state {#define EMC_CLARIION "emc_clariion"#define READSECTOR0 "readsector0"#define CCISS_TUR "cciss_tur" +#define NONE "none"#define RBD "rbd"#define ASYNC_TIMEOUT_SEC 30
@@ -135,7 +136,7 @@ void checker_set_fd (struct checker *, int);void checker_enable (struct checker *);void checker_disable (struct checker *);void checker_repair (struct checker *); -int checker_check (struct checker *); +int checker_check (struct checker *,int );int checker_selected (struct checker *);char *checker_name (struct checker *);char *checker_message (struct checker *);
libmultipath/discovery.c +6 -4
@@ -1550,7 +1550,7 @@ cciss_ioctl_pathinfo (struct path * pp, int mask) }int -get_state (struct path * pp,struct config *conf,int daemon) +get_state (struct path * pp,struct config *conf,int daemon,int oldstate) {struct checker * c = &pp->checker;int state;
@@ -1588,8 +1588,9 @@ get_state (struct path * pp, struct config *conf, int daemon)if (!conf->checker_timeout &&sysfs_get_timeout (pp, &(c->timeout)) <=0 ) c->timeout =DEF_TIMEOUT ; - state =checker_check (c); -condlog (3 ,"%s: state = %s" , pp->dev,checker_state_name (state)); + state =checker_check (c, oldstate); +condlog (3 ,"%s: %s state = %s" , pp->dev, +checker_name (c),checker_state_name (state));if (state !=PATH_UP && state !=PATH_GHOST &&strlen (checker_message (c))) condlog(3, "%s: checker msg is \"%s\"",
@@ -1960,7 +1961,8 @@ int pathinfo(struct path *pp, struct config *conf, int mask)if (mask &DI_CHECKER ) {if (path_state ==PATH_UP ) { - pp->chkrstate = pp->state =get_state (pp, conf,0 ); + pp->chkrstate = pp->state =get_state (pp, conf,0 , + path_state);if (pp->state ==PATH_UNCHECKED || pp->state ==PATH_WILD ) goto blank;
libmultipath/discovery.h +1 -1
@@ -34,7 +34,7 @@ int path_discovery (vector pathvec, int flag);int do_tur (char *);int path_offline (struct path *); -int get_state (struct path * pp,struct config * conf,int daemon); +int get_state (struct path * pp,struct config * conf,int daemon,int state);int get_vpd_sgio (int fd,int pg,char * str,int maxlen);int pathinfo (struct path * pp,struct config * conf,int mask); int alloc_path_with_pathinfo (struct config *conf, struct udev_device *udevice,
multipath/multipath.conf.5 +3 -0
@@ -451,6 +451,9 @@ Please use \fItur\fR instead. (Hardware-dependent) Check the path state for HP/COMPAQ Smart Array(CCISS) controllers. .TP +.I none +Do not check the device, fallback to use the values retrieved from sysfs +.TP .I rbd Check if the path is in the Ceph blacklist and remap the path if it is. .TP
multipathd/main.c +1 -1
@@ -1623,7 +1623,7 @@ check_path (struct vectors * vecs, struct path * pp, int ticks)if (newstate ==PATH_UP ) { conf =get_multipath_config (); - newstate =get_state (pp, conf,1 ); + newstate =get_state (pp, conf,1 , newstate);put_multipath_config (conf); }else checker_clear_message (&pp->checker);
Signature · 1 line
1.8.5.6
Re: [PATCH 3/4] Add 'none' checker
Looks good.
Quoted 194 lines · Hannes Reinecke
For NVMe we don't have a good way of checking the path state, so add a new checker 'none' which doesn't do any checking, but rely on the internal sysfs state for path checking.
Signed-off-by Hannes Reinecke <[email protected]>--- libmultipath/checkers.c | 22 ++++++++++++++++------ libmultipath/checkers.h | 3 ++- libmultipath/discovery.c | 10 ++++++---- libmultipath/discovery.h | 2 +- multipath/multipath.conf.5 | 3 +++ multipathd/main.c | 2 +- 6 files changed, 29 insertions(+), 13 deletions(-)libmultipath/checkers.c +16
-6@@ -19,6 +19,7 @@ char *checker_state_names[] = {"timeout" ,"removed" ,"delayed" , + "none", };static LIST_HEAD (checkers);@@ -102,6 +103,8 @@ struct checker * add_checker (char *multipath_dir, char * name)if (!c)return NULL ;snprintf (c->name,CHECKER_NAME_LEN ,"%s" , name); +if (!strncmp (c->name,NONE ,4 )) + goto done;snprintf (libname,LIB_CHECKER_NAMELEN ,"%s/libcheck%s.so" , multipath_dir, name);if (stat (libname,&stbuf) <0 ) {@@ -145,7 +148,7 @@ struct checker * add_checker (char *multipath_dir, char * name)condlog (0 ,"A dynamic linking error occurred: (%s)" , errstr);if (!c->repair) goto out; - +done: c->fd =-1 ; c->sync =1 ;list_add (&c->node, &checkers);@@ -195,14 +198,16 @@ int checker_init (struct checker * c, void ** mpctxt_addr)if (!c)return 1 ; c->mpcontext = mpctxt_addr; -return c->init (c); +if (c->init) +return c->init (c); +return 0 ; }void checker_put (struct checker * dst) {struct checker * src; -if (!dst || !dst->check) +if (!dst || !strlen (dst->name))return ; src =checker_lookup (dst->name);if (dst->free)@@ -221,11 +226,11 @@ void checker_repair (struct checker * c)MSG (c,"checker disabled" );return ; } - - c->repair (c); +if (c->repair) + c->repair (c); } -int checker_check (struct checker * c) +int checker_check (struct checker * c,int path_state) {int r;@@ -237,6 +242,9 @@ int checker_check (struct checker * c)MSG (c,"checker disabled" );return PATH_UNCHECKED ; } +if (!strncmp (c->name,NONE ,4 )) +return path_state; +if (c->fd <0 ) {MSG (c,"no usable fd" );return PATH_WILD ;@@ -250,6 +258,8 @@ int checker_selected (struct checker * c) {if (!c)return 0 ; +if (!strncmp (c->name,NONE ,4 )) +return 1 ;return (c->check) ?1 :0 ; }libmultipath/checkers.h +2
-1@@ -85,6 +85,7 @@ enum path_check_state {#define EMC_CLARIION "emc_clariion"#define READSECTOR0 "readsector0"#define CCISS_TUR "cciss_tur" +#define NONE "none"#define RBD "rbd"#define ASYNC_TIMEOUT_SEC 30@@ -135,7 +136,7 @@ void checker_set_fd (struct checker *, int);void checker_enable (struct checker *);void checker_disable (struct checker *);void checker_repair (struct checker *); -int checker_check (struct checker *); +int checker_check (struct checker *,int );int checker_selected (struct checker *);char *checker_name (struct checker *);char *checker_message (struct checker *);libmultipath/discovery.c +6
-4@@ -1550,7 +1550,7 @@ cciss_ioctl_pathinfo (struct path * pp, int mask) }int -get_state (struct path * pp,struct config *conf,int daemon) +get_state (struct path * pp,struct config *conf,int daemon,int oldstate) {struct checker * c = &pp->checker;int state;@@ -1588,8 +1588,9 @@ get_state (struct path * pp, struct config *conf, int daemon)if (!conf->checker_timeout &&sysfs_get_timeout (pp, &(c->timeout)) <=0 ) c->timeout =DEF_TIMEOUT ; - state =checker_check (c); -condlog (3 ,"%s: state = %s" , pp->dev,checker_state_name (state)); + state =checker_check (c, oldstate); +condlog (3 ,"%s: %s state = %s" , pp->dev, +checker_name (c),checker_state_name (state));if (state !=PATH_UP && state !=PATH_GHOST &&strlen (checker_message (c))) condlog(3, "%s: checker msg is \"%s\"",@@ -1960,7 +1961,8 @@ int pathinfo(struct path *pp, struct config *conf, int mask)if (mask &DI_CHECKER ) {if (path_state ==PATH_UP ) { - pp->chkrstate = pp->state =get_state (pp, conf,0 ); + pp->chkrstate = pp->state =get_state (pp, conf,0 , + path_state);if (pp->state ==PATH_UNCHECKED || pp->state ==PATH_WILD ) goto blank;libmultipath/discovery.h +1
-1@@ -34,7 +34,7 @@ int path_discovery (vector pathvec, int flag);int do_tur (char *);int path_offline (struct path *); -int get_state (struct path * pp,struct config * conf,int daemon); +int get_state (struct path * pp,struct config * conf,int daemon,int state);int get_vpd_sgio (int fd,int pg,char * str,int maxlen);int pathinfo (struct path * pp,struct config * conf,int mask); int alloc_path_with_pathinfo (struct config *conf, struct udev_device *udevice,multipath/multipath.conf.5 +3
-0@@ -451,6 +451,9 @@ Please use \fItur\fR instead. (Hardware-dependent) Check the path state for HP/COMPAQ Smart Array(CCISS) controllers. .TP +.I none +Do not check the device, fallback to use the values retrieved from sysfs +.TP .I rbd Check if the path is in the Ceph blacklist and remap the path if it is. .TPmultipathd/main.c +1
-1@@ -1623,7 +1623,7 @@ check_path (struct vectors * vecs, struct path * pp, int ticks)if (newstate ==PATH_UP ) { conf =get_multipath_config (); - newstate =get_state (pp, conf,1 ); + newstate =get_state (pp, conf,1 , newstate);put_multipath_config (conf); }else checker_clear_message (&pp->checker);
PATCH 4/4 hwtable: set 'none' as default checker for NVMe
In reply to Hannes ReineckeWe shouldn't be using the directio checker for NVMe, as this might cause spurious path failures under high load.
As the 'state' attribute provides reliable information about the link status it's sufficient to just check this and don't call any path checkers.
--- libmultipath/hwtable.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
libmultipath/hwtable.c +1 -1
@@ -1113,7 +1113,7 @@ static struct hwentry default_hw[] = { .vendor = "NVME", .product = ".*", .uid_attribute = "ID_WWN", - .checker_name = DIRECTIO, + .checker_name = NONE, .retain_hwhandler = RETAIN_HWHANDLER_OFF, },/*
Signature · 1 line
1.8.5.6
Re: [PATCH 4/4] hwtable: set 'none' as default checker for NVMe
Looks good.
Quoted 25 lines · Hannes Reinecke
We shouldn't be using the directio checker for NVMe, as this might cause spurious path failures under high load.
As the 'state' attribute provides reliable information about the link status it's sufficient to just check this and don't call any path checkers.Signed-off-by Hannes Reinecke <[email protected]>--- libmultipath/hwtable.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)libmultipath/hwtable.c +1
-1@@ -1113,7 +1113,7 @@ static struct hwentry default_hw[] = { .vendor = "NVME", .product = ".*", .uid_attribute = "ID_WWN", - .checker_name = DIRECTIO, + .checker_name = NONE, .retain_hwhandler = RETAIN_HWHANDLER_OFF, },/*
Hi Hannes,
Thanks for improving DM-multipath over NVMe. Please find my comment.
Cheers
Guan Junxiong
Quoted 11 lines · Hannes Reinecke
Hi all,
the current NVMe support is fairly rudimentary, and we've had reports about spurious path failures under high load.
Which is a bit disappointing, seeing that high load is exactly what NVMe is about ...
So here's a patchset to clean up the situation somewhat.
In particular:
- I've fixed up the discovery to fall in line with the other transports, like filling out thesg_idfields (so that we're not greeted with weird hashes in the topology output)
Great, that is something I want to touch. IMO, it's better to use a union fields such as nvme_id fields which shows the true topology of NVMe/NVMf storage such as: host NQN ->portid->subsytem NQN ->controller ID ->namespace id .