📄 detect_multipath.c
字号:
/* * detect_multipath.c * * Copyright (C) 2000, 2001, Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * * 8/14/01 - Initial version snagged from the scsi_reserve package as * the scan_drives.c file and then modified to only do * multipath detection. *//* * This is a small and simple program that uses the scsi_reserve library * and the md library code to detect and create raidtab entries for any * multipath devices found on a system. */#include <stdio.h>#include <stdarg.h>#include <stdlib.h>#include <string.h>#include <fcntl.h>#include <linux/fs.h>#include <errno.h>#include <unistd.h>#include <popt.h>#include <sys/types.h>#include <sys/ioctl.h>#include <scsi/scsi.h>#include <scsi/sg.h>#include <scsi/scsi_ioctl.h>#include "common.h"#include "parser.h"#include "raidlib.h"#include "raid_io.h"#include "version.h"#include "scsi.h"#define NUM_SCSI_DEVICES 128#define MAX_PARTITIONS 16int global_verbose;int global_superblock;int global_new;struct poptOption popt_options[] = { {"verbose", 'v', POPT_ARG_NONE, &global_verbose, 0, "Print out extra information", NULL}, {"superblock", 's', POPT_ARG_NONE, &global_superblock, 0, "Print out only those devices that already have a valid multipath " "raid superblock", NULL}, {"new", 'n', POPT_ARG_NONE, &global_new, 0, "Print out only those devices that don't have a valid multipath " "superblock", NULL}, POPT_AUTOHELP {NULL, 0, 0, NULL, 0, NULL, NULL}};intmain(int argc, char *argv[]){ int fd, i, j, num_devs; scsi_sg_dev_t *sg_dev[NUM_SCSI_DEVICES]; char *buffer[NUM_SCSI_DEVICES]; poptContext context; context = poptGetContext(argv[0], argc, (const char **)argv, (const struct poptOption *)&popt_options, 0); i = poptGetNextOpt(context); if (i < -1) { poptPrintHelp(context, stderr, 0); exit(1); } if (global_superblock && global_new) { fprintf(stderr, "Only one of the -n or -s options are allowed\n"); exit(1); } if(prepare_raidlib()) exit(1); for (i = 0; i < NUM_SCSI_DEVICES; i++) { sg_dev[i] = NULL; buffer[i] = NULL; } i = 0; j = 0; do { if ((buffer[j] == NULL) && ((buffer[j] = malloc(128)) == NULL)) { fprintf(stderr, "Unable to allocate memory, exiting.\n"); exit(1); } if (i < 26) sprintf(buffer[j], "/dev/sd%c", i + 'a'); else sprintf(buffer[j], "/dev/sd%c%c", i / 26 + 'a' - 1, i % 26 + 'a'); fd = open(buffer[j], O_RDONLY | O_NDELAY); if (fd != -1) { sg_dev[j] = scsi_init_sg_device(fd, buffer[j]); if (sg_dev[j] && sg_dev[j]->initialized) j++; } } while (++i < NUM_SCSI_DEVICES); num_devs = j; if (global_verbose) printf("\nChecking for multipath drives...(%d devices)\n", num_devs); for (i = 0; i < num_devs - 1; i++) { int multipath_array[NUM_SCSI_DEVICES], k, l; k = 1; multipath_array[0] = i; multipath_array[k] = -1; for (j = i + 1; j < num_devs; j++) { int a0, a1, b0, b1; if (!sg_dev[i]->initialized || !sg_dev[j]->initialized) continue; a0 = sg_dev[i]->id_eui64[0]; a1 = sg_dev[i]->id_eui64[1]; b0 = sg_dev[j]->id_eui64[0]; b1 = sg_dev[j]->id_eui64[1]; if ((a0 || a1) && (b0 || b1) && ((a0 == b0) && (a1 == b1))) { if (global_verbose) printf("%s and %s are multiple paths to the same " "device (id_eui64)\n", sg_dev[i]->name, sg_dev[j]->name); multipath_array[k++] = j; continue; } else if ((a0 || a1 || b0 || b1) && ((a0 != b0) || (a1 != b1))) { continue; } a0 = sg_dev[i]->id_fcph[0]; a1 = sg_dev[i]->id_fcph[1]; b0 = sg_dev[j]->id_fcph[0]; b1 = sg_dev[j]->id_fcph[1]; if ((a0 || a1) && (b0 || b1) && ((a0 == b0) && (a1 == b1))) { if (global_verbose) printf("%s and %s are multiple paths to the same " "device (id_fcph)\n", sg_dev[i]->name, sg_dev[j]->name); multipath_array[k++] = j; continue; } else if ((a0 || a1 || b0 || b1) && ((a0 != b0) || (a1 != b1))) { continue; } if ((sg_dev[i]->scsi_dev_id == sg_dev[j]->scsi_dev_id) && (sg_dev[i]->scsi_dev_lun == sg_dev[j]->scsi_dev_lun) && !strcmp(sg_dev[i]->vendor, sg_dev[j]->vendor) && !strcmp(sg_dev[i]->product, sg_dev[j]->product) && !strcmp(sg_dev[i]->revision, sg_dev[j]->revision)) { if (sg_dev[i]->serial_number && sg_dev[j]->serial_number && !strcmp(sg_dev[i]->serial_number, sg_dev[j]->serial_number)) { if (global_verbose) printf("%s and %s are multiple paths to the same " "device (serial_number)\n", sg_dev[i]->name, sg_dev[j]->name); multipath_array[k++] = j; continue; } else if (sg_dev[i]->serial_number != NULL || sg_dev[j]->serial_number != NULL) { continue; } if (sg_dev[i]->id_vendor && sg_dev[j]->id_vendor && !strcmp(sg_dev[i]->id_vendor, sg_dev[j]->id_vendor)) { if (global_verbose) printf("%s and %s are multiple paths to the same " "device (id_vendor)\n", sg_dev[i]->name, sg_dev[j]->name); multipath_array[k++] = j; continue; } else if (sg_dev[i]->id_vendor != NULL || sg_dev[j]->id_vendor != NULL) { continue; } if (sg_dev[i]->id_nonunique && sg_dev[j]->id_nonunique && !strcmp(sg_dev[i]->id_nonunique, sg_dev[j]->id_nonunique)) { if (global_verbose) printf("%s and %s are multiple paths to the same " "device (id_nonunique)\n", sg_dev[i]->name, sg_dev[j]->name); multipath_array[k++] = j; continue; } else if (sg_dev[i]->id_vendor != NULL || sg_dev[j]->id_vendor != NULL) { continue; } } } if (k > 1) { int has_superblock; unsigned long nr_blocks; unsigned long sb_offset; unsigned char sb_buf[MD_SB_BYTES]; mdp_super_t *sb; sb = (mdp_super_t *)&sb_buf[0]; if (ioctl(sg_dev[i]->disk_fd, BLKGETSIZE, &nr_blocks) == -1) { perror("ioctl BLKGETSIZE"); fprintf(stderr, "Error getting size for %s\n", sg_dev[i]->name); continue; } if (nr_blocks < MD_RESERVED_BLOCKS) { fprintf(stderr, "Device %s is too small to be a raid device.\n", sg_dev[i]->name); continue; } nr_blocks >>= 1; /* convert to 1K blocks */ sb_offset = MD_NEW_SIZE_BLOCKS(nr_blocks); if (raidseek(sg_dev[i]->disk_fd, sb_offset) == -1) { perror("raidseek"); fprintf(stderr, "Unable to seek to superblock offset of %s\n", sg_dev[i]->name); continue; } if (read(sg_dev[i]->disk_fd, sb_buf, MD_SB_BYTES) != MD_SB_BYTES) { perror("read"); fprintf(stderr, "Short read for superblock from %s\n", sg_dev[i]->name); continue; } if (sb->md_magic == MD_SB_MAGIC && sb->level == MULTIPATH) has_superblock = 1; else has_superblock = 0; if (!(global_superblock && !has_superblock) && !(global_new && has_superblock)) { if (k == 2) { printf ("%s and %s are multiple paths to ", sg_dev[i]->name, sg_dev[multipath_array[1]]->name); if(has_superblock) printf("/dev/md%d\n", sb->md_minor); else printf("the same device\n"); /* mark it not-initialized, then we won't scan it again */ sg_dev[multipath_array[1]]->initialized = 0; } else { printf("%s, ", sg_dev[i]->name); for (j = 1; j < (k - 1); j++) { printf("%s, ", sg_dev[multipath_array[j]]->name); sg_dev[multipath_array[j]]->initialized = 0; } printf("and %s are multiple paths to ", sg_dev[multipath_array[j]]->name); if(has_superblock) printf("/dev/md%d\n", sb->md_minor); else printf("the same device\n"); sg_dev[multipath_array[j]]->initialized = 0; } } /* * Now process partitions on the main array device to see if * any of them have superblocks. */ for(l=1; l<MAX_PARTITIONS; l++) { int fd; char name[256]; sprintf(name,"%s%d",sg_dev[i]->name,l); if((fd = open(name,O_RDONLY | O_NDELAY)) == -1) continue; if (global_verbose) printf("Checking for a superblock on %s\n", name); if (ioctl(fd, BLKGETSIZE, &nr_blocks) == -1) { perror("ioctl BLKGETSIZE"); fprintf(stderr, "Error getting size for %s\n", name); continue; } if (nr_blocks < MD_RESERVED_BLOCKS) { fprintf(stderr, "Device %s is too small to be a raid " "device.\n", name); continue; } nr_blocks >>= 1; /* convert to 1K blocks */ sb_offset = MD_NEW_SIZE_BLOCKS(nr_blocks); if (raidseek(fd, sb_offset) == -1) { perror("raidseek"); fprintf(stderr, "Unable to seek to superblock offset of " "%s\n", name); continue; } if (read(fd, sb_buf, MD_SB_BYTES) != MD_SB_BYTES) { perror("read"); fprintf(stderr, "Short read for superblock from %s\n", name); continue; } /* When creating raid arrays, the MULTIPATH personality is * enumerated as 7. However, when parser.c actually puts * the level into the param block for being written out to * the real superblock, it uses -4 for MULTIPATH. So, * check that the sb->level == -4 here */ if (sb->md_magic == MD_SB_MAGIC && sb->level == -4) { has_superblock = 1; } else { has_superblock = 0; } if (has_superblock && !global_new) { printf("/dev/md%d = ", sb->md_minor); printf("%s, ", name); for (j = 1; j < (k - 1); j++) { printf("%s%d, ", sg_dev[multipath_array[j]]->name, l); } printf("%s%d\n", sg_dev[multipath_array[j]]->name, l); } } } } if (global_verbose) printf("\n"); exit(0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -