收藏 分享(赏)

pvcreate代码分析.doc

上传人:精品资料 文档编号:10909169 上传时间:2020-01-20 格式:DOC 页数:48 大小:254KB
下载 相关 举报
pvcreate代码分析.doc_第1页
第1页 / 共48页
pvcreate代码分析.doc_第2页
第2页 / 共48页
pvcreate代码分析.doc_第3页
第3页 / 共48页
pvcreate代码分析.doc_第4页
第4页 / 共48页
pvcreate代码分析.doc_第5页
第5页 / 共48页
点击查看更多>>
资源描述

1、LVM 代码分析1. 探索 pvcreate 函数大致的执行过程1.1.pvcreate/* 代码 1*/int pvcreate(struct cmd_context *cmd, int argc, char *argv)int i;int ret = ECMD_PROCESSED;struct pvcreate_params pp;struct physical_volume *pv;/* 给 pp 设置默认值 */pvcreate_params_set_defaults(/* 检查 pvcreate 需要保存到磁盘的参数,如 restorefile、uuid,并传给 pp 结构体 */i

2、f (!pvcreate_restore_params_validate(cmd, argc, argv, /* 检查 pvcreate 不需要保存到磁盘的参数(见 man pvcreate) ,并传给 pp 结构体 */if (!pvcreate_params_validate(cmd, argc, argv, /* 将用户输入的所有 device 转换成 PV */for (i = 0; i idp) / 如果 UUID 存在(比如用户指定一个 UUID)if (dev = lvmcache_device_from_pvid(cmd, pp-idp, NULL, NULL) log_err

3、or(“uuid %s already in use on “%s“, buffer,dev_name(dev);goto bad;/ 上述缓存为两个 hash 表,在 lvm 启动的时候初始化if (!pvcreate_check(cmd, pv_name, pp)goto_bad;if (sigint_caught()goto_bad;if (!(dev = dev_cache_get(pv_name, cmd-filter) log_error(“%s: Couldnt find device. Check your filters?“,pv_name);goto bad;dm_list

4、_init(/* pv_create 函数见代码 3,作用是:创建并填充 pv 结构体 */if (!(pv = pv_create(cmd, dev, pp-idp, pp-size,pp-data_alignment, pp-data_alignment_offset,pp-pe_start ? pp-pe_start : PV_PE_START_CALC,pp-extent_count, pp-extent_size,pp-labelsector, pp-pvmetadatacopies,pp-pvmetadatasize, pp-metadataignore) log_error(“F

5、ailed to setup physical volume “%s“, pv_name);goto bad;log_verbose(“Set up physical volume for “%s“ with %“ PRIu64“ available sectors“, pv_name, pv_size(pv);if (write_now) struct pv_to_create pvc;pvc.pp = pp;pvc.pv = pv;if (!_pvcreate_write(cmd, else pv-status |= UNLABELLED_PV;return pv;bad:return N

6、ULL;1.3.pv_create/* 代码 3* pv_create - initialize a physical volume for use with a volume group* created PV belongs to Orphan VG.* fmt: format type* dev: PV device to initialize* size: size of the PV in sectors* data_alignment: requested alignment of data* data_alignment_offset: requested offset to a

7、ligned data* pe_start: physical extent start* existing_extent_count* existing_extent_size* pvmetadatacopies* pvmetadatasize* mdas* Returns:* PV handle - physical volume initialized successfully* NULL - invalid parameter or problem initializing the physical volume* Note:* FIXME: shorten argument list

8、 and replace with explict set functions*/struct physical_volume *pv_create(const struct cmd_context *cmd,struct device *dev,struct id *id, uint64_t size,unsigned long data_alignment,unsigned long data_alignment_offset,uint64_t pe_start,uint32_t existing_extent_count,uint32_t existing_extent_size,uin

9、t64_t label_sector,unsigned pvmetadatacopies,uint64_t pvmetadatasize,unsigned metadataignore)const struct format_type *fmt = cmd-fmt;struct dm_pool *mem = fmt-orphan_vg-vgmem;struct physical_volume *pv = _alloc_pv(mem, dev);unsigned mda_index;struct pv_list *pvl;if (!pv)return_NULL;if (id)memcpy(els

10、e if (!id_create(goto bad;if (!dev_get_size(pv-dev, goto bad;if (size) if (size pv-size)log_warn(“WARNING: %s: Overriding real size. “You could lose data.“, pv_dev_name(pv);log_verbose(“%s: Pretending size is %“ PRIu64 “ sectors.“,pv_dev_name(pv), size);pv-size = size;if (pv-size size pv = pv;add_pv

11、l_to_vgs(fmt-orphan_vg, pvl);fmt-orphan_vg-extent_count += pv-pe_count;fmt-orphan_vg-free_count += pv-pe_count;pv-fmt = fmt;pv-vg_name = fmt-orphan_vg_name;if (!fmt-ops-pv_initialise(fmt, label_sector, pe_start,existing_extent_count, existing_extent_size,data_alignment, data_alignment_offset, pv) lo

12、g_error(“Format-specific initialisation of physical “volume %s failed.“, pv_dev_name(pv);goto bad;for (mda_index = 0; mda_index fmt-ops-pv_add_metadata_area goto bad;return pv;bad:/ FIXME: detach from orphan in error path/free_pv_fid(pv);/dm_pool_free(mem, pv);return NULL;1.4._pvcreate_write/* 代码 4*

13、/static int _pvcreate_write(struct cmd_context *cmd, struct pv_to_create *pvc)int zero = pvc-pp-zero;struct physical_volume *pv = pvc-pv;struct device *dev = pv-dev;const char *pv_name = dev_name(dev);/* Wipe existing label first */if (!label_remove(pv_dev(pv) log_error(“Failed to wipe existing labe

14、l on %s“, pv_name);return 0;if (zero) log_verbose(“Zeroing start of device %s“, pv_name);if (!dev_open_quiet(dev) log_error(“%s not opened: device not zeroed“, pv_name);return 0;if (!dev_set(dev, UINT64_C(0), (size_t) 2048, 0) log_error(“%s not wiped: aborting“, pv_name);if (!dev_close(dev)stack;ret

15、urn 0;if (!dev_close(dev)stack;log_error(“Writing physical volume data to disk “%s“,pv_name);if (!(pv_write(cmd, pv, 1) / 很明显,这个命令就是写磁盘用的,详见代码 5log_error(“Failed to write physical volume “%s“, pv_name);return 0;log_print(“Physical volume “%s“ successfully created“, pv_name);return 1;1.5.pv_write/* 代

16、码 5* 调用 pv-fmt-ops-pv_write 函数* 代码 3 中,第一句就是:const struct format_type *fmt = cmd-fmt;之后 pv-fmt = fmt;* 所以找 pv_write 函数,需从 cmd 结构体下手* 另外有个蛋疼的名词:orphan,词典解释:孤儿。从别人的邮件里面窥到:* Orphan PV is device with PV label which is not attached to any Volume Group.* 使用 pvcreate 创建 PV 时,就是一个 Orphan PV,将 PV 加入到 VG 后,就不

17、是 Orphan PV 了*/int pv_write(struct cmd_context *cmd _attribute_(unused),struct physical_volume *pv, int allow_non_orphan)if (!pv-fmt-ops-pv_write) log_error(“Format does not support writing physical volumes“);return 0;/* FIXME: Try to remove this restriction. This requires checking* that the PV and

18、the VG are in a consistent state. We need* to provide some revert mechanism since PV label together* with VG metadata write is not atomic.*/if (!allow_non_orphan return 0;/如何实现 pv_write 函数的调用,需从 cmd 结构体下手,详见“探索 cmd_context”小节if (!pv-fmt-ops-pv_write(pv-fmt, pv) return_0;if (!lvmetad_pv_found(pv-id,

19、pv-dev, pv-fmt, pv-label_sector, NULL)return_0;return 1;2. 探索 cmd_context本小节探索如何使用 cmd_context 这个结构体的数据来源2.1.lvm2_main/*代码 1*命令执行的主程序*/int lvm2_main(int argc, char *argv)const char *base;int ret, alias = 0;struct cmd_context *cmd;/* 获取命令,如果用户输入 /sbin/pvcreate,则 base=pvcreate */base = last_path_compo

20、nent(argv0);if (strcmp(base, “lvm“) /alias 为 1,表示不在 lvm 界面(在终端输入 lvm 指令,即进入 lvm 界面)_close_stray_fds(base);/*is_static()返回 lvm-globals.c 中定义的_is_static 变量值,这个值会由 init_is_static 函数改变*/if (is_static() if (execvp(LVM_SHARED_PATH, argv) = -1)log_sys_error(“execvp“, “LVM_SHARED_PATH“);if (unsetenv(“LVM_DI

21、D_EXEC“)log_sys_error(“unsetenv“, “LVM_DID_EXEC“);/* “version“ command is simple enough so it doesnt need any complex init */if (!alias /* hiahiahia,这就是创造 cmd 变量并赋予内存空间的函数,见代码 4 */if (!(cmd = init_lvm()return -1;cmd-argv = argv;lvm_register_commands();/ 注册命令,往_cmdline 变量塞命令的属性,详见“探索 cmdline_context”

22、一节if (_lvm1_fallback(cmd) /* Attempt to run equivalent LVM1 tool instead */if (!alias) argv+;argc-;if (!argc) log_error(“Falling back to LVM1 tools, but no “command specified.“);ret = ECMD_FAILED;goto out;_exec_lvm1_command(argv);ret = ECMD_FAILED;goto out;#ifdef READLINE_SUPPORTif (!alias ret = lvm

23、_shell(cmd, goto out;#endifif (!alias) if (argc command 指针接管,*最后运行 cmd-command-fn(cmd, argc, argv)*/int lvm_run_command(struct cmd_context *cmd, int argc, char *argv)int ret = 0;int locking_type;int monitoring;struct dm_config_tree *old_cft;init_error_message_produced(0);/* each command should start

24、 out with sigint flag cleared */sigint_clear();if (!(cmd-cmd_line = _copy_command_line(cmd, argc, argv) stack;return ECMD_FAILED;log_debug(“Parsing: %s“, cmd-cmd_line);/* 将 cmd-command 指针指向_mands 指针指向的内存空间,见代码 3 */if (!(cmd-command = _find_command(argv0)/argv0为用户输入的命令,已注册在_cmdline 中return ENO_SUCH_C

25、MD;/*见_process_command_line 小节*/if (!_process_command_line(cmd, return EINVALID_CMD_LINE;set_cmd_name(cmd-command-name);if (arg_count(cmd, config_ARG)if (override_config_tree_from_string(cmd, arg_str_value(cmd, config_ARG, “) ret = EINVALID_CMD_LINE;goto_out;if (arg_count(cmd, config_ARG) | !cmd-con

26、fig_valid | config_files_changed(cmd) /* Reinitialise various settings inc. logging, filters */if (!refresh_toolcontext(cmd) old_cft = remove_overridden_config_tree(cmd);if (old_cft)dm_config_destroy(old_cft);log_error(“Updated config file invalid. Aborting.“);return ECMD_FAILED;/* 根据已有的 cmd 结构体里面的参

27、数,填充 cmd 这个结构体。成功则返回 0 */if (ret = _get_settings(cmd)goto_out;_apply_settings(cmd); /这个函数设置了 cmd-fmt 参数,此参数在 pvcreate 函数中会被用到。详见代码 6if (!get_activation_monitoring_mode(cmd, init_dmeventd_monitor(monitoring);log_debug(“Processing: %s“, cmd-cmd_line);#ifdef O_DIRECT_SUPPORTlog_debug(“O_DIRECT will be

28、used“);#endifif (ret = _process_common_commands(cmd) if (ret != ECMD_PROCESSED)stack;goto out;if (cmd-metadata_read_only goto out;if (arg_count(cmd, nolocking_ARG)locking_type = 0;elselocking_type = -1;if (!init_locking(locking_type, cmd, arg_count(cmd, sysinit_ARG) ret = ECMD_FAILED;goto out;ret =

29、cmd-command-fn(cmd, argc, argv);/详细解释,见 lvm_register_commands 函数的注释部分fin_locking();out:if (test_mode() log_verbose(“Test mode: Wiping internal cache“);lvmcache_destroy(cmd, 1);if (old_cft = remove_overridden_config_tree(cmd) dm_config_destroy(old_cft);/* Move this? */if (!refresh_toolcontext(cmd)sta

30、ck;/* FIXME Move this? */cmd-current_settings = cmd-default_settings;_apply_settings(cmd);if (ret = EINVALID_CMD_LINE log_debug(“Completed: %s“, cmd-cmd_line);/* free off any memory the command used.*/dm_list_init(dm_pool_empty(cmd-mem);reset_lvm_errno(1);reset_log_duplicated();return ret;2.3._proce

31、ss_command_line/* 此函数的作用是逐个解析命令输入的参数,并判断输入的某个参数是否需要执行额外的函数。* 如果需要执行额外的函数,则用户为这个参数提供 option 值,getopt 函数上表现为“u:a:”此类的形式,* 表明如果用户输入-u 参数,则需要给 -u 参数提供 option 值* cmd_context 为用户输入命令时产生的结构体,* 不像 cmdline_context 以及其指向的 arg_props、command 结构体,静态存在于内存中*/static int _process_command_line(struct cmd_context *cmd

32、, int *argc,char *argv)int i, opt, arg;char str(ARG_COUNT + 1) * 2) + 1, *ptr = str; /存放一个命令的所有短参数(如 u:a:)struct option optsARG_COUNT + 1, *o = opts; /存放长参数struct arg_props *a;struct arg_values *av;struct arg_value_group_list *current_group = NULL;/*cmd-arg_values 指针指向一大块内存块,ARG_COUNT 为 LVM 命令所支持的所有

33、参数的数量*/if (!(cmd-arg_values = dm_pool_zalloc(cmd-mem, sizeof(*cmd-arg_values) * ARG_COUNT) log_fatal(“Unable to allocate memory for command line arguments.“);return 0;/* fill in the short and long opts * _add_getopt_arg 见下面小节,* cmd-command-num_args 是 cmd-command 这个命令(如 pvcreate)支持的所有参数的个数。*/for (i =

34、 0; i command-num_args; i+)_add_getopt_arg(cmd-command-valid_argsi, *ptr = 0;memset(o, 0, sizeof(*o);/* initialise getopt_long optind = OPTIND_INIT;/*一次获取一个参数,,但有些参数可以重复,比如 pvcreate -vvvv,每读到一个 v,就把这个参数的av-count 加 1*/while (opt = GETOPTLONG_FN(*argc, *argv, str, opts, NULL) = 0) if (opt = ?)return 0

35、;/*_find_arg 遍历 cmd-command 这个命令所支持的所有参数,找到 opt 所指参数的索引值,赋给 arg*/if (arg = _find_arg(cmd-command, opt) arg_values 指向上面分配的内存块,此内存块是一个结构体数组。将 arg 对应的内存地址赋给 av 指针,* 此时内存块还没有任何数据,接下来通过 av 指针获取数据。*/av = /*# grep -r “ARG_GROUPABLE“ .|grep args.h:./tools/args.h:arg(addtag_ARG, 0, “addtag“, tag_arg, ARG_GRO

36、UPABLE)./tools/args.h:arg(deltag_ARG, 0, “deltag“, tag_arg, ARG_GROUPABLE)./tools/args.h:arg(minor_ARG, 0, “minor“, minor_arg, ARG_GROUPABLE)./tools/args.h:arg(replace_ARG, 0, “replace“, string_arg, ARG_GROUPABLE)./tools/args.h:arg(major_ARG, j, “major“, major_arg, ARG_GROUPABLE)只有上述 5 个参数对应的 arg_pr

37、ogs 结构体中的 flag 域为 ARG_GROUPABLEAddtag:将一些 PV、VG、LV 做标记,比如可以将所有 VG 分成两组,一组标记database,另一组标记userdata。可以使用 vgchang -ay database 命令,将有database 标记的 vg 设为 active 状态*/if (a-flags return 0;dm_list_add(/* Maintain total argument count as well as count within each group */av-count+;av = /*# grep -r “ARG_COUNTA

38、BLE“ .|grep args.h:./tools/args.h:arg(debug_ARG, d, “debug“, NULL, ARG_COUNTABLE)./tools/args.h:arg(force_ARG, f, “force“, NULL, ARG_COUNTABLE)./tools/args.h:arg(verbose_ARG, v, “verbose“, NULL, ARG_COUNTABLE)*/if (av-count return 0;if (a-fn) /如果输入的参数需要执行另外函数,则需要用户输入参数(函数需要参数)if (!optarg) log_error(

39、“Option requires argument.“);return 0;av-value = optarg;/将参数的 option 值赋给 av-valueif (!a-fn(cmd, av) /执行该函数log_error(“Invalid argument for %s: %s“, a-long_arg, optarg);return 0;av-count+; /如果一个参数可以重复(比如 pvchange -vvvv) ,记录重复值*argc -= optind;*argv += optind;return 1;2.4._find_argstatic int _find_arg(s

40、truct command *com, int opt)struct arg_props *a;int i, arg;for (i = 0; i num_args; i+) /com-num_args 为命令(如 pvcreate)支持的参数总数/*com-valid_args 指向命令(如 pvcreate)支持的参数数组,*获取此参数在 LVM 中所有参数集合内的索引号,赋给 arg。*com-valid_args 指针如何被赋值,参考 _create_new_command*/arg = com-valid_argsi; a = _cmdline.arg_props + arg;/获取

41、XX_ARG 对应的属性/* opt should equal either the* short arg, or the index into* the_args.*/if (a-short_arg return -1;2.5._add_getopt_argstatic void _add_getopt_arg(int arg, char *ptr, struct option *o)struct arg_props *a = _cmdline.arg_props + arg;if (a-short_arg) *(*ptr)+ = a-short_arg; /将 a-short_arg(比如

42、参数 “u”)追加给字符串if (a-fn)*(*ptr)+ = :; /如果此参数属性的函数指针存在,则需要用户输入参数(将 u:追加给字符串)#ifdef HAVE_GETOPTLONGif (*(a-long_arg + 2) (*o)-name = a-long_arg + 2;(*o)-has_arg = a-fn ? 1 : 0;(*o)-flag = NULL;if (a-short_arg)(*o)-val = a-short_arg;else(*o)-val = arg + 128;(*o)+;#endif2.6._find_command/*代码 3 *_find_comm

43、and 函数从_cmdline 变量内查找命令 * 返回_mands 指针*/static struct command *_find_command(const char *name)int i;const char *base;base = last_path_component(name);for (i = 0; i = _cmdline.num_commands)return 0;return _mands + i;2.7.init_lvm/* 代码 4* 调用 create_toolcontext 函数,构造 cmd 变量,以及构造 fmt 变量*/struct cmd_contex

44、t *init_lvm(void)struct cmd_context *cmd;if (!udev_init_library_context()stack;if (!(cmd = create_toolcontext(0, NULL, 1, 0)/函数详见代码 5return_NULL;/_arg_props 为参数的属性结构体数组,为静态变量。在 tools/lvmcmdline.c 中被赋值_cmdline.arg_props = if (stored_errno() destroy_toolcontext(cmd);return_NULL;return cmd;2.8.create_t

45、oolcontext/* 代码 5* 给 cmd 指针分配内存空间,初始化 cmd 结构体中的部分元素* 对于 cmd-commands 指针赋值(最核心的部分) ,则要在 lvm_run_command 函数(代码 2)内进行*/struct cmd_context *create_toolcontext(unsigned is_long_lived,const char *system_dir,unsigned set_buffering,unsigned threaded)struct cmd_context *cmd;#ifdef M_MMAP_MAXmallopt(M_MMAP_MA

46、X, 0);#endifif (!setlocale(LC_ALL, “)log_very_verbose(“setlocale failed“);#ifdef INTL_PACKAGEbindtextdomain(INTL_PACKAGE, LOCALEDIR);#endifinit_syslog(DEFAULT_LOG_FACILITY);if (!(cmd = dm_zalloc(sizeof(*cmd) / 给 cmd 指针分配内存空间log_error(“Failed to allocate command context“);return NULL;cmd-is_long_live

47、d = is_long_lived;cmd-threaded = threaded ? 1 : 0;cmd-handles_missing_pvs = 0;cmd-handles_unknown_segments = 0;cmd-independent_metadata_areas = 0;cmd-hosttags = 0;dm_list_init(dm_list_init(dm_list_init(dm_list_init(dm_list_init(label_init();/* FIXME Make this configurable? */reset_lvm_errno(1);/* Se

48、t in/out stream buffering before glibc */if (set_buffering) /* Allocate 2 buffers */if (!(cmd-linebuffer = dm_malloc(2 * linebuffer_size) log_error(“Failed to allocate line buffer.“);goto out;if (setvbuf(stdin, cmd-linebuffer, _IOLBF, linebuffer_size) |setvbuf(stdout, cmd-linebuffer + linebuffer_size,_IOLBF, linebuffer_size) log_sys_error(“setvbuf“, “);goto out;/* Buffers are used for lines without n */* Environment variable LVM_SYSTEM_DIR overrides this below.*/if (system_dir)strncpy(cmd-system_dir, s

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报