/* * lvm topology * -- this is fallback for old systems where the topology information is not * exported by sysfs * * Copyright (C) 2009 Karel Zak * * This file may be redistributed under the terms of the * GNU Lesser General Public License. * */ #include #include #include #include #include #include #include #include #include #include "topology.h" #ifndef LVM_BLK_MAJOR # define LVM_BLK_MAJOR 58 #endif static int is_lvm_device(dev_t devno) { if (major(devno) == LVM_BLK_MAJOR) return 1; return blkid_driver_has_major("lvm", major(devno)); } static int probe_lvm_tp(blkid_probe pr, const struct blkid_idmag *mag __attribute__((__unused__))) { const char *paths[] = { "/usr/local/sbin/lvdisplay", "/usr/sbin/lvdisplay", "/sbin/lvdisplay" }; int lvpipe[] = { -1, -1 }, stripes = 0, stripesize = 0; FILE *stream = NULL; char *cmd = NULL, *devname = NULL, buf[1024]; size_t i; dev_t devno = blkid_probe_get_devno(pr); if (!devno) goto nothing; /* probably not a block device */ if (!is_lvm_device(devno)) goto nothing; for (i = 0; i < ARRAY_SIZE(paths); i++) { struct stat sb; if (stat(paths[i], &sb) == 0) { cmd = (char *) paths[i]; break; } } if (!cmd) goto nothing; devname = blkid_devno_to_devname(devno); if (!devname) goto nothing; if (pipe(lvpipe) < 0) { DBG(LOWPROBE, ul_debug("Failed to open pipe: errno=%d", errno)); goto nothing; } switch (fork()) { case 0: { char *lvargv[3]; /* Plumbing */ close(lvpipe[0]); if (lvpipe[1] != STDOUT_FILENO) dup2(lvpipe[1], STDOUT_FILENO); if (drop_permissions() != 0) exit(1); lvargv[0] = cmd; lvargv[1] = devname; lvargv[2] = NULL; execv(lvargv[0], lvargv); DBG(LOWPROBE, ul_debug("Failed to execute %s: errno=%d", cmd, errno)); exit(1); } case -1: DBG(LOWPROBE, ul_debug("Failed to forking: errno=%d", errno)); goto nothing; default: break; } stream = fdopen(lvpipe[0], "r" UL_CLOEXECSTR); if (!stream) goto nothing; while (fgets(buf, sizeof(buf), stream) != NULL) { if (!strncmp(buf, "Stripes", 7)) sscanf(buf, "Stripes %d", &stripes); if (!strncmp(buf, "Stripe size", 11)) sscanf(buf, "Stripe size (KByte) %d", &stripesize); } if (!stripes) goto nothing; blkid_topology_set_minimum_io_size(pr, stripesize << 10); blkid_topology_set_optimal_io_size(pr, (stripes * stripesize) << 10); free(devname); fclose(stream); close(lvpipe[1]); return 0; nothing: free(devname); if (stream) fclose(stream); else if (lvpipe[0] != -1) close(lvpipe[0]); if (lvpipe[1] != -1) close(lvpipe[1]); return 1; } const struct blkid_idinfo lvm_tp_idinfo = { .name = "lvm", .probefunc = probe_lvm_tp, .magics = BLKID_NONE_MAGIC };