1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
|
#ifndef CHECKERS_H_INCLUDED
#define CHECKERS_H_INCLUDED
#include <pthread.h>
#include <stdbool.h>
#include "list.h"
#include "defaults.h"
/*
*
* Userspace (multipath/multipathd) path states
*
* PATH_WILD:
* - Use: Any checker
* - Description: Corner case where "fd < 0" for path fd (see checker_check()),
* or where a checker detects an unsupported device
* (e.g. wrong checker configured for a given device).
*
* PATH_UNCHECKED:
* - Use: Only in directio checker
* - Description: set when fcntl(F_GETFL) fails to return flags or O_DIRECT
* not include in flags, or O_DIRECT read fails
* - Notes:
* - multipathd: uses it to skip over paths in sync_map_state()
* - multipath: used in update_paths(); if state==PATH_UNCHECKED, call
* pathinfo()
*
* PATH_DOWN:
* - Use: All checkers (directio, emc_clariion, hp_sw, readsector0, tur)
* - Description: Either a) SG_IO ioctl failed, or b) check condition on some
* SG_IO ioctls that succeed (tur, readsector0 checkers); path is down and
* you shouldn't try to send commands to it
*
* PATH_UP:
* - Use: All checkers (directio, emc_clariion, hp_sw, readsector0, tur)
* - Description: Path is up and I/O can be sent to it
*
* PATH_SHAKY:
* - Use: Only emc_clariion
* - Description: Indicates path not available for "normal" operations
*
* PATH_GHOST:
* - Use: Only hp_sw and rdac
* - Description: Indicates a "passive/standby" path on active/passive HP
* arrays. These paths will return valid answers to certain SCSI commands
* (tur, read_capacity, inquiry, start_stop), but will fail I/O commands.
* The path needs an initialization command to be sent to it in order for
* I/Os to succeed.
*
* PATH_PENDING:
* - Use: All async checkers
* - Description: Indicates a check IO is in flight.
*
* PATH_TIMEOUT:
* - Use: Only tur checker
* - Description: Command timed out
*
* PATH REMOVED:
* - Use: All checkers
* - Description: Device has been removed from the system
*
* PATH_DELAYED:
* - Use: None of the checkers (returned if the path is being delayed before
* reintegration.
* - Description: If a path fails after being up for less than
* delay_watch_checks checks, when it comes back up again, it will not
* be marked as up until it has been up for delay_wait_checks checks.
* During this time, it is marked as "delayed"
*
* PATH_DISCONNECTED is a special ephemeral state used to signal that a path
* has been disconnected at the storage target (e.g., LUN unmapped). When a
* checker returns PATH_DISCONNECTED:
* 1. The path's pp->disconnected field is set to track purge state
* 2. The state is immediately converted to PATH_DOWN for normal processing
* 3. If purge_disconnected is enabled, the path will be removed via sysfs
* This state should never be stored in pp->state or pp->chkrstate; it exists
* only as a transient return value from checkers to trigger special handling.
*/
enum path_check_state {
PATH_WILD = 0,
PATH_UNCHECKED,
PATH_DOWN,
PATH_UP,
PATH_SHAKY,
PATH_GHOST,
PATH_PENDING,
PATH_TIMEOUT,
PATH_REMOVED,
PATH_DELAYED,
PATH_DISCONNECTED, /* Ephemeral: mapped to PATH_DOWN */
PATH_MAX_STATE
};
#define DIRECTIO "directio"
#define TUR "tur"
#define HP_SW "hp_sw"
#define RDAC "rdac"
#define EMC_CLARIION "emc_clariion"
#define READSECTOR0 "readsector0"
#define CCISS_TUR "cciss_tur"
#define NONE "none"
#define INVALID "invalid"
#define ASYNC_TIMEOUT_SEC 30
/*
* strings lengths
*/
#define CHECKER_NAME_LEN 16
#define CHECKER_MSG_LEN 256
#define CHECKER_DEV_LEN 256
#define LIB_CHECKER_NAMELEN 256
/*
* Generic message IDs for use in checkers.
*/
enum {
CHECKER_MSGID_NONE = 0,
CHECKER_MSGID_DISABLED,
CHECKER_MSGID_NO_FD,
CHECKER_MSGID_INVALID,
CHECKER_MSGID_UP,
CHECKER_MSGID_DOWN,
CHECKER_MSGID_GHOST,
CHECKER_MSGID_UNSUPPORTED,
CHECKER_MSGID_DISCONNECTED,
CHECKER_GENERIC_MSGTABLE_SIZE,
CHECKER_FIRST_MSGID = 100, /* lowest msgid for checkers */
CHECKER_MSGTABLE_SIZE = 100, /* max msg table size for checkers */
};
struct checker_class;
struct checker {
struct checker_class *cls;
int fd;
unsigned int timeout;
int disable;
int path_state;
short msgid; /* checker-internal extra status */
void * context; /* store for persistent data */
void ** mpcontext; /* store for persistent data shared
multipath-wide. */
};
static inline int checker_selected(const struct checker *c)
{
return c != NULL && c->cls != NULL;
}
const char *checker_state_name(int);
int init_checkers(void);
void cleanup_checkers (void);
int checker_init (struct checker *, void **);
int checker_mp_init(struct checker *, void **);
void checker_clear (struct checker *);
void checker_put (struct checker *);
void checker_reset (struct checker *);
void checker_set_sync (struct checker *);
void checker_set_async (struct checker *);
void checker_set_fd (struct checker *, int);
void checker_enable (struct checker *);
void checker_disable (struct checker *);
/*
* start_checker_thread(): start async path checker thread
*
* This function provides a wrapper around pthread_create().
* The created thread will call the DSO's "libcheck_thread" function with the
* checker context as argument.
*
* Rationale:
* Path checkers that do I/O may hang forever. To avoid blocking, some
* checkers therefore use asynchronous, detached threads for checking
* the paths. These threads may continue hanging if multipathd is stopped.
* In this case, we can't unload the checker DSO at exit. In order to
* avoid race conditions and crashes, the entry point of the thread
* needs to be in libmultipath, not in the DSO itself.
*
* @param arg: pointer to struct checker_context.
*/
struct checker_context {
struct checker_class *cls;
};
int start_checker_thread (pthread_t *thread, const pthread_attr_t *attr,
struct checker_context *ctx);
int checker_get_state(struct checker *c);
bool checker_need_wait(struct checker *c);
void checker_check (struct checker *, int);
int checker_is_sync(const struct checker *);
const char *checker_name (const struct checker *);
void reset_checker_classes(void);
/*
* This returns a string that's best prepended with "$NAME checker",
* where $NAME is the return value of checker_name().
*/
const char *checker_message(const struct checker *);
void checker_clear_message (struct checker *c);
void checker_get(struct checker *, const char *);
/* Prototypes for symbols exported by path checker dynamic libraries (.so) */
int libcheck_check(struct checker *);
int libcheck_init(struct checker *);
void libcheck_free(struct checker *);
void *libcheck_thread(struct checker_context *ctx);
void libcheck_reset(void);
int libcheck_mp_init(struct checker *);
int libcheck_pending(struct checker *c);
bool libcheck_need_wait(struct checker *c);
/*
* msgid => message map.
*
* It only needs to be provided if the checker defines specific
* message IDs.
* Message IDs available to checkers start at CHECKER_FIRST_MSG.
* The msgtable array is 0-based, i.e. msgtable[0] is the message
* for msgid == CHECKER_FIRST_MSG.
* The table ends with a NULL element.
*/
extern const char *libcheck_msgtable[];
#endif /* CHECKERS_H_INCLUDED */
|