Linux 文件系统中卷覆写导致UUID改变--更改卷的UUID

【UUID的来源】
  Linux系统中一个卷只有在格式化的时候才会拥有一个全局唯一ID(UUID),这个UUID将会存储于卷的superblock中,会被很多命令索引,可以参见文章《Linux获取卷或文件系统唯一标识(UUID)的四种通用方法》。


【问题】
  针对一个系统中存在多个相同UUID卷的解决方案之一即是对UUID冲突的卷赋予新的UUID或者维持其原有的UUID。
  Linux系统中对一个卷进行保护时,其metadata数据和非Metadata数据都将作为待保护数据被备份至后端存储设备中。那么当对一个卷的备份采用 byte-by-byte方式执行恢复操作的时,无论是恢复至原始卷还是恢复至一个新的卷,其都将和备份卷拥有相同的GUID/UUID/Volume GUID/FileSystem UUID。
  上述问题对应的应用场景:假设当前Linux系统存在两个LVM卷:lvmvol-01, lvmvol-02
    1. 对lvmvol-01进行全量备份,备份卷标记为:lvmvol-01-bakcup
    2. 将备份卷lvmvol-01-backup恢复至卷lvmvol-02
    3. 通过执行命令blkid发现:卷lvmvol-02的UUID将被改写为与lvmvol-01一样的UUID,也就是系统中同时存在两个相同UUID的卷。多数情况下,这将会引起未知错误,比如系统启动时候卷无法正常挂载。。。


【解决方法】
  本文将采用命令tune2fs来更新一个卷的GUID,从而解决不同卷GUID冲突问题。显然在某些实际应用场景中这种做法未必合理!需要注意的是,此命令无法对处于挂载状态的卷进行GUID信息更新。

  一般情况下,卷会被挂载到某一个目录以进行读写操作,此处假设卷lvmvol-02被挂载到mnt_point。

  1. 在卷lvmvol-02被覆写之前,记录其UUID;
  2. 在卷lvmvol-02被覆写之后,重置其UUID;
  3. 验证是否生效;
	/*
	 * util.h
	 */
    #define MAX_BUFFER_LENGTH 160
    
    int get_cmd_output_withoption(const char *cmd_str, char **ret_str, bool_t need_output);
	/*
	 * util.c
	 */
	int
	get_cmd_output_withoption(
			const char *cmd_str,
			char **ret_str,
			bool_t need_output)
	{
		int ret = 0;
		FILE *stream;
		char buffer[MAX_BUFFER_LENGTH];
		char * sub_str = NULL;
		stream = popen(cmd_str, "r");
		if (!stream) {
			printf("Unable to spawn command: '%s'.\n", cmd_str);
			return (-1);
		}
		
		if (TRUE == need_output && NULL != *ret_str) {
			if (NULL != lg_fgets(buffer, MAX_BUFFER_LENGTH, stream)) {
				// The LVM volume name length limits [1, 127], so we just read the first MAX_BUFFER_LENGTH data
				if (NULL != strchr(buffer, '\n')) {
					sub_str = strtok(buffer, "\n");
					strncpy(*ret_str, sub_str, strlen(sub_str)+1);
				}
			}
			printf("Command '%s' output: '%s'.\n", cmd_str, *ret_str);
		}
		ret = lg_pclose(stream);
		return (ret);
	}
/*
 * recover.c
 */
    #include <stdlib.h>
    #include <stdio.h>
    #include <blkid/blkid.h>
    #include <util.h>
    
    char *cmd_str = NULL;
	char *volume_name = NULL;
	char *original_volume_guid = NULL;
	char *source_volume_guid = b6259d20-c9f1-4fb2-993c-67531525f57f";
 	
 	// 1. 记录目标卷(被覆写)的UUID
    cmd_str = (char *)malloc(MAX_BUFFER_LENGTH * sizeof (char));
    volume_name = (char *)malloc(MAX_BUFFER_LENGTH * sizeof (char));
    if (NULL == cmd_str || NULL == volume_name) {
	    print("Unable to allocate memory!\n");
		goto out;
	}
    memset(cmd_str, '\0', MAX_BUFFER_LENGTH * sizeof (char));
    memset(volume_name, '\0', MAX_BUFFER_LENGTH * sizeof (char));
    sprintf(cmd_str, MAX_BUFFER_LENGTH, "mount | grep %s | awk \'{print $1}\'", mnt_point);
    
    // 1.1 执行命令,获取一个挂载点对应的卷名称
    if (get_cmd_output_withoption(cmd_str, &volume_name, TRUE)) {
        print("Error occurs when try to execute command: '%s'.\n", cmd_str);
        goto out;
    } 
    
    // 1.2 通过卷名获取其原始的UUID
    if (NULL != volume_name) {
 	    original_volume_guid = blkid_get_tag_value(NULL, "UUID", volume_name);
	} else {
	    print("The volume name is empty, please check!\n");
        goto out;
    }
  
    /* 2. 卷覆写操作业务逻辑 */
    ........................................
    ........................................
    ........................................

    // 3. 当目标卷的GUID和源卷的GUID不一样时,重置被覆写卷的UUID,若重置失败则退出
    if (NULL != original_volume_guid && NULL != volume_name && strcmp(source_volume_guid, original_volume_guid)) {
        memset(cmd_str, '\0', MAX_BUFFER_LENGTH * sizeof (char));
        // 命令tune2fs无法应用于处于挂载状态的卷信息的更新
        sprintf(cmd_str, MAX_BUFFER_LENGTH, "tune2fs -U %s %s", original_volume_guid, volume_name);
        // 3.1 执行命令,重置目标卷的UUID
		if (get_cmd_output_withoption(cmd_str, NULL, FALSE)) {
            print("Error occurs when try to execute command: '%s'.\n", cmd_str);
            goto out;
     }
  
// 资源释放
out:
    if (NULL != cmd_str) {
       free(cmd_str);
       cmd_str = NULL:
    }
    if (NULL != volume_name) {
       free(volume_name);
       volume_name = NULL:
    }
    ....
    ....
    ....

【验证】
  关于如何验证上述代码是否生效,可以参见文章《Linux获取卷或文件系统唯一标识(UUID)的四种通用方法》中方法,任选一种即可。


【参考资料】
http://ftp.ntu.edu.tw/linux/utils/util-linux/v2.26/libblkid-docs/libblkid-Search-and-iterate.html
https://www.techrepublic.com/blog/linux-and-open-source/drive-and-partition-backups-with-dd/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值