lsblk: add dependence between CD/DVD block and packet devices
This dependence is defined by $ cat /sys/class/pktcdvd/device_map pktcdvd0 252:0 11:0 Unfortunately, there is not any direct sysfs way how to refer this relationship in /sys/{block,dev/block}. So, we have to read the device_map file and then compare device numbers with the list. $ lsblk /dev/sr0 NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sr0 11:0 1 1024M 0 rom └─pktcdvd0 252:0 1 0B 0 disk Addresses: https://github.com/karelzak/util-linux/issues/1185 Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
parent
1e416dc0b9
commit
94ebe1d3e4
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
#include "lsblk.h"
|
||||
#include "sysfs.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
|
||||
void lsblk_reset_iter(struct lsblk_iter *itr, int direction)
|
||||
|
@ -244,6 +245,7 @@ struct lsblk_devtree *lsblk_new_devtree()
|
|||
|
||||
INIT_LIST_HEAD(&tr->roots);
|
||||
INIT_LIST_HEAD(&tr->devices);
|
||||
INIT_LIST_HEAD(&tr->pktcdvd_map);
|
||||
|
||||
DBG(TREE, ul_debugobj(tr, "alloc"));
|
||||
return tr;
|
||||
|
@ -268,6 +270,14 @@ void lsblk_unref_devtree(struct lsblk_devtree *tr)
|
|||
struct lsblk_device, ls_devices);
|
||||
lsblk_devtree_remove_device(tr, dev);
|
||||
}
|
||||
|
||||
while (!list_empty(&tr->pktcdvd_map)) {
|
||||
struct lsblk_devnomap *map = list_entry(tr->pktcdvd_map.next,
|
||||
struct lsblk_devnomap, ls_devnomap);
|
||||
list_del(&map->ls_devnomap);
|
||||
free(map);
|
||||
}
|
||||
|
||||
free(tr);
|
||||
}
|
||||
}
|
||||
|
@ -285,6 +295,15 @@ int lsblk_devtree_add_root(struct lsblk_devtree *tr, struct lsblk_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int lsblk_devtree_remove_root(struct lsblk_devtree *tr __attribute__((unused)),
|
||||
struct lsblk_device *dev)
|
||||
{
|
||||
DBG(TREE, ul_debugobj(tr, "remove root device 0x%p [%s]", dev, dev->name));
|
||||
list_del_init(&dev->ls_roots);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lsblk_devtree_next_root(struct lsblk_devtree *tr,
|
||||
struct lsblk_iter *itr,
|
||||
struct lsblk_device **dev)
|
||||
|
@ -374,6 +393,62 @@ int lsblk_devtree_remove_device(struct lsblk_devtree *tr, struct lsblk_device *d
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void read_pktcdvd_map(struct lsblk_devtree *tr)
|
||||
{
|
||||
char buf[PATH_MAX];
|
||||
FILE *f;
|
||||
|
||||
assert(tr->pktcdvd_read == 0);
|
||||
|
||||
f = ul_path_fopen(NULL, "r", _PATH_SYS_CLASS "/pktcdvd/device_map");
|
||||
if (!f)
|
||||
goto done;
|
||||
|
||||
while (fgets(buf, sizeof(buf), f)) {
|
||||
struct lsblk_devnomap *map;
|
||||
int pkt_maj, pkt_min, blk_maj, blk_min;
|
||||
|
||||
if (sscanf(buf, "%*s %d:%d %d:%d\n",
|
||||
&pkt_maj, &pkt_min,
|
||||
&blk_maj, &blk_min) != 4)
|
||||
continue;
|
||||
|
||||
map = malloc(sizeof(*map));
|
||||
if (!map)
|
||||
break;
|
||||
map->holder = makedev(pkt_maj, pkt_min);
|
||||
map->slave = makedev(blk_maj, blk_min);
|
||||
INIT_LIST_HEAD(&map->ls_devnomap);
|
||||
list_add_tail(&map->ls_devnomap, &tr->pktcdvd_map);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
done:
|
||||
tr->pktcdvd_read = 1;
|
||||
}
|
||||
|
||||
/* returns opposite device of @devno for blk->pkt relation -- e.g. if devno
|
||||
* is_slave (blk) then returns holder (pkt) and vice-versa */
|
||||
dev_t lsblk_devtree_pktcdvd_get_mate(struct lsblk_devtree *tr, dev_t devno, int is_slave)
|
||||
{
|
||||
struct list_head *p;
|
||||
|
||||
if (!tr->pktcdvd_read)
|
||||
read_pktcdvd_map(tr);
|
||||
if (list_empty(&tr->pktcdvd_map))
|
||||
return 0;
|
||||
|
||||
list_for_each(p, &tr->pktcdvd_map) {
|
||||
struct lsblk_devnomap *x = list_entry(p, struct lsblk_devnomap, ls_devnomap);
|
||||
|
||||
if (is_slave && devno == x->slave)
|
||||
return x->holder;
|
||||
if (!is_slave && devno == x->holder)
|
||||
return x->slave;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int device_dedupkey_is_equal(
|
||||
struct lsblk_device *dev,
|
||||
struct lsblk_device *pattern)
|
||||
|
|
|
@ -1267,6 +1267,26 @@ static struct lsblk_device *devtree_get_device_or_new(struct lsblk_devtree *tr,
|
|||
return dev;
|
||||
}
|
||||
|
||||
static struct lsblk_device *devtree_pktcdvd_get_dep(
|
||||
struct lsblk_devtree *tr,
|
||||
struct lsblk_device *dev,
|
||||
int want_slave)
|
||||
{
|
||||
char buf[PATH_MAX], *name;
|
||||
dev_t devno;
|
||||
|
||||
devno = lsblk_devtree_pktcdvd_get_mate(tr,
|
||||
makedev(dev->maj, dev->min), !want_slave);
|
||||
if (!devno)
|
||||
return NULL;
|
||||
|
||||
name = sysfs_devno_to_devname(devno, buf, sizeof(buf));
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
return devtree_get_device_or_new(tr, NULL, name);
|
||||
}
|
||||
|
||||
static int process_dependencies(
|
||||
struct lsblk_devtree *tr,
|
||||
struct lsblk_device *dev,
|
||||
|
@ -1357,6 +1377,7 @@ static int process_dependencies(
|
|||
DIR *dir;
|
||||
struct dirent *d;
|
||||
const char *depname;
|
||||
struct lsblk_device *dep = NULL;
|
||||
|
||||
assert(dev);
|
||||
|
||||
|
@ -1371,21 +1392,20 @@ static int process_dependencies(
|
|||
|
||||
if (!(lsblk->inverse ? dev->nslaves : dev->nholders)) {
|
||||
DBG(DEV, ul_debugobj(dev, " ignore (no slaves/holders)"));
|
||||
return 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
depname = lsblk->inverse ? "slaves" : "holders";
|
||||
dir = ul_path_opendir(dev->sysfs, depname);
|
||||
if (!dir) {
|
||||
DBG(DEV, ul_debugobj(dev, " ignore (no slaves/holders directory)"));
|
||||
return 0;
|
||||
goto done;
|
||||
}
|
||||
ul_path_close_dirfd(dev->sysfs);
|
||||
|
||||
DBG(DEV, ul_debugobj(dev, " %s: checking for '%s' dependence", dev->name, depname));
|
||||
|
||||
while ((d = xreaddir(dir))) {
|
||||
struct lsblk_device *dep = NULL;
|
||||
struct lsblk_device *disk = NULL;
|
||||
|
||||
/* Is the dependency a partition? */
|
||||
|
@ -1436,8 +1456,14 @@ next:
|
|||
ul_path_close_dirfd(disk->sysfs);
|
||||
}
|
||||
closedir(dir);
|
||||
done:
|
||||
dep = devtree_pktcdvd_get_dep(tr, dev, lsblk->inverse);
|
||||
|
||||
if (dep && lsblk_device_new_dependence(dev, dep) == 0) {
|
||||
lsblk_devtree_remove_root(tr, dep);
|
||||
process_dependencies(tr, dep, lsblk->inverse ? 0 : 1);
|
||||
}
|
||||
|
||||
DBG(DEV, ul_debugobj(dev, "%s: checking for '%s' -- done", dev->name, depname));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ struct lsblk {
|
|||
|
||||
int dedup_id;
|
||||
|
||||
|
||||
const char *sysroot;
|
||||
int flags; /* LSBLK_* */
|
||||
|
||||
|
@ -140,6 +141,18 @@ struct lsblk_device {
|
|||
|
||||
#define device_is_partition(_x) ((_x)->wholedisk != NULL)
|
||||
|
||||
/* Unfortunately, pktcdvd dependence on block device is not defined by
|
||||
* slave/holder symlinks. The struct lsblk_devnomap represents one line in
|
||||
* /sys/class/pktcdvd/device_map
|
||||
*/
|
||||
struct lsblk_devnomap {
|
||||
dev_t slave; /* packet device devno */
|
||||
dev_t holder; /* block device devno */
|
||||
|
||||
struct list_head ls_devnomap;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Note that lsblk tree uses bottom devices (devices without slaves) as root
|
||||
* of the tree, and partitions are interpreted as a dependence too; it means:
|
||||
|
@ -153,8 +166,10 @@ struct lsblk_devtree {
|
|||
|
||||
struct list_head roots; /* tree root devices */
|
||||
struct list_head devices; /* all devices */
|
||||
struct list_head pktcdvd_map; /* devnomap->ls_devnomap */
|
||||
|
||||
unsigned int is_inverse : 1; /* inverse tree */
|
||||
unsigned int is_inverse : 1, /* inverse tree */
|
||||
pktcdvd_read : 1;
|
||||
};
|
||||
|
||||
|
||||
|
@ -212,6 +227,8 @@ int lsblk_device_next_child(struct lsblk_device *dev,
|
|||
struct lsblk_iter *itr,
|
||||
struct lsblk_device **child);
|
||||
|
||||
dev_t lsblk_devtree_pktcdvd_get_mate(struct lsblk_devtree *tr, dev_t devno, int is_slave);
|
||||
|
||||
int lsblk_device_is_last_parent(struct lsblk_device *dev, struct lsblk_device *parent);
|
||||
int lsblk_device_next_parent(
|
||||
struct lsblk_device *dev,
|
||||
|
@ -222,6 +239,7 @@ struct lsblk_devtree *lsblk_new_devtree(void);
|
|||
void lsblk_ref_devtree(struct lsblk_devtree *tr);
|
||||
void lsblk_unref_devtree(struct lsblk_devtree *tr);
|
||||
int lsblk_devtree_add_root(struct lsblk_devtree *tr, struct lsblk_device *dev);
|
||||
int lsblk_devtree_remove_root(struct lsblk_devtree *tr, struct lsblk_device *dev);
|
||||
int lsblk_devtree_next_root(struct lsblk_devtree *tr,
|
||||
struct lsblk_iter *itr,
|
||||
struct lsblk_device **dev);
|
||||
|
|
Loading…
Reference in New Issue