(root)/
util-linux-2.39/
libblkid/
src/
topology/
topology.c
       1  /*
       2   * topology - gathers information about device topology
       3   *
       4   * Copyright 2009 Red Hat, Inc.  All rights reserved.
       5   *
       6   * This file may be redistributed under the terms of the
       7   * GNU Lesser General Public License.
       8   */
       9  
      10  #include <stdio.h>
      11  #include <string.h>
      12  #include <stdlib.h>
      13  #include <stddef.h>
      14  
      15  #include "topology.h"
      16  
      17  /**
      18   * SECTION:topology
      19   * @title: Topology information
      20   * @short_description: block device topology information.
      21   *
      22   * The topology chain provides details about Linux block devices, for more
      23   * information see:
      24   *
      25   *      Linux kernel Documentation/ABI/testing/sysfs-block
      26   *
      27   * NAME=value (tags) interface is enabled by blkid_probe_enable_topology(),
      28   * and provides:
      29   *
      30   * @LOGICAL_SECTOR_SIZE: this is the smallest unit the storage device can
      31   *                       address. It is typically 512 bytes.
      32   *
      33   * @PHYSICAL_SECTOR_SIZE: this is the smallest unit a physical storage device
      34   *                        can write atomically. It is usually the same as the
      35   *                        logical sector size but may be bigger.
      36   *
      37   * @MINIMUM_IO_SIZE: minimum size which is the device's preferred unit of I/O.
      38   *                   For RAID arrays it is often the stripe chunk size.
      39   *
      40   * @OPTIMAL_IO_SIZE: usually the stripe width for RAID or zero. For RAID arrays
      41   *                   it is usually the stripe width or the internal track size.
      42   *
      43   * @ALIGNMENT_OFFSET: indicates how many bytes the beginning of the device is
      44   *                    offset from the disk's natural alignment.
      45   *
      46   * The NAME=value tags are not defined when the corresponding topology value
      47   * is zero. The MINIMUM_IO_SIZE should be always defined if kernel provides
      48   * topology information.
      49   *
      50   * Binary interface:
      51   *
      52   * blkid_probe_get_topology()
      53   *
      54   * blkid_topology_get_'VALUENAME'()
      55   */
      56  static int topology_probe(blkid_probe pr, struct blkid_chain *chn);
      57  static void topology_free(blkid_probe pr, void *data);
      58  static int topology_is_complete(blkid_probe pr);
      59  static int topology_set_logical_sector_size(blkid_probe pr);
      60  
      61  /*
      62   * Binary interface
      63   */
      64  struct blkid_struct_topology {
      65  	unsigned long	alignment_offset;
      66  	unsigned long	minimum_io_size;
      67  	unsigned long	optimal_io_size;
      68  	unsigned long	logical_sector_size;
      69  	unsigned long	physical_sector_size;
      70  	unsigned long   dax;
      71  	uint64_t	diskseq;
      72  };
      73  
      74  /*
      75   * Topology chain probing functions
      76   */
      77  static const struct blkid_idinfo *idinfos[] =
      78  {
      79  #ifdef __linux__
      80  	&sysfs_tp_idinfo,
      81  	&ioctl_tp_idinfo,
      82  	&md_tp_idinfo,
      83  	&dm_tp_idinfo,
      84  	&lvm_tp_idinfo,
      85  	&evms_tp_idinfo
      86  #endif
      87  };
      88  
      89  
      90  /*
      91   * Driver definition
      92   */
      93  const struct blkid_chaindrv topology_drv = {
      94  	.id           = BLKID_CHAIN_TOPLGY,
      95  	.name         = "topology",
      96  	.dflt_enabled = FALSE,
      97  	.idinfos      = idinfos,
      98  	.nidinfos     = ARRAY_SIZE(idinfos),
      99  	.probe        = topology_probe,
     100  	.safeprobe    = topology_probe,
     101  	.free_data    = topology_free
     102  };
     103  
     104  /**
     105   * blkid_probe_enable_topology:
     106   * @pr: probe
     107   * @enable: TRUE/FALSE
     108   *
     109   * Enables/disables the topology probing for non-binary interface.
     110   *
     111   * Returns: 0 on success, or -1 in case of error.
     112   */
     113  int blkid_probe_enable_topology(blkid_probe pr, int enable)
     114  {
     115  	pr->chains[BLKID_CHAIN_TOPLGY].enabled = enable;
     116  	return 0;
     117  }
     118  
     119  /**
     120   * blkid_probe_get_topology:
     121   * @pr: probe
     122   *
     123   * This is a binary interface for topology values. See also blkid_topology_*
     124   * functions.
     125   *
     126   * This function is independent on blkid_do_[safe,full]probe() and
     127   * blkid_probe_enable_topology() calls.
     128   *
     129   * WARNING: the returned object will be overwritten by the next
     130   *          blkid_probe_get_topology() call for the same @pr. If you want to
     131   *          use more blkid_topology objects in the same time you have to create
     132   *          more blkid_probe handlers (see blkid_new_probe()).
     133   *
     134   * Returns: blkid_topology, or NULL in case of error.
     135   */
     136  blkid_topology blkid_probe_get_topology(blkid_probe pr)
     137  {
     138  	return (blkid_topology) blkid_probe_get_binary_data(pr,
     139  			&pr->chains[BLKID_CHAIN_TOPLGY]);
     140  }
     141  
     142  /*
     143   * The blkid_do_probe() backend.
     144   */
     145  static int topology_probe(blkid_probe pr, struct blkid_chain *chn)
     146  {
     147  	size_t i;
     148  
     149  	if (chn->idx < -1)
     150  		return -1;
     151  
     152  	if (!S_ISBLK(pr->mode))
     153  		return -EINVAL;	/* nothing, works with block devices only */
     154  
     155  	if (chn->binary) {
     156  		DBG(LOWPROBE, ul_debug("initialize topology binary data"));
     157  
     158  		if (chn->data)
     159  			/* reset binary data */
     160  			memset(chn->data, 0,
     161  					sizeof(struct blkid_struct_topology));
     162  		else {
     163  			chn->data = calloc(1,
     164  					sizeof(struct blkid_struct_topology));
     165  			if (!chn->data)
     166  				return -ENOMEM;
     167  		}
     168  	}
     169  
     170  	blkid_probe_chain_reset_values(pr, chn);
     171  
     172  	DBG(LOWPROBE, ul_debug("--> starting probing loop [TOPOLOGY idx=%d]",
     173  		chn->idx));
     174  
     175  	i = chn->idx < 0 ? 0 : chn->idx + 1U;
     176  
     177  	for ( ; i < ARRAY_SIZE(idinfos); i++) {
     178  		const struct blkid_idinfo *id = idinfos[i];
     179  
     180  		chn->idx = i;
     181  
     182  		if (id->probefunc) {
     183  			DBG(LOWPROBE, ul_debug("%s: call probefunc()", id->name));
     184  			if (id->probefunc(pr, NULL) != 0)
     185  				continue;
     186  		}
     187  
     188  		if (!topology_is_complete(pr))
     189  			continue;
     190  
     191  		/* generic for all probing drivers */
     192  		topology_set_logical_sector_size(pr);
     193  
     194  		DBG(LOWPROBE, ul_debug("<-- leaving probing loop (type=%s) [TOPOLOGY idx=%d]",
     195  			id->name, chn->idx));
     196  		return BLKID_PROBE_OK;
     197  	}
     198  
     199  	DBG(LOWPROBE, ul_debug("<-- leaving probing loop (failed) [TOPOLOGY idx=%d]",
     200  		chn->idx));
     201  	return BLKID_PROBE_NONE;
     202  }
     203  
     204  static void topology_free(blkid_probe pr __attribute__((__unused__)),
     205  			  void *data)
     206  {
     207  	free(data);
     208  }
     209  
     210  static int topology_set_value(blkid_probe pr, const char *name,
     211  				size_t structoff, unsigned long long data)
     212  {
     213  	struct blkid_chain *chn = blkid_probe_get_chain(pr);
     214  
     215  	if (!chn)
     216  		return -1;
     217  	if (!data)
     218  		return 0;	/* ignore zeros */
     219  
     220  	if (chn->binary) {
     221  		memcpy((char *) chn->data + structoff, &data, sizeof(data));
     222  		return 0;
     223  	}
     224  	return blkid_probe_sprintf_value(pr, name, "%llu", data);
     225  }
     226  
     227  
     228  /* the topology info is complete when we have at least "minimum_io_size" which
     229   * is provided by all blkid topology drivers */
     230  static int topology_is_complete(blkid_probe pr)
     231  {
     232  	struct blkid_chain *chn = blkid_probe_get_chain(pr);
     233  
     234  	if (!chn)
     235  		return FALSE;
     236  
     237  	if (chn->binary && chn->data) {
     238  		blkid_topology tp = (blkid_topology) chn->data;
     239  		if (tp->minimum_io_size)
     240  			return TRUE;
     241  	}
     242  
     243  	return __blkid_probe_lookup_value(pr, "MINIMUM_IO_SIZE") ? TRUE : FALSE;
     244  }
     245  
     246  int blkid_topology_set_alignment_offset(blkid_probe pr, int val)
     247  {
     248  	unsigned long xval;
     249  
     250  	/* Welcome to Hell. The kernel is able to return -1 as an
     251  	 * alignment_offset if no compatible sizes and alignments
     252  	 * exist for stacked devices.
     253  	 *
     254  	 * There is no way how libblkid caller can respond to the value -1, so
     255  	 * we will hide this corner case...
     256  	 *
     257  	 * (TODO: maybe we can export an extra boolean value 'misaligned' rather
     258  	 *  then complete hide this problem.)
     259  	 */
     260  	xval = val < 0 ? 0 : val;
     261  
     262  	return topology_set_value(pr,
     263  			"ALIGNMENT_OFFSET",
     264  			offsetof(struct blkid_struct_topology, alignment_offset),
     265  			xval);
     266  }
     267  
     268  int blkid_topology_set_minimum_io_size(blkid_probe pr, unsigned long val)
     269  {
     270  	return topology_set_value(pr,
     271  			"MINIMUM_IO_SIZE",
     272  			offsetof(struct blkid_struct_topology, minimum_io_size),
     273  			val);
     274  }
     275  
     276  int blkid_topology_set_optimal_io_size(blkid_probe pr, unsigned long val)
     277  {
     278  	return topology_set_value(pr,
     279  			"OPTIMAL_IO_SIZE",
     280  			offsetof(struct blkid_struct_topology, optimal_io_size),
     281  			val);
     282  }
     283  
     284  /* BLKSSZGET is provided on all systems since 2.3.3 -- so we don't have to
     285   * waste time with sysfs.
     286   */
     287  static int topology_set_logical_sector_size(blkid_probe pr)
     288  {
     289  	unsigned long val = blkid_probe_get_sectorsize(pr);
     290  
     291  	if (!val)
     292  		return -1;
     293  
     294  	return topology_set_value(pr,
     295  			"LOGICAL_SECTOR_SIZE",
     296  			offsetof(struct blkid_struct_topology, logical_sector_size),
     297  			val);
     298  }
     299  
     300  int blkid_topology_set_physical_sector_size(blkid_probe pr, unsigned long val)
     301  {
     302  	return topology_set_value(pr,
     303  			"PHYSICAL_SECTOR_SIZE",
     304  			offsetof(struct blkid_struct_topology, physical_sector_size),
     305  			val);
     306  }
     307  
     308  int blkid_topology_set_dax(blkid_probe pr, unsigned long val)
     309  {
     310  	return topology_set_value(pr,
     311  			"DAX",
     312  			offsetof(struct blkid_struct_topology, dax),
     313  			val);
     314  }
     315  
     316  int blkid_topology_set_diskseq(blkid_probe pr, uint64_t val)
     317  {
     318  	return topology_set_value(pr,
     319  			"DISKSEQ",
     320  			offsetof(struct blkid_struct_topology, diskseq),
     321  			val);
     322  }
     323  
     324  /**
     325   * blkid_topology_get_alignment_offset:
     326   * @tp: topology
     327   *
     328   * Returns: alignment offset in bytes or 0.
     329   */
     330  unsigned long blkid_topology_get_alignment_offset(blkid_topology tp)
     331  {
     332  	return tp->alignment_offset;
     333  }
     334  
     335  /**
     336   * blkid_topology_get_minimum_io_size:
     337   * @tp: topology
     338   *
     339   * Returns: minimum io size in bytes or 0.
     340   */
     341  unsigned long blkid_topology_get_minimum_io_size(blkid_topology tp)
     342  {
     343  	return tp->minimum_io_size;
     344  }
     345  
     346  /**
     347   * blkid_topology_get_optimal_io_size
     348   * @tp: topology
     349   *
     350   * Returns: optimal io size in bytes or 0.
     351   */
     352  unsigned long blkid_topology_get_optimal_io_size(blkid_topology tp)
     353  {
     354  	return tp->optimal_io_size;
     355  }
     356  
     357  /**
     358   * blkid_topology_get_logical_sector_size
     359   * @tp: topology
     360   *
     361   * Returns: logical sector size (BLKSSZGET ioctl) in bytes or 0.
     362   */
     363  unsigned long blkid_topology_get_logical_sector_size(blkid_topology tp)
     364  {
     365  	return tp->logical_sector_size;
     366  }
     367  
     368  /**
     369   * blkid_topology_get_physical_sector_size
     370   * @tp: topology
     371   *
     372   * Returns: logical sector size (BLKSSZGET ioctl) in bytes or 0.
     373   */
     374  unsigned long blkid_topology_get_physical_sector_size(blkid_topology tp)
     375  {
     376  	return tp->physical_sector_size;
     377  }
     378  
     379  /**
     380   * blkid_topology_get_dax
     381   * @tp: topology
     382   *
     383   * Returns: 1 if dax is supported, 0 otherwise.
     384   *
     385   * Since: 2.36
     386   */
     387  unsigned long blkid_topology_get_dax(blkid_topology tp)
     388  {
     389  	return tp->dax;
     390  }
     391  
     392  /**
     393   * blkid_topology_get_diskseq
     394   * @tp: topology
     395   *
     396   * Returns: disk sequence number
     397   *
     398   * Since: 2.39
     399   */
     400  uint64_t blkid_topology_get_diskseq(blkid_topology tp)
     401  {
     402  	return tp->diskseq;
     403  }