Skip to content

Commit

Permalink
multipathd: handle fpin events
Browse files Browse the repository at this point in the history
This patch incorporates the functionality to handle
FPIN ELS events present as part of FCTransport daemon
(available in EPEL8) into the multipathd. This helps us to
reduce the response time to react and take the necessary actions
on receiving the FPIN events.

This patch currently support FPIN-Li Events.

It adds a new thread to listen for ELS frames from driver and on
receiving the frame payload, push the payload to a list and notify the
fpin_els_li_consumer thread to process it.Once consumer thread is
notified, it returns to listen for more ELS frames from driver.

The consumer thread process the ELS frames and moves the devices paths
which are affected due to link integrity to marginal path groups.
This also sets the associated portstate to marginal.
The paths which are set to marginal path group will be unset
on receiving the RSCN events

[ MW: minor fixup for 32bit compilation ]

Signed-off-by: Muneendra Kumar <muneendra.kumar@broadcom.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Martin Wilck <mwilck@suse.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
  • Loading branch information
muneendramandala authored and mwilck committed Feb 10, 2022
1 parent 4f50e0e commit cfff03e
Show file tree
Hide file tree
Showing 11 changed files with 745 additions and 16 deletions.
13 changes: 13 additions & 0 deletions Makefile.inc
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,19 @@ check_file = $(shell \
echo "$$found" \
)

# Check whether a file contains a variable with name $1 in header file $2
check_var = $(shell \
if grep -Eq "(^|[[:blank:]])$1([[:blank:]]|=|$$)" "$2"; then \
found=1; \
status="yes"; \
else \
found=0; \
status="no"; \
fi; \
echo 1>&2 "Checking for .. $1 in $2 ... $$status"; \
echo "$$found" \
)

%.o: %.c
@echo building $@ because of $?
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
Expand Down
5 changes: 5 additions & 0 deletions libmultipath/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ ifneq ($(call check_func,dm_hold_control_dev,$(DEVMAPPER_INCDIR)/libdevmapper.h)
CFLAGS += -DLIBDM_API_HOLD_CONTROL
endif

ifneq ($(call check_var,ELS_DTAG_LNK_INTEGRITY,$(LINUX_HEADERS_INCDIR)/scsi/fc/fc_els.h),0)
CFLAGS += -DFPIN_EVENT_HANDLER
endif


OBJS = parser.o vector.o devmapper.o callout.o \
hwtable.o blacklist.o util.o dmparser.o config.o \
structs.o discovery.o propsel.o dict.o \
Expand Down
56 changes: 53 additions & 3 deletions libmultipath/dict.c
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,59 @@ snprint_def_find_multipaths(struct config *conf, struct strbuf *buff,
find_multipaths_optvals[conf->find_multipaths]);
}

static const char * const marginal_pathgroups_optvals[] = {
[MARGINAL_PATHGROUP_OFF] = "off",
[MARGINAL_PATHGROUP_ON] = "on",
#ifdef FPIN_EVENT_HANDLER
[MARGINAL_PATHGROUP_FPIN] = "fpin",
#endif
};

static int
def_marginal_pathgroups_handler(struct config *conf, vector strvec,
const char *file, int line_nr)
{
char *buff;
unsigned int i;

buff = set_value(strvec);
if (!buff)
return 1;
for (i = MARGINAL_PATHGROUP_OFF;
i < ARRAY_SIZE(marginal_pathgroups_optvals); i++) {
if (marginal_pathgroups_optvals[i] != NULL &&
!strcmp(buff, marginal_pathgroups_optvals[i])) {
conf->marginal_pathgroups = i;
break;
}
}

if (i >= ARRAY_SIZE(marginal_pathgroups_optvals)) {
if (strcmp(buff, "no") == 0 || strcmp(buff, "0") == 0)
conf->marginal_pathgroups = MARGINAL_PATHGROUP_OFF;
else if (strcmp(buff, "yes") == 0 || strcmp(buff, "1") == 0)
conf->marginal_pathgroups = MARGINAL_PATHGROUP_ON;
/* This can only be true if FPIN_EVENT_HANDLER isn't defined,
* otherwise this check will have already happened above */
else if (strcmp(buff, "fpin") == 0)
condlog(1, "%s line %d, support for \"fpin\" is not compiled in for marginal_pathgroups", file, line_nr);
else
condlog(1, "%s line %d, invalid value for marginal_pathgroups: \"%s\"",
file, line_nr, buff);
}
free(buff);
return 0;
}

