[lvm-devel] [PATCH 4/6] Improve ability to lookup primary device associated with partition
Mike Snitzer
snitzer at redhat.com
Thu Jul 23 02:53:05 UTC 2009
Improve lib/device/device.c:_primary_dev()'s ability to look up the
primary device associated with all partitions; including blkext
(e.g. partitions directly on MD). The same will also work for obscure
sysfs paths; e.g.: paths with mangled names like the HP cciss driver
uses: /sys/block/cciss!c0d0/cciss!c0d0p1/
Signed-off-by: Mike Snitzer <snitzer at redhat.com>
---
lib/device/device.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 56 insertions(+), 5 deletions(-)
diff --git a/lib/device/device.c b/lib/device/device.c
index e627517..93cd4bb 100644
--- a/lib/device/device.c
+++ b/lib/device/device.c
@@ -13,6 +13,7 @@
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <libgen.h> /* dirname, basename */
#include "lib.h"
#include "lvm-types.h"
#include "device.h"
@@ -289,21 +290,71 @@ static int _primary_dev(const char *sysfs_dir,
struct device *dev, dev_t *result)
{
char path[PATH_MAX+1];
+ char temp_path[PATH_MAX+1];
+ char buffer[64];
struct stat info;
+ FILE *fp;
+ int pri_maj, pri_min;
+ int ret = 0;
/* check if dev is a partition */
if (dm_snprintf(path, PATH_MAX, "%s/dev/block/%d:%d/partition",
sysfs_dir, (int)MAJOR(dev->dev), (int)MINOR(dev->dev)) < 0) {
log_error("dm_snprintf partition failed");
- return 0;
+ return ret;
}
if (stat(path, &info) < 0)
- return 0;
+ return ret;
- *result = dev->dev -
- (MINOR(dev->dev) % max_partitions(MAJOR(dev->dev)));
- return 1;
+ /*
+ * extract parent's path from the partition's symlink, e.g.:
+ * - readlink /sys/dev/block/259:0 = ../../block/md0/md0p1
+ * - dirname ../../block/md0/md0p1 = ../../block/md0
+ * - basename ../../block/md0/md0 = md0
+ * Parent's 'dev' sysfs attribute = /sys/block/md0/dev
+ */
+ if (readlink(dirname(path), temp_path, PATH_MAX) < 0) {
+ log_sys_error("readlink", path);
+ return ret;
+ }
+
+ if (dm_snprintf(path, PATH_MAX, "%s/block/%s/dev",
+ sysfs_dir, basename(dirname(temp_path))) < 0) {
+ log_error("dm_snprintf dev failed");
+ return ret;
+ }
+
+ /* finally, parse 'dev' attribute and create corresponding dev_t */
+ if (stat(path, &info) < 0) {
+ log_error("sysfs file %s does not exist", path);
+ return ret;
+ }
+
+ fp = fopen(path, "r");
+ if (!fp) {
+ log_sys_error("fopen", path);
+ return ret;
+ }
+
+ if (!fgets(buffer, sizeof(buffer), fp)) {
+ log_sys_error("fgets", path);
+ goto out;
+ }
+
+ if (sscanf(buffer, "%d:%d", &pri_maj, &pri_min) != 2) {
+ log_error("sysfs file %s not in expected MAJ:MIN format: %s",
+ path, buffer);
+ goto out;
+ }
+ *result = makedev(pri_maj, pri_min);
+ ret = 1;
+
+out:
+ if (fclose(fp))
+ log_sys_error("fclose", path);
+
+ return ret;
}
static unsigned long _dev_topology_attribute(const char *attribute,
--
1.6.2.5
More information about the lvm-devel
mailing list