(root)/
util-linux-2.39/
libblkid/
src/
topology/
sysfs.c
       1  /*
       2   * sysfs based topology -- gathers topology information from Linux sysfs
       3   *
       4   * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
       5   *
       6   * This file may be redistributed under the terms of the
       7   * GNU Lesser General Public License.
       8   *
       9   * For more information see Linux kernel Documentation/ABI/testing/sysfs-block.
      10   */
      11  #include <stdio.h>
      12  #include <string.h>
      13  #include <stdlib.h>
      14  #include <inttypes.h>
      15  #include <sys/types.h>
      16  #include <sys/stat.h>
      17  #include <unistd.h>
      18  #include <errno.h>
      19  
      20  #include "sysfs.h"
      21  #include "topology.h"
      22  
      23  /*
      24   * Sysfs topology values (since 2.6.31, May 2009).
      25   */
      26  static const struct topology_val {
      27  
      28  	/* /sys/dev/block/<maj>:<min>/<ATTR> */
      29  	const char *attr;
      30  
      31  	/* functions to set probing result */
      32  	int (*set_ulong)(blkid_probe, unsigned long);
      33  	int (*set_int)(blkid_probe, int);
      34  	int (*set_u64)(blkid_probe, uint64_t);
      35  
      36  } topology_vals[] = {
      37  	{ "alignment_offset", NULL, blkid_topology_set_alignment_offset },
      38  	{ "queue/minimum_io_size", blkid_topology_set_minimum_io_size },
      39  	{ "queue/optimal_io_size", blkid_topology_set_optimal_io_size },
      40  	{ "queue/physical_block_size", blkid_topology_set_physical_sector_size },
      41  	{ "queue/dax", blkid_topology_set_dax },
      42  	{ "diskseq", .set_u64 = blkid_topology_set_diskseq },
      43  };
      44  
      45  static int probe_sysfs_tp(blkid_probe pr,
      46  		const struct blkid_idmag *mag __attribute__((__unused__)))
      47  {
      48  	dev_t dev;
      49  	int rc, set_parent = 1;
      50  	struct path_cxt *pc;
      51  	size_t i, count = 0;
      52  
      53  	dev = blkid_probe_get_devno(pr);
      54  	if (!dev)
      55  		return 1;
      56  	pc = ul_new_sysfs_path(dev, NULL, NULL);
      57  	if (!pc)
      58  		return 1;
      59  
      60  	rc = 1;		/* nothing (default) */
      61  
      62  	for (i = 0; i < ARRAY_SIZE(topology_vals); i++) {
      63  		const struct topology_val *val = &topology_vals[i];
      64  		int ok = ul_path_access(pc, F_OK, val->attr) == 0;
      65  
      66  		rc = 1;	/* nothing */
      67  
      68  		if (!ok && set_parent) {
      69  			dev_t disk = blkid_probe_get_wholedisk_devno(pr);
      70  			set_parent = 0;
      71  
      72  			/*
      73  			 * Read attributes from "disk" if the current device is
      74  			 * a partition. Note that sysfs ul_path_* API is able
      75  			 * to redirect requests to attributes if parent is set.
      76  			 */
      77  			if (disk && disk != dev) {
      78  				struct path_cxt *parent = ul_new_sysfs_path(disk, NULL, NULL);
      79  				if (!parent)
      80  					goto done;
      81  
      82  				sysfs_blkdev_set_parent(pc, parent);
      83  				ul_unref_path(parent);
      84  
      85  				/* try it again */
      86  				ok = ul_path_access(pc, F_OK, val->attr) == 0;
      87  			}
      88  		}
      89  		if (!ok)
      90  			continue;	/* attribute does not exist */
      91  
      92  		if (val->set_ulong) {
      93  			uint64_t data;
      94  
      95  			if (ul_path_read_u64(pc, &data, val->attr) != 0)
      96  				continue;
      97  			rc = val->set_ulong(pr, (unsigned long) data);
      98  
      99  		} else if (val->set_int) {
     100  			int64_t data;
     101  
     102  			if (ul_path_read_s64(pc, &data, val->attr) != 0)
     103  				continue;
     104  			rc = val->set_int(pr, (int) data);
     105  		} else if (val->set_u64) {
     106  			uint64_t data;
     107  
     108  			if (ul_path_read_u64(pc, &data, val->attr) != 0)
     109  				continue;
     110  			rc = val->set_u64(pr, data);
     111  		}
     112  
     113  		if (rc < 0)
     114  			goto done;	/* error */
     115  		if (rc == 0)
     116  			count++;
     117  	}
     118  
     119  done:
     120  	ul_unref_path(pc);		/* unref pc and parent */
     121  	if (count)
     122  		return 0;		/* success */
     123  	return rc;			/* error or nothing */
     124  }
     125  
     126  const struct blkid_idinfo sysfs_tp_idinfo =
     127  {
     128  	.name		= "sysfs",
     129  	.probefunc	= probe_sysfs_tp,
     130  	.magics		= BLKID_NONE_MAGIC
     131  };
     132