static int
snprint_def_marginal_pathgroups(struct config *conf, struct strbuf *buff,
const void *data)
{
return append_strbuf_quoted(buff,
marginal_pathgroups_optvals[conf->marginal_pathgroups]);
}


declare_def_handler(selector, set_str)
declare_def_snprint_defstr(selector, print_str, DEFAULT_SELECTOR)
declare_hw_handler(selector, set_str)
Expand Down Expand Up @@ -1526,9 +1579,6 @@ declare_ovr_snprint(all_tg_pt, print_yes_no_undef)
declare_hw_handler(all_tg_pt, set_yes_no_undef)
declare_hw_snprint(all_tg_pt, print_yes_no_undef)

declare_def_handler(marginal_pathgroups, set_yes_no)
declare_def_snprint(marginal_pathgroups, print_yes_no)

declare_def_handler(recheck_wwid, set_yes_no_undef)
declare_def_snprint_defint(recheck_wwid, print_yes_no_undef, DEFAULT_RECHECK_WWID)
declare_ovr_handler(recheck_wwid, set_yes_no_undef)
Expand Down
1 change: 1 addition & 0 deletions libmultipath/libmultipath.version
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ global:
check_foreign;
cleanup_charp;
cleanup_lock;
cleanup_mutex;
cleanup_ucharp;
close_fd;
coalesce_paths;
Expand Down
47 changes: 41 additions & 6 deletions libmultipath/propsel.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ static const char cmdline_origin[] =
"(setting: multipath command line [-p] flag)";
static const char autodetect_origin[] =
"(setting: storage device autodetected)";
static const char fpin_marginal_path_origin[] =
"(setting: overridden by marginal_path_fpin)";
static const char marginal_path_origin[] =
"(setting: implied by marginal_path check)";
static const char delay_watch_origin[] =
Expand Down Expand Up @@ -1035,9 +1037,12 @@ int select_san_path_err_threshold(struct config *conf, struct multipath *mp)
const char *origin;
STRBUF_ON_STACK(buff);

