DM-Multipathing (DM-MPIO) provides I/O failover and load-balancing within Linux for block devices. By utilizing device-mapper, multipathd provides the host-side logic to use multiple paths of a redundant network to provide continuous availability and higher bandwidth connectivity between the host server and the block-level device.
在内核中它通过一个一个模块化的 target driver 插件实现对 IO 请求的过滤或者重新定向等工作,当前已经实现的 target driver 插件包括软 raid、软加密、逻辑卷条带、多路径、镜像、快照等,图中 linear、mirror、snapshot、multipath 表示的就是这些 target driver。
Device mapper 进一步体现了在 Linux 内核设计中策略和机制分离的原则,将所有与策略相关的工作放到用户空间完成,内核中主要提供完成这些策略所需要的机制。Device mapper 用户空间相关部分主要负责配置具体的策略和控制逻辑,比如逻辑设备和哪些物理设备建立映射,怎么建立这些映射关系等等,而具体过滤和重定向 IO 请求的工作由内核中相关代码完成。因此整个 device mapper 机制由两部分组成,内核空间的 device mapper 驱动、用户空间的device mapper 库以及它提供的 dmsetup 工具。
mapped_device: device mapper生成的逻辑块设备,map指向dm_table
dm_table: mapped_device和物理设备target的映射,按照B树组织dm_target,便于IO请求映射的查找
dm_target: 记录映射的mapped device的逻辑区域的开始地址和范围,type指向target设备的驱动类型(target_type),private记录具体设备的数据。
target_type multipath_target: mulitpath类型的target的driver,包括创建、销毁device的方法。
Device mapper本质功能就是根据映射关系和target driver描述的IO处理规则,将IO请求从逻辑设备mapped device转发相应的target device上。Device mapper处理所有从内核中块一级IO子系统的generic_make_request和submit_bio接口中定向到mapped device的所有块读写IO请求。IO请求在device mapper的设备树中通过请求转发从上到下地进行处理。当一个bio请求在设备树中的mapped deivce向下层转发时,一个或者多个bio的克隆被创建并发送给下层target device。target driver结束某个bio请求后,将表示结束该bio请求的事件上报给它上层的mapped device,该过程在各个层次上进行直到该事件最终上传到根mapped device的为止,然后device mapper结束根mapped device上原始bio请求,结束整个IO请求过程。
(1) 发现每个mapped device相关的target device;
(2) 根据配置信息创建映射表;
(3) 将用户空间构建好的映射表传入内核,让内核构建该mapped device对应的dm_table结构;
(4) 保存当前的映射信息,以便未来重新构建。
The Device Mapper multipath module of the Linux kernel:multipath_target
The multipath-tools userspace package:multipath-tools take care of automatic path discovery and grouping as well as automated path retesting, so that a previously failed path is automatically reinstated when it becomes healthy again. This minimizes the need for administrator attention in a production environment. Include Multipathd service and multipath(CLI)
主要提供的方法(每种类型的target都必须提供):
multipath_ctr:构建target device 的方法
multipath_dtr:删除target device 的方法
multipath_map:Target的映射IO请求的方法,调用map_io
multipath_status:获取当前target device状态的访问
multipath_message: Target 处理用户消息的方法,根据具体的消息类型会调用fail_path, queue_if_no_path, switch_pg_num等方法
multipath_end_io:Target结束IO请求的方法
Multipath
Pathgroup(优先组)
Path
配置文件中path_grouping_policy项如果设定为failover,则每个path都在不同的pathgroup,如果设置为multibus,则所有的path都在一个pathgroup。
path_grouping_policy
path_checker:指定用于决定路径状态的默认方法,包括:readsector0\directio
failback: 路径出错恢复正常后切换策略,包括immediate/manual/数字(代表时间)
no_path_retry:指定所有路径都失败后应该再试图尝试的次数。Queue/fail/数字(代表次数)
path_selector:指定用来决定下一个 I/O 操作所使用路径的默认算法。Round-robin/queue-length。
Prio: 指定要获得路径优先值所需调用的默认程序及参数。默认是const,即优先值都为1
Hardware_handler(device配置):指定将在切换路径组群或者处理 I/O 错误时用来执行硬件具体动作的模块。配置值:emc/hp_sw/rdac。默认为”0”
The multipath daemon learns of and reacts to changes in both the current block device configuration and the kernel resident multipathing configuration.
The addition of a new path or the removal of an already existing path to an already managed block device is detected over a netlink socket as a uevent triggered callback which adds or removes the path to or from the set of paths which will be actively tested.
Changes to the kernel resident multipathing state are detected as device-mapper generated event callbacks. Events of this kind invole block io errors, path state change, and changes in the highest priority path group for a mapped device.
内核Multipath对象的成员trigger_event,由Dm-mpath.c中的trigger_event函数赋值,
trigger_event调用Dm-table.c的dm_table_event函数,dm_table_event调用dm_table对象的event_fn,event_fn在Dm.c的dm_table_event_callback函数(对于该函数何时被调用还有疑问!!!)里被赋值为event_callback。
event_callback会wake_up mapped_device的eventq,而Dm_ioctl.c中dev_wait函数调用dm_wait_event函数等待eventq的事件中断。
用户态每个multipath对象都会启动一个waiter_thread,线程函数waitevent while(1)循环调用waiteventloop函数,waiteventloop最终调用内核的dev_wait方法。
用户态ueventloop线程监听Netlink events事件,调用uev_add_map/uev_add_path等方法处理map(未发现内核有此类事件!!!)和path相关的事件。
内核态dm_path_uevent(Dm_uevent.c)向Netlink events中加入path相关事件到mapped_device对象的uevent_list中。dm_send_uevents函数发送事件,该函数被event_callback方法调用。
Multipathd服务启动时会调用configure方法,该方法依次执行发现路径、过滤路径、发现multipath、通过Path生成Multipath、同步用户态和内核路径状态、启动Multipath的DM事件监听等操作。
发现路径:Path_discovery从/sys/block目录下获取设备名,即路径名,通过ioctl等方法获取设备信息。
过滤路径:filter_path根据配置文件中blacklist项的配置过滤路径。
发现multipath: 通过libdevmapper向内核DM发送DM_DEVICE_LIST指令,获取所有DM设备,保留multipath类型的设备,获取alias,size,params,status等信息,使用setup_multipath方法,首先从params中解析出multipath的部分配置(pathgroup/path)和状态,然后从配置文件(或者bulid-in)中获取mpe、hwe,再根据mpe、hwe的中配置multipath的rr_weight\pgfailback\no_path_retry等配置。
Multipathd第一次启动从DM获取multipath,返回应该为空。
通过Path生成Multipath:coalesce_paths遍历所有路径,mpp=NULL的生成multipath对象,通过adopt_paths将wwid相同的其它路径加入到multipath的paths中。verify_paths检查multipath中所有的path是否都能从sysfs获取设备信息,如果不行删除。setup_map通过mpe/hwe/conf设置multipath配置,根据pgpolicy从path生成pathgroup(路径分组),从配置打包params。select_action确定要对dm要执行的操作(create/rename),domap向内核DM层发送相应指令,DM创建相应的multipath_target。通过dm_message设置no_path_retry。删除deadmap(所有path都not in sysfs的Multipath)
同步用户态和内核路径状态: 遍历所有multipath的所有path,根据dmstate和state的差别,调用dm_reinstate_path或dm_fail_path向DM发送对应message,使内核管理的path状态和用户态一致。
启动DM事件监听:用户态每个multipath对象启动一个监听线程,监听来自内核DM的报告的事件,可能包括路径错误等事件
使用Multipathd –k命令进去CLI管理界面,add path或add map可以添加路径和multipath
PATH_UNCHECKED: checker方法获取失败,或checker_init调用失败返回。
PATH_WILD: sysfs接口查询设备及状态失败时返回。
PATH_PENDING:从sysfs获取的设备状态是”blocked”。
PATH_DOWN:从sysfs获取的设备状态是”offline”,或通过checker方法检查返回。
PATH_UP:从sysfs获取的设备状态是”running”,并且通过了checker方法的检查。
PATH_SHAKY:emc_clariion检查方法中出现,类似于PATH_DOWN
PATH_GHOST: hp_sw和tur检查方法中出现,类似于PATH_UP
路径的初始检查间隔(checkint)由配置文件polling_interval项配置,默认为5。
配置文件中path_checker项设置路径检查方法,譬如readsector0,即通过ioctl读取设备的第0个扇区(长度根据fstat设备的属性,测试的iscsi是4K)。
Multipathd服务启动Checkerloop线程进行路径检查,遍历vecs中所有的path,调用check_path方法进行检查。
Check_path:
(1) getstate: 首先用path_offline通过sysfs获取设备状态(sysfs_get_state),然后针对up状态的path再调用path_checker具体方法进行检查。
(2) 如果新旧状态不一致,作如下(3)-(6)处理:
(3) 恢复path的检查间隔checkint为配置值(conf->checkint)
(4) 如果新状态是fail或shark,update_multipath_strings,通过dm_message主动通知DM,并且如果旧状态是up或ghost,减少该multipath的活跃路径数nr_active。
处理活跃路径为0:
如果活跃数等于0 ,判断no_path_retry是否设置(大于0为重试次数,小于0为其它策略),如果是,设置retry_tick(=mpp->no_path_retry * conf->checkint + 1)。然后退出检查。
(5) 新状态是up或ghost,通过dm_message主动通知DM,如果旧状态不是up或ghost,增加该multipath的活跃路径数,
处理增加前活跃为0:
如果增加前活跃路径数为0,并且no_path_retry>0,设置retry_tick=0,并且通过dm_message通知DM “queue_if_no_path”
处理failback:
根据mpp->pgfailback的设置(大于0为等待切换时间,小于0为其它策略),如果大于0,设置failback_tick=pgfailback+1;如果等于--FAILBACK_IMMEDIATE,通过need_switch_pathgroup重新刷新计算path的优先级,如果nextpg<>bestpg,通过dm_message通知DM bestpg(switchgroup)。
默认情况每条路径的优先级都是1(prio=const),因此need_switch_pathgroup每次都会第一个Path作为最优Path。
(6) 如果新状态是up,并且所在pathgroup的状态是disable,通过dm_message通知DM”enable”该pathgroup
(7) 如果新旧状态一致,并且一直是up或ghost状态,设置路径的checkint为原有值的两倍,最大为配置值的4倍。
(8) 刷新path的优先级,need_switch_pathgroup判断是否需要切换,如果需要:
如果pgfailback>0并且failback_tick<0,设置failback_tick=pgfailback+1;否则如果pgfailback等于--FAILBACK_IMMEDIATE,通过dm_message通知DM切换到bestpg。
Checkloop线程在检查完所有path后,会对vecs中所有的multipath做下列两件事情:
defered_failback_tick:
遍历所有multipath,对于设置了pgfailback的,failback_tick减1,如果failback_tick等于0并且need_switch_pathgroup刷新路径返回1,switchgroup。
retry_count_tick:
遍历所有multipath,对于retry_tick>0,retry_tick减1,如果retry_tick等于0,通过dm_message通知DM “fail_if_no_path”
Switchgroup消息传递到内核,会修改内核multipath对象的current_pgpath=NULL和nextpg,failback消息传递到内核,会调用fail_path方法修改内核multipath对象的current_pgpath=NULL,之后的读写请求到multipath_target的map_io时就会选择的新的路径。
内核在对multipath_target进行读写结束后会调用do_end_io方法,如果读写发生错误时,该方法会调用fail_path,通过ioctl事件机制通知用户态
用户态multipathd收到事件后,调用update_multipath方法修改path的state为down,并且如果活跃路径数变为0,采用上述相同方法处理。
在3.3.1路径检查中,发现路径故障,会通过dm_message消息通知内核DM,DM修改current_pgpath=NULL,在下次map_io时会选择新的路径。
选择方式为首先在当前优先组(currentpg)中查找,如果找不到,再从其它优先组中查找。
在3.3.1路径检查中,如果pgfailback设置为IMMEDIATE,或者设定为等待时间failback_tick到了,用户态会通过dm_message消息通知内核DM,DM设置nextpg,修改current_pgpath=NULL, 在下次map_io时会选择新的路径。
选择方式为设定nextpg为当前优先组(currentpg),直接在当前优先组中查找。
内核multipath_target里,每个path有一个属性repeat_count( round-robin模式下等于1000),每次map_io,repeat_count减1,等于0时,切换路径
选择方式为当前currentpg的path列表的头部取出一个path,然后再插入列表的尾部
在3.5中当选择路径失败时,即全部路径都出错了,这时map_io根据queue_if_no_path的值,决定是将请求排队(值为1),还是立即返回错误。通过测试发现如果请求在排队时,上层应用进程的状态是S(可中断睡眠)。
在3.4.1中用户态的no_path_retry配置(queue/fail)在向DM发送create multipath指令之后,会传递给DM。
在3.3.1路径检查中,如果no_path_retry设置为queue/fail,或者设定的等待时间retry_tick到了,用户态通过dm_message发送“queue_if_no_path”或“fail_if_no_path”消息给DM,DM由此设置queue_if_no_path。
用户态Multipath对象的hw_handle配置会传递到内核赋值内核multipath对象的hw_handle_name。
内核mapio在处理路径切换时,如果发现currentpg和要切换的pg是否相同,如果不相同会调用__switch_pg,__switch_pg方法除了设置currentpg外,会根据hw_handle_name的值设置queue_io和pg_init_required,如果hw_handle_name有值,都设置1。
Mapio处理完路径切换后,会判断currentpath!=NULL&&queue_io,或currentpath==NULL&&queue_if_no_path(3.7路径全部失败)满足一个条件后就将请求排队,将请求插入到queued_ios。
在一些可能要结束排队的触发事件发生后会通过queue_work调用process_queued_ios方法:
(1) 该方法首先判断currentpath是否为空,如果是,调用__choose_pgpath选择路径;
(2) 判断如果curentpath不等于空,queue_io是否等于0,或者等于空,queue_if_no_path是否等于0,这两个条件如果满足一个,设置must_queue=0;
(3) 然后判断pg_init_required是否设置,并且pg_init_in_progress没有设置,如果是调用__pg_init_all_paths初始化path;
(4) __pg_init_all_paths遍历每个路径,调用path的activate_path方法,设置pg_init_in_progress++,activate_path方法最终调用到Scsi_dh.c中的scsi_dh_activate方法(Scsi_device设备驱动需要实现),该方法在设备初始化完成后会调用pg_init_done;
(5) 如果must_queue==0,dispatch_queued_ios调用map_io处理排队的请求。
可能的触发条件有:
(1) queue_if_no_path方法在m->queue_if_no_path等于0(fail)时调用
(2) reinstate_path方法在m->nr_valid_paths原为0,情况下调用
(3) pg_init_done在path初始化完后调用
(4) map_io在处理完请求排队,在pg_init_required被设置(目的是处理path初始化),调用process_queued_ios。
Multipath采用动态加载的方式加载路径检查的方法;
directio主要是用aio的方法读取一个块的大小(最大4096)
readsector0是通过ioctl(sg_fd, SG_IO, &io_hdr)向scsi驱动器发送读指令。
(1) load_config()
(2) init_checker()
(3) init_prio(): 默认为const,每条路径的优先级都是1
(4) configure()
(5) 创建几个线程(checkerloop、ueventloop、uxlsnrloop(注册各种CLI请求(Multipathd -k)处理方法))
(1)path_discovery
(2)filter_path:根据blacklist过滤路径
(3)map_discovery:dm_get_maps调用libdevicemap的接口、setup_multipath(update_multipath_strings)
(4)coalesce_paths
(5)coalesce_maps
(6)sync_maps_state: 遍历所有multipath的所有path,根据dmstate和state的差别,调用dm_reinstate_path或dm_fail_path向DM发送对应message。
(7)遍历每个multipath,调用start_waiter_thread,启动一个dm事件监听线程,update_multipath处理产生的事件,首先查找Multipath,然后setup_multipath,如果查找失败或setup失败,退出线程。之后判断所有path的dmstate如果是failed,修改path的state为down,并且如果path的原有state是up(ghost),调用update_queue_mode_del_path
(1)从“/sys/block”目录下获取设备名(char*)
(2)根据设备名在path_vec中查找,不存在添加
(3)path_info获取路径相关信息(state\priority\uid\scsi设备的serialno)
discovery.c(.h)里其它方法都是由path_info调用,向各种设备获取各种设备信息和状态
(1)dm_task_create(DM_DEVICE_LIST)获取所有DM设备名称names
(2)遍历names
(3)dm_type(),通过name判断是否是multipath设备(通过获取DM_DEVICE_TABLE)
(4)如果是multipath设备,获取mpp->alias,mpp->size,mpp->params,mpp->status,mpp->wwid,mpp->dmi(dm_info),插入全局的mpvec
(5)至(2)完成遍历
(1)dm_get_info (maybe 重复了,而且可能有内存泄露!!!)
(2)dm_map_present判断dm_info.exists
(3)set_multipath_wwid (在map_discovery的调用里,不会再执行)
(4)通过wwid,find_mpe赋值mpp->mpe
(5)update_multipath_strings,如果返回1,dm_get_name获取new_alias,如果成功,说明发生rename,赋值当前mpp->alias,goto out(remove_map(mpp, vecs, PURGE_VEC))
(6)extract_hwe_from_path: 从Multipath中选择PGSTATE_ACTIVE和PGSTATE_ENABLED的pgp,再选择非PSTATE_FAILED状态的path,使用find_hwe,通过path->vendor_id,product_id,rev查询conf->hwtable,并赋值path->hwe,然后返回hwe
(7)通过mpp->mpe或mpp->hwe或conf,设置Multipath各种属性(rr_weight\pgfailback\no_path_retry\pg_timeout\flush_on_last_del)
(1)free_multipath_attributes,free_pgvec
(2)update_multipath_table
(3)update_multipath_status
(1)dm_get_map:获取mpp->params
(2)disassemble_map:从params中解析出multipath的配置
(1)从mpp->params解析出mpp->no_path_retry,mpp->hwhandler
(2)解析出path group的个数
(3)(0,num_pg)循环
(4)如果mpp->selector没有赋值,先赋值
(5)alloc_pathgroup()
(6)解析出pgp下面的path个数
(7)(0,num_paths)循环
(8)解析出path的设备名,从全局pathvec查找path,没有则alloc_path(),插入pathvec
(9)将path插入到pgp->paths
(10)如果mpp->wwid没有赋值,用path->wwid赋值,否则如果path->wwid没有赋值,用mpp->wwid赋值
(11)解析出mpp->minio(?)
(12)至(7),至(3)
(1)dm_get_status,通过dm_get_status获取设备状态,赋值mpp->status(char*)
(2)disassemble_status:解析mpp->status
赋值mpp->queueio
循环赋值所以pgp,赋值status(PGSTATE_DISABLED\PGSTATE_ACTIVE\PGSTATE_ENABLED\PGSTATE_UNDEF)
循环赋值pgp下面所有的path的状态:PSTATE_FAILED、PSTATE_ACTIVE,和failcount
解析出mpp->minio
(1)遍历所有的路径Path
(2)针对mpp=NULL的Path(pp1),调用add_map_with_path方法,创建multipath(mpp),赋值Path的mpp, adopt_paths
(3)从当前迭代位置K往后遍历Path,当Path(pp2)的wwid和当前Path的wwid相等时,如果pp2的size不等于mpp的size,或pp2的priority为undef,设置mpp的action为ACT_REJECT
(4)verify_paths: 遍历Multipath的path,如果path->sysdev=null或者从sysfs_get_dev获取不到设备信息,从multipath中删除path,同时从全局的pathvec中删除path.
(5)setup_map: 通过mpp->mpe或mpp->hwe或conf,设置Multipath各种属性(pgfailback\pgpolicy\selector等,mpp->pgpolicyfn(mpp):根据pgpolicy从path生成pathgroup),调用assemble_map,将mulitpath相关配置编码到mp->params.
(6)select_action: 如果mpp->action==undef,通过alias、wwid在全局的mpvec是否存在,设置action为create,rename,reload,nothing等。
(7)domap:根据action具体类别,调用相应dm接口处理
(8)通过dm_message设置no_path_retry和pg_timeout
(9)如果mpp的action不是reject,将mpp加入newmp(与mpvec同类型)
(10)转向(1)直至遍历全部path
(11)遍历newmpp中所有Multipath,如果Multipath是deadmap(所有path->dev=null,not in sysfs),从newmp和全局mpvec中删除Multipath,调用dm_flush_map通知DM删除该mpp。
(1)update_mpp_paths,使用multipath->pg->paths更新multipath->paths
(2)遍历全局的pathvec, 如果Path的wwid等于multipath的wwid,将Path加入multipath->paths,同时path_info(path).
将vecs->mpvec中已经不存在于newmp(coalesce_paths方法生成)的mpp,调用dm_flush_map从DM内核删除,如果删除失败,将mpp插入newmp,setup_multipath(),从oldmp删除
Hwtable.c记录了默认支持的硬件驱动器,struct hwentry default_hw[]
conf->hwtable,首先是来自上述的default_hw,其次是由load_config的init_data()从配置文件的devices项读取.
find_hwe 根据vendor和product,从conf->hwtable中查找hwentry
conf->mptable,由load_config的init_data()从配置文件的multipaths项读取。
find_mpe从conf->mptable中根据wwid查找mpentry
(1)check_path:get_state获取Path状态,根据最新状态调用update_multipath_strings更新Multipath状态,或主动更新内核DM的状态。
(2)defered_failback_tick: Multipath的failback_tick每次减1,当等于0时,根据是否需要(mpp->pgfailback == -FAILBACK_MANUAL)切换调用switchgroup
(3)retry_count_tick: Multipath的retry_tick每次减1,当等于0时,调用dm_queue_if_no_path
(1)首先用path_offline通过sysfs获取设备状态(sysfs_get_state)
(2)如果是up状态,再调用checker_check使用具体的检查路径方法进行check
(1)newstate=get_state(pp)
(2)如果状态是PATH_WILD(sysfs相关操作失败)或PATH_UNCHECKED(获取或设置checker失败),pathinfo(pp, conf->hwtable, 0),退出
(3)如果状态是PATH_PENDING,pp->tick=1
(4)如果新状态和旧状态不相等,调用(5)-(8)
(5)调用update_multipath_strings()更新pp->mpp,如果返回大于0,或者新状态是PATH_DOWN或者PATH_SHAKY,并且oldstate是PATH_UP或PATH_GHOST,调用fail_path(调用dm_fail_path通知DM,update_queue_mode_del_path修改retry_tick),pp->mpp->failback_tick = 0,退出
(6)(新状态等于PATH_UP或PATH_GHOST),如果oldstate不等于PATH_UP或者不等于PATH_GHOST,reinstate_path(pp,1)否则reinstate_path(pp,0)(dm_reinstate_path通知DM,update_queue_mode_add_path)
(7)如果pp->mpp->pgfailback == FAILBACK_IMMEDIATE并且need_switch_pathgroup(pp>mpp, 1),调用switch_pathgroup(pp->mpp)
(8)如果新状态是PATH_UP,调用enable_group(dm_enablegroup通知DM)
(9)如果新旧状态相等,并且newstate是PATH_UP或PATH_GHOST,pp->checkint自增1
(10)pathinfo(DI_PRIO),refreshing path prio
(11)处理need_switch_pathgroup,根据pgfailback可能switch_pathgroup()
(1)mpp活跃路径数nr_active减1
(2)如果mpp的nr_active等于0并且no_path_retry大于0,stat_queueing_timeouts自增1,设置retry_tick等于mpp->no_path_retry * conf->checkint + 1。
(1)增加活跃路径数nr_active
(2)如果增加前活跃路径数为0,并且no_path_retry>0,设置retry_tick=0,通知DM “queue_if_no_path”
(1)如果mpp->pgfailback=-FAILBACK_MANUAL,返回0
(2)如果参数refresh设置为1,调用pathinfo刷新path的prio
(3)select_path_group计算mpp的最优pathgroup,先比较平均优先级,再比较enable路径个数。
(4)如果bestpg不等于nextpg,返回1
(5)返回0
libdevmapper提供大部分接口是通过ioctl方法向“/dev/mapper/control”设备(设备号等于/proc/misc中dev-mapper驱动的设备号)通信完成的。
支持的请求类型定义在:_cmd_data_v4
multipath_target的主要方法:
multipath_ctr
multipath_dtr
multipath_map:调用map_io
multipath_status
multipath_message: 根据具体的消息类型会调用fail_path, queue_if_no_path, switch_pg_num等方法
multipath_end_io
处理来自libdevmapper对内核信息的各种请求,主要的方法有:
list_devices
dev_create
table_status (会调用到target的相应方法,即multipath_status)
target_message(最终调用target的相应方法,即multipath_message)
(1)if (!m->current_pgpath ||
(!m->queue_io && (m->repeat_count && -m>repeat_count == 0)))
__choose_pgpath(m, nr_bytes);
路径失败、路径恢复、负载均衡(repeat_count)等原因,会触发调用__choose_pgpath
(2)bdev = pgpath->path.dev->bdev;
clone->q = bdev_get_queue(bdev);
clone->rq_disk = bdev->bd_disk;
return DM_MAPIO_REMAPPED;
(1)首先根据m->next_pg选择,其次在current_pg中寻找,最后再遍历m->priority_groups,调用__choose_path_in_pg()寻找path.
(2)_choose_path_in_pg():使用path_selector_type中调用的select_path的方法选择path,然后设置m->current_pgpath,如果m->current_pg和选择pg不相同,调用_switch_pg。
round-robin:rr_select_path:从valid_paths列表的头部取出路径,然后插入到尾部,返回该路径。用path的repeat_count赋值multipath的repeat_count。
(3)_switch_pg首先设置m->currentpg,然后根据hw_handler_name是否赋值,如果是,设置pg_init_required=1,queue_io=1,否则都设置为0。
(1)调用Path所在优先组pg的path_selector_type中定义的fail_path方法
round-robin:将path加入selector的invalid_paths列表中
(2)pgpath->is_active = 0;m->nr_valid_paths-;如果m>current_pgpath等于该path,设置m->current_pgpath=NULL
(3)dm_path_ueventt产生一个fail_path的事件通过netlink events机制通知用户态
(4)schedule_work(&m->trigger_event)触发一个event以唤起用户态的对该Multipath事件的监听线程
根据传递的参数queue_if_no_path设置multipath的queue_if_no_path。
对用户态的switch_pg的指令消息进行处理,修改multipath的next_pg为相应组序号(参数)的优先组,设置m->current_pgpath = NULL;m->current_pg = NULL。
schedule_work(&m->trigger_event)触发一个event以唤起用户态的对该Multipath事件的监听线程
(1) 内核devmapper建立过程分为两个步骤,创建mapped_device和table_load(创建table和target),用户态触发内核创建的代码应该在coalesce_paths中,但是这个方法如何实现触发这两个过程的?