if (marginal_path_check_enabled(mp)) {
if (marginal_path_check_enabled(mp) || (conf->marginal_pathgroups == MARGINAL_PATHGROUP_FPIN)) {
mp->san_path_err_threshold = NU_NO;
origin = marginal_path_origin;
if (conf->marginal_pathgroups == MARGINAL_PATHGROUP_FPIN)
origin = fpin_marginal_path_origin;
else
origin = marginal_path_origin;
goto out;
}
mp_set_mpe(san_path_err_threshold);
Expand All @@ -1058,9 +1063,12 @@ int select_san_path_err_forget_rate(struct config *conf, struct multipath *mp)
const char *origin;
STRBUF_ON_STACK(buff);

if (marginal_path_check_enabled(mp)) {
if (marginal_path_check_enabled(mp) || (conf->marginal_pathgroups == MARGINAL_PATHGROUP_FPIN)) {
mp->san_path_err_forget_rate = NU_NO;
origin = marginal_path_origin;
if (conf->marginal_pathgroups == MARGINAL_PATHGROUP_FPIN)
origin = fpin_marginal_path_origin;
else
origin = marginal_path_origin;
goto out;
}
mp_set_mpe(san_path_err_forget_rate);
Expand All @@ -1082,9 +1090,12 @@ int select_san_path_err_recovery_time(struct config *conf, struct multipath *mp)
const char *origin;
STRBUF_ON_STACK(buff);

if (marginal_path_check_enabled(mp)) {
if (marginal_path_check_enabled(mp) || (conf->marginal_pathgroups == MARGINAL_PATHGROUP_FPIN)) {
mp->san_path_err_recovery_time = NU_NO;
origin = marginal_path_origin;
if (conf->marginal_pathgroups == MARGINAL_PATHGROUP_FPIN)
origin = fpin_marginal_path_origin;
else
origin = marginal_path_origin;
goto out;
}
mp_set_mpe(san_path_err_recovery_time);
Expand All @@ -1106,6 +1117,12 @@ int select_marginal_path_err_sample_time(struct config *conf, struct multipath *
const char *origin;
STRBUF_ON_STACK(buff);

if (conf->marginal_pathgroups == MARGINAL_PATHGROUP_FPIN) {
mp->marginal_path_err_sample_time = NU_NO;
origin = fpin_marginal_path_origin;
goto out;
}

mp_set_mpe(marginal_path_err_sample_time);
mp_set_ovr(marginal_path_err_sample_time);
mp_set_hwe(marginal_path_err_sample_time);
Expand All @@ -1129,6 +1146,12 @@ int select_marginal_path_err_rate_threshold(struct config *conf, struct multipat
const char *origin;
STRBUF_ON_STACK(buff);

if (conf->marginal_pathgroups == MARGINAL_PATHGROUP_FPIN) {
mp->marginal_path_err_rate_threshold = NU_NO;
origin = fpin_marginal_path_origin;
goto out;
}

mp_set_mpe(marginal_path_err_rate_threshold);
mp_set_ovr(marginal_path_err_rate_threshold);
mp_set_hwe(marginal_path_err_rate_threshold);
Expand All @@ -1146,6 +1169,12 @@ int select_marginal_path_err_recheck_gap_time(struct config *conf, struct multip
const char *origin;
STRBUF_ON_STACK(buff);

if (conf->marginal_pathgroups == MARGINAL_PATHGROUP_FPIN) {
mp->marginal_path_err_recheck_gap_time = NU_NO;
origin = fpin_marginal_path_origin;
goto out;
}

mp_set_mpe(marginal_path_err_recheck_gap_time);
mp_set_ovr(marginal_path_err_recheck_gap_time);
mp_set_hwe(marginal_path_err_recheck_gap_time);
Expand All @@ -1164,6 +1193,12 @@ int select_marginal_path_double_failed_time(struct config *conf, struct multipat
const char *origin;
STRBUF_ON_STACK(buff);

if (conf->marginal_pathgroups == MARGINAL_PATHGROUP_FPIN) {
mp->marginal_path_double_failed_time = NU_NO;
origin = fpin_marginal_path_origin;
goto out;
}

mp_set_mpe(marginal_path_double_failed_time);
mp_set_ovr(marginal_path_double_failed_time);
mp_set_hwe(marginal_path_double_failed_time);
Expand Down
7 changes: 7 additions & 0 deletions libmultipath/structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ enum find_multipaths_states {
__FIND_MULTIPATHS_LAST,
};

enum marginal_pathgroups_mode {
MARGINAL_PATHGROUP_OFF = YN_NO,
MARGINAL_PATHGROUP_ON = YN_YES,
MARGINAL_PATHGROUP_FPIN,
};

enum flush_states {
FLUSH_UNDEF = YNU_UNDEF,
FLUSH_DISABLED = YNU_NO,
Expand Down Expand Up @@ -419,6 +425,7 @@ struct multipath {
unsigned char prflag;
int all_tg_pt;
struct gen_multipath generic_mp;
bool fpin_must_reload;
};

static inline int marginal_path_check_enabled(const struct multipath *mpp)
Expand Down
19 changes: 16 additions & 3 deletions multipath/multipath.conf.5
Original file line number Diff line number Diff line change
Expand Up @@ -1088,20 +1088,26 @@ The default is: \fBno\fR
.
.TP
.B marginal_pathgroups
If set to \fIno\fR, the \fIdelay_*_checks\fR, \fImarginal_path_*\fR, and
If set to \fIoff\fR, the \fIdelay_*_checks\fR, \fImarginal_path_*\fR, and
\fIsan_path_err_*\fR options will keep marginal, or \(dqshaky\(dq, paths from
being reinstated until they have been monitored for some time. This can cause
situations where all non-marginal paths are down, and no paths are usable
until multipathd detects this and reinstates a marginal path. If the multipath
device is not configured to queue IO in this case, it can cause IO errors to
occur, even though there are marginal paths available. However, if this
option is set to \fIyes\fR, when one of the marginal path detecting methods
option is set to \fIon\fR, when one of the marginal path detecting methods
determines that a path is marginal, it will be reinstated and placed in a
separate pathgroup that will only be used after all the non-marginal pathgroups
have been tried first. This prevents the possibility of IO errors occurring
while marginal paths are still usable. After the path has been monitored
for the configured time, and is declared healthy, it will be returned to its
normal pathgroup. See "Shaky paths detection" below for more information.
normal pathgroup.
However if this option is set to \fIfpin\fR multipathd will receive fpin
notifications, set path states to "marginal" accordingly, and regroup paths
as described for "marginal_pathgroups yes". This option can't be used in combination
with other options for "Shaky path detection" (see below).If it is set to fpin,
marginal_path_xyz and san_path_err_xyz parameters are implicitly set to 0.
See "Shaky paths detection" below for more information.
.RS
.TP
The default is: \fBno\fR
Expand Down Expand Up @@ -1841,6 +1847,13 @@ increase and the threshold is never reached. Ticks are the time between
path checks by multipathd, which is variable and controlled by the
\fIpolling_interval\fR and \fImax_polling_interval\fR parameters.
.
.TP
.B \(dqFPIN \(dq failure tracking
Fibre channel fabrics can notify hosts about fabric-level issues such
as integrity failures or congestion with so-called Fabric Performance
Impact Notifications (FPINs).On receiving the fpin notifications through ELS
multipathd will move the affected path and port states to marginal.
.
.RS 8
.LP
This method is \fBdeprecated\fR in favor of the \(dqmarginal_path\(dq failure
Expand Down
10 changes: 10 additions & 0 deletions multipathd/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ ifneq ($(call check_func,dm_task_get_errno,$(DEVMAPPER_INCDIR)/libdevmapper.h),0
CFLAGS += -DLIBDM_API_GET_ERRNO
endif

ifneq ($(call check_var,ELS_DTAG_LNK_INTEGRITY,$(LINUX_HEADERS_INCDIR)/scsi/fc/fc_els.h),0)
CFLAGS += -DFPIN_EVENT_HANDLER
FPIN_SUPPORT = 1
endif
#
# debugging stuff
#
Expand Down Expand Up @@ -34,6 +38,12 @@ endif
OBJS = main.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o waiter.o \
dmevents.o init_unwinder.o

ifeq ($(FPIN_SUPPORT),1)
OBJS += fpin_handlers.o
endif



EXEC = multipathd

all : $(EXEC)
Expand Down
20 changes: 20 additions & 0 deletions multipathd/fpin.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#ifndef __FPIN_H__
#define __FPIN_H__

#ifdef FPIN_EVENT_HANDLER
void *fpin_fabric_notification_receiver(void *unused);
void *fpin_els_li_consumer(void *data);
void fpin_clean_marginal_dev_list(__attribute__((unused)) void *arg);
#else
static void *fpin_fabric_notification_receiver(__attribute__((unused))void *unused)
{
return NULL;
}
static void *fpin_els_li_consumer(__attribute__((unused))void *data)
{
return NULL;
}
/* fpin_clean_marginal_dev_list() is never called */
#endif

#endif

0 comments on commit cfff03e

Please sign in to comment.