1*86d7f5d3SJohn Marino /* $NetBSD: device.c,v 1.1.1.2 2009/12/02 00:26:34 haad Exp $ */
2*86d7f5d3SJohn Marino
3*86d7f5d3SJohn Marino /*
4*86d7f5d3SJohn Marino * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5*86d7f5d3SJohn Marino * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
6*86d7f5d3SJohn Marino *
7*86d7f5d3SJohn Marino * This file is part of LVM2.
8*86d7f5d3SJohn Marino *
9*86d7f5d3SJohn Marino * This copyrighted material is made available to anyone wishing to use,
10*86d7f5d3SJohn Marino * modify, copy, or redistribute it subject to the terms and conditions
11*86d7f5d3SJohn Marino * of the GNU Lesser General Public License v.2.1.
12*86d7f5d3SJohn Marino *
13*86d7f5d3SJohn Marino * You should have received a copy of the GNU Lesser General Public License
14*86d7f5d3SJohn Marino * along with this program; if not, write to the Free Software Foundation,
15*86d7f5d3SJohn Marino * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16*86d7f5d3SJohn Marino */
17*86d7f5d3SJohn Marino
18*86d7f5d3SJohn Marino #include <libgen.h> /* dirname, basename */
19*86d7f5d3SJohn Marino #include "lib.h"
20*86d7f5d3SJohn Marino #include "lvm-types.h"
21*86d7f5d3SJohn Marino #include "device.h"
22*86d7f5d3SJohn Marino #include "metadata.h"
23*86d7f5d3SJohn Marino #include "filter.h"
24*86d7f5d3SJohn Marino #include "xlate.h"
25*86d7f5d3SJohn Marino
26*86d7f5d3SJohn Marino /* See linux/genhd.h and fs/partitions/msdos */
27*86d7f5d3SJohn Marino
28*86d7f5d3SJohn Marino #define PART_MAGIC 0xAA55
29*86d7f5d3SJohn Marino #define PART_MAGIC_OFFSET UINT64_C(0x1FE)
30*86d7f5d3SJohn Marino #define PART_OFFSET UINT64_C(0x1BE)
31*86d7f5d3SJohn Marino
32*86d7f5d3SJohn Marino struct partition {
33*86d7f5d3SJohn Marino uint8_t boot_ind;
34*86d7f5d3SJohn Marino uint8_t head;
35*86d7f5d3SJohn Marino uint8_t sector;
36*86d7f5d3SJohn Marino uint8_t cyl;
37*86d7f5d3SJohn Marino uint8_t sys_ind; /* partition type */
38*86d7f5d3SJohn Marino uint8_t end_head;
39*86d7f5d3SJohn Marino uint8_t end_sector;
40*86d7f5d3SJohn Marino uint8_t end_cyl;
41*86d7f5d3SJohn Marino uint32_t start_sect;
42*86d7f5d3SJohn Marino uint32_t nr_sects;
43*86d7f5d3SJohn Marino } __attribute__((packed));
44*86d7f5d3SJohn Marino
_is_partitionable(struct device * dev)45*86d7f5d3SJohn Marino static int _is_partitionable(struct device *dev)
46*86d7f5d3SJohn Marino {
47*86d7f5d3SJohn Marino int parts = max_partitions(MAJOR(dev->dev));
48*86d7f5d3SJohn Marino
49*86d7f5d3SJohn Marino /* All MD devices are partitionable via blkext (as of 2.6.28) */
50*86d7f5d3SJohn Marino if (MAJOR(dev->dev) == md_major())
51*86d7f5d3SJohn Marino return 1;
52*86d7f5d3SJohn Marino
53*86d7f5d3SJohn Marino if ((parts <= 1) || (MINOR(dev->dev) % parts))
54*86d7f5d3SJohn Marino return 0;
55*86d7f5d3SJohn Marino
56*86d7f5d3SJohn Marino return 1;
57*86d7f5d3SJohn Marino }
58*86d7f5d3SJohn Marino
_has_partition_table(struct device * dev)59*86d7f5d3SJohn Marino static int _has_partition_table(struct device *dev)
60*86d7f5d3SJohn Marino {
61*86d7f5d3SJohn Marino int ret = 0;
62*86d7f5d3SJohn Marino unsigned p;
63*86d7f5d3SJohn Marino uint16_t buf[SECTOR_SIZE/sizeof(uint16_t)];
64*86d7f5d3SJohn Marino uint16_t *part_magic;
65*86d7f5d3SJohn Marino struct partition *part;
66*86d7f5d3SJohn Marino
67*86d7f5d3SJohn Marino if (!dev_open(dev)) {
68*86d7f5d3SJohn Marino stack;
69*86d7f5d3SJohn Marino return -1;
70*86d7f5d3SJohn Marino }
71*86d7f5d3SJohn Marino
72*86d7f5d3SJohn Marino if (!dev_read(dev, UINT64_C(0), sizeof(buf), &buf))
73*86d7f5d3SJohn Marino goto_out;
74*86d7f5d3SJohn Marino
75*86d7f5d3SJohn Marino /* FIXME Check for other types of partition table too */
76*86d7f5d3SJohn Marino
77*86d7f5d3SJohn Marino /* Check for msdos partition table */
78*86d7f5d3SJohn Marino part_magic = buf + PART_MAGIC_OFFSET/sizeof(buf[0]);
79*86d7f5d3SJohn Marino if ((*part_magic == xlate16(PART_MAGIC))) {
80*86d7f5d3SJohn Marino part = (struct partition *) (buf + PART_OFFSET/sizeof(buf[0]));
81*86d7f5d3SJohn Marino for (p = 0; p < 4; p++, part++) {
82*86d7f5d3SJohn Marino /* Table is invalid if boot indicator not 0 or 0x80 */
83*86d7f5d3SJohn Marino if ((part->boot_ind & 0x7f)) {
84*86d7f5d3SJohn Marino ret = 0;
85*86d7f5d3SJohn Marino break;
86*86d7f5d3SJohn Marino }
87*86d7f5d3SJohn Marino /* Must have at least one non-empty partition */
88*86d7f5d3SJohn Marino if (part->nr_sects)
89*86d7f5d3SJohn Marino ret = 1;
90*86d7f5d3SJohn Marino }
91*86d7f5d3SJohn Marino }
92*86d7f5d3SJohn Marino
93*86d7f5d3SJohn Marino out:
94*86d7f5d3SJohn Marino if (!dev_close(dev))
95*86d7f5d3SJohn Marino stack;
96*86d7f5d3SJohn Marino
97*86d7f5d3SJohn Marino return ret;
98*86d7f5d3SJohn Marino }
99*86d7f5d3SJohn Marino
is_partitioned_dev(struct device * dev)100*86d7f5d3SJohn Marino int is_partitioned_dev(struct device *dev)
101*86d7f5d3SJohn Marino {
102*86d7f5d3SJohn Marino if (!_is_partitionable(dev))
103*86d7f5d3SJohn Marino return 0;
104*86d7f5d3SJohn Marino
105*86d7f5d3SJohn Marino return _has_partition_table(dev);
106*86d7f5d3SJohn Marino }
107*86d7f5d3SJohn Marino
108*86d7f5d3SJohn Marino #if 0
109*86d7f5d3SJohn Marino #include <sys/stat.h>
110*86d7f5d3SJohn Marino #include <sys/mman.h>
111*86d7f5d3SJohn Marino #include <stdio.h>
112*86d7f5d3SJohn Marino #include <unistd.h>
113*86d7f5d3SJohn Marino #include <fcntl.h>
114*86d7f5d3SJohn Marino #include <ctype.h>
115*86d7f5d3SJohn Marino
116*86d7f5d3SJohn Marino #include <errno.h>
117*86d7f5d3SJohn Marino #include <sys/ioctl.h>
118*86d7f5d3SJohn Marino #include <linux/fs.h>
119*86d7f5d3SJohn Marino #include <linux/major.h>
120*86d7f5d3SJohn Marino #include <linux/genhd.h>
121*86d7f5d3SJohn Marino
122*86d7f5d3SJohn Marino int _get_partition_type(struct dev_filter *filter, struct device *d);
123*86d7f5d3SJohn Marino
124*86d7f5d3SJohn Marino #define MINOR_PART(dev) (MINOR((dev)->dev) % max_partitions(MINOR((dev)->dev)))
125*86d7f5d3SJohn Marino
126*86d7f5d3SJohn Marino int is_extended_partition(struct device *d)
127*86d7f5d3SJohn Marino {
128*86d7f5d3SJohn Marino return (MINOR_PART(d) > 4) ? 1 : 0;
129*86d7f5d3SJohn Marino }
130*86d7f5d3SJohn Marino
131*86d7f5d3SJohn Marino struct device *dev_primary(struct dev_mgr *dm, struct device *d)
132*86d7f5d3SJohn Marino {
133*86d7f5d3SJohn Marino struct device *ret;
134*86d7f5d3SJohn Marino
135*86d7f5d3SJohn Marino ret = dev_by_dev(dm, d->dev - MINOR_PART(dm, d));
136*86d7f5d3SJohn Marino /* FIXME: Needs replacing with a 'refresh' */
137*86d7f5d3SJohn Marino if (!ret) {
138*86d7f5d3SJohn Marino init_dev_scan(dm);
139*86d7f5d3SJohn Marino ret = dev_by_dev(dm, d->dev - MINOR_PART(dm, d));
140*86d7f5d3SJohn Marino }
141*86d7f5d3SJohn Marino
142*86d7f5d3SJohn Marino return ret;
143*86d7f5d3SJohn Marino
144*86d7f5d3SJohn Marino }
145*86d7f5d3SJohn Marino
146*86d7f5d3SJohn Marino int partition_type_is_lvm(struct dev_mgr *dm, struct device *d)
147*86d7f5d3SJohn Marino {
148*86d7f5d3SJohn Marino int pt;
149*86d7f5d3SJohn Marino
150*86d7f5d3SJohn Marino pt = _get_partition_type(dm, d);
151*86d7f5d3SJohn Marino
152*86d7f5d3SJohn Marino if (!pt) {
153*86d7f5d3SJohn Marino if (is_whole_disk(dm, d))
154*86d7f5d3SJohn Marino /* FIXME: Overloaded pt=0 in error cases */
155*86d7f5d3SJohn Marino return 1;
156*86d7f5d3SJohn Marino else {
157*86d7f5d3SJohn Marino log_error
158*86d7f5d3SJohn Marino ("%s: missing partition table "
159*86d7f5d3SJohn Marino "on partitioned device", d->name);
160*86d7f5d3SJohn Marino return 0;
161*86d7f5d3SJohn Marino }
162*86d7f5d3SJohn Marino }
163*86d7f5d3SJohn Marino
164*86d7f5d3SJohn Marino if (is_whole_disk(dm, d)) {
165*86d7f5d3SJohn Marino log_error("%s: looks to possess partition table", d->name);
166*86d7f5d3SJohn Marino return 0;
167*86d7f5d3SJohn Marino }
168*86d7f5d3SJohn Marino
169*86d7f5d3SJohn Marino /* check part type */
170*86d7f5d3SJohn Marino if (pt != LVM_PARTITION && pt != LVM_NEW_PARTITION) {
171*86d7f5d3SJohn Marino log_error("%s: invalid partition type 0x%x "
172*86d7f5d3SJohn Marino "(must be 0x%x)", d->name, pt, LVM_NEW_PARTITION);
173*86d7f5d3SJohn Marino return 0;
174*86d7f5d3SJohn Marino }
175*86d7f5d3SJohn Marino
176*86d7f5d3SJohn Marino if (pt == LVM_PARTITION) {
177*86d7f5d3SJohn Marino log_error
178*86d7f5d3SJohn Marino ("%s: old LVM partition type found - please change to 0x%x",
179*86d7f5d3SJohn Marino d->name, LVM_NEW_PARTITION);
180*86d7f5d3SJohn Marino return 0;
181*86d7f5d3SJohn Marino }
182*86d7f5d3SJohn Marino
183*86d7f5d3SJohn Marino return 1;
184*86d7f5d3SJohn Marino }
185*86d7f5d3SJohn Marino
186*86d7f5d3SJohn Marino int _get_partition_type(struct dev_mgr *dm, struct device *d)
187*86d7f5d3SJohn Marino {
188*86d7f5d3SJohn Marino int pv_handle = -1;
189*86d7f5d3SJohn Marino struct device *primary;
190*86d7f5d3SJohn Marino ssize_t read_ret;
191*86d7f5d3SJohn Marino ssize_t bytes_read = 0;
192*86d7f5d3SJohn Marino char *buffer;
193*86d7f5d3SJohn Marino unsigned short *s_buffer;
194*86d7f5d3SJohn Marino struct partition *part;
195*86d7f5d3SJohn Marino loff_t offset = 0;
196*86d7f5d3SJohn Marino loff_t extended_offset = 0;
197*86d7f5d3SJohn Marino int part_sought;
198*86d7f5d3SJohn Marino int part_found = 0;
199*86d7f5d3SJohn Marino int first_partition = 1;
200*86d7f5d3SJohn Marino int extended_partition = 0;
201*86d7f5d3SJohn Marino int p;
202*86d7f5d3SJohn Marino
203*86d7f5d3SJohn Marino if (!(primary = dev_primary(dm, d))) {
204*86d7f5d3SJohn Marino log_error
205*86d7f5d3SJohn Marino ("Failed to find main device containing partition %s",
206*86d7f5d3SJohn Marino d->name);
207*86d7f5d3SJohn Marino return 0;
208*86d7f5d3SJohn Marino }
209*86d7f5d3SJohn Marino
210*86d7f5d3SJohn Marino if (!(buffer = dm_malloc(SECTOR_SIZE))) {
211*86d7f5d3SJohn Marino log_error("Failed to allocate partition table buffer");
212*86d7f5d3SJohn Marino return 0;
213*86d7f5d3SJohn Marino }
214*86d7f5d3SJohn Marino
215*86d7f5d3SJohn Marino /* Get partition table */
216*86d7f5d3SJohn Marino if ((pv_handle = open(primary->name, O_RDONLY)) < 0) {
217*86d7f5d3SJohn Marino log_error("%s: open failed: %s", primary->name,
218*86d7f5d3SJohn Marino strerror(errno));
219*86d7f5d3SJohn Marino return 0;
220*86d7f5d3SJohn Marino }
221*86d7f5d3SJohn Marino
222*86d7f5d3SJohn Marino s_buffer = (unsigned short *) buffer;
223*86d7f5d3SJohn Marino part = (struct partition *) (buffer + 0x1be);
224*86d7f5d3SJohn Marino part_sought = MINOR_PART(dm, d);
225*86d7f5d3SJohn Marino
226*86d7f5d3SJohn Marino do {
227*86d7f5d3SJohn Marino bytes_read = 0;
228*86d7f5d3SJohn Marino
229*86d7f5d3SJohn Marino if (llseek(pv_handle, offset * SECTOR_SIZE, SEEK_SET) == -1) {
230*86d7f5d3SJohn Marino log_error("%s: llseek failed: %s",
231*86d7f5d3SJohn Marino primary->name, strerror(errno));
232*86d7f5d3SJohn Marino return 0;
233*86d7f5d3SJohn Marino }
234*86d7f5d3SJohn Marino
235*86d7f5d3SJohn Marino while ((bytes_read < SECTOR_SIZE) &&
236*86d7f5d3SJohn Marino (read_ret =
237*86d7f5d3SJohn Marino read(pv_handle, buffer + bytes_read,
238*86d7f5d3SJohn Marino SECTOR_SIZE - bytes_read)) != -1)
239*86d7f5d3SJohn Marino bytes_read += read_ret;
240*86d7f5d3SJohn Marino
241*86d7f5d3SJohn Marino if (read_ret == -1) {
242*86d7f5d3SJohn Marino log_error("%s: read failed: %s", primary->name,
243*86d7f5d3SJohn Marino strerror(errno));
244*86d7f5d3SJohn Marino return 0;
245*86d7f5d3SJohn Marino }
246*86d7f5d3SJohn Marino
247*86d7f5d3SJohn Marino if (s_buffer[255] == 0xAA55) {
248*86d7f5d3SJohn Marino if (is_whole_disk(dm, d))
249*86d7f5d3SJohn Marino return -1;
250*86d7f5d3SJohn Marino } else
251*86d7f5d3SJohn Marino return 0;
252*86d7f5d3SJohn Marino
253*86d7f5d3SJohn Marino extended_partition = 0;
254*86d7f5d3SJohn Marino
255*86d7f5d3SJohn Marino /* Loop through primary partitions */
256*86d7f5d3SJohn Marino for (p = 0; p < 4; p++) {
257*86d7f5d3SJohn Marino if (part[p].sys_ind == DOS_EXTENDED_PARTITION ||
258*86d7f5d3SJohn Marino part[p].sys_ind == LINUX_EXTENDED_PARTITION
259*86d7f5d3SJohn Marino || part[p].sys_ind == WIN98_EXTENDED_PARTITION) {
260*86d7f5d3SJohn Marino extended_partition = 1;
261*86d7f5d3SJohn Marino offset = extended_offset + part[p].start_sect;
262*86d7f5d3SJohn Marino if (extended_offset == 0)
263*86d7f5d3SJohn Marino extended_offset = part[p].start_sect;
264*86d7f5d3SJohn Marino if (first_partition == 1)
265*86d7f5d3SJohn Marino part_found++;
266*86d7f5d3SJohn Marino } else if (first_partition == 1) {
267*86d7f5d3SJohn Marino if (p == part_sought) {
268*86d7f5d3SJohn Marino if (part[p].sys_ind == 0) {
269*86d7f5d3SJohn Marino /* missing primary? */
270*86d7f5d3SJohn Marino return 0;
271*86d7f5d3SJohn Marino }
272*86d7f5d3SJohn Marino } else
273*86d7f5d3SJohn Marino part_found++;
274*86d7f5d3SJohn Marino } else if (!part[p].sys_ind)
275*86d7f5d3SJohn Marino part_found++;
276*86d7f5d3SJohn Marino
277*86d7f5d3SJohn Marino if (part_sought == part_found)
278*86d7f5d3SJohn Marino return part[p].sys_ind;
279*86d7f5d3SJohn Marino
280*86d7f5d3SJohn Marino }
281*86d7f5d3SJohn Marino first_partition = 0;
282*86d7f5d3SJohn Marino }
283*86d7f5d3SJohn Marino while (extended_partition == 1);
284*86d7f5d3SJohn Marino
285*86d7f5d3SJohn Marino return 0;
286*86d7f5d3SJohn Marino }
287*86d7f5d3SJohn Marino #endif
288*86d7f5d3SJohn Marino
289*86d7f5d3SJohn Marino #ifdef linux
290*86d7f5d3SJohn Marino
get_primary_dev(const char * sysfs_dir,struct device * dev,dev_t * result)291*86d7f5d3SJohn Marino int get_primary_dev(const char *sysfs_dir,
292*86d7f5d3SJohn Marino struct device *dev, dev_t *result)
293*86d7f5d3SJohn Marino {
294*86d7f5d3SJohn Marino char path[PATH_MAX+1];
295*86d7f5d3SJohn Marino char temp_path[PATH_MAX+1];
296*86d7f5d3SJohn Marino char buffer[64];
297*86d7f5d3SJohn Marino struct stat info;
298*86d7f5d3SJohn Marino FILE *fp;
299*86d7f5d3SJohn Marino uint32_t pri_maj, pri_min;
300*86d7f5d3SJohn Marino int ret = 0;
301*86d7f5d3SJohn Marino
302*86d7f5d3SJohn Marino /* check if dev is a partition */
303*86d7f5d3SJohn Marino if (dm_snprintf(path, PATH_MAX, "%s/dev/block/%d:%d/partition",
304*86d7f5d3SJohn Marino sysfs_dir, (int)MAJOR(dev->dev), (int)MINOR(dev->dev)) < 0) {
305*86d7f5d3SJohn Marino log_error("dm_snprintf partition failed");
306*86d7f5d3SJohn Marino return ret;
307*86d7f5d3SJohn Marino }
308*86d7f5d3SJohn Marino
309*86d7f5d3SJohn Marino if (stat(path, &info) == -1) {
310*86d7f5d3SJohn Marino if (errno != ENOENT)
311*86d7f5d3SJohn Marino log_sys_error("stat", path);
312*86d7f5d3SJohn Marino return ret;
313*86d7f5d3SJohn Marino }
314*86d7f5d3SJohn Marino
315*86d7f5d3SJohn Marino /*
316*86d7f5d3SJohn Marino * extract parent's path from the partition's symlink, e.g.:
317*86d7f5d3SJohn Marino * - readlink /sys/dev/block/259:0 = ../../block/md0/md0p1
318*86d7f5d3SJohn Marino * - dirname ../../block/md0/md0p1 = ../../block/md0
319*86d7f5d3SJohn Marino * - basename ../../block/md0/md0 = md0
320*86d7f5d3SJohn Marino * Parent's 'dev' sysfs attribute = /sys/block/md0/dev
321*86d7f5d3SJohn Marino */
322*86d7f5d3SJohn Marino if (readlink(dirname(path), temp_path, PATH_MAX) < 0) {
323*86d7f5d3SJohn Marino log_sys_error("readlink", path);
324*86d7f5d3SJohn Marino return ret;
325*86d7f5d3SJohn Marino }
326*86d7f5d3SJohn Marino
327*86d7f5d3SJohn Marino if (dm_snprintf(path, PATH_MAX, "%s/block/%s/dev",
328*86d7f5d3SJohn Marino sysfs_dir, basename(dirname(temp_path))) < 0) {
329*86d7f5d3SJohn Marino log_error("dm_snprintf dev failed");
330*86d7f5d3SJohn Marino return ret;
331*86d7f5d3SJohn Marino }
332*86d7f5d3SJohn Marino
333*86d7f5d3SJohn Marino /* finally, parse 'dev' attribute and create corresponding dev_t */
334*86d7f5d3SJohn Marino if (stat(path, &info) == -1) {
335*86d7f5d3SJohn Marino if (errno == ENOENT)
336*86d7f5d3SJohn Marino log_error("sysfs file %s does not exist", path);
337*86d7f5d3SJohn Marino else
338*86d7f5d3SJohn Marino log_sys_error("stat", path);
339*86d7f5d3SJohn Marino return ret;
340*86d7f5d3SJohn Marino }
341*86d7f5d3SJohn Marino
342*86d7f5d3SJohn Marino fp = fopen(path, "r");
343*86d7f5d3SJohn Marino if (!fp) {
344*86d7f5d3SJohn Marino log_sys_error("fopen", path);
345*86d7f5d3SJohn Marino return ret;
346*86d7f5d3SJohn Marino }
347*86d7f5d3SJohn Marino
348*86d7f5d3SJohn Marino if (!fgets(buffer, sizeof(buffer), fp)) {
349*86d7f5d3SJohn Marino log_sys_error("fgets", path);
350*86d7f5d3SJohn Marino goto out;
351*86d7f5d3SJohn Marino }
352*86d7f5d3SJohn Marino
353*86d7f5d3SJohn Marino if (sscanf(buffer, "%d:%d", &pri_maj, &pri_min) != 2) {
354*86d7f5d3SJohn Marino log_error("sysfs file %s not in expected MAJ:MIN format: %s",
355*86d7f5d3SJohn Marino path, buffer);
356*86d7f5d3SJohn Marino goto out;
357*86d7f5d3SJohn Marino }
358*86d7f5d3SJohn Marino *result = MKDEV(pri_maj, pri_min);
359*86d7f5d3SJohn Marino ret = 1;
360*86d7f5d3SJohn Marino
361*86d7f5d3SJohn Marino out:
362*86d7f5d3SJohn Marino if (fclose(fp))
363*86d7f5d3SJohn Marino log_sys_error("fclose", path);
364*86d7f5d3SJohn Marino
365*86d7f5d3SJohn Marino return ret;
366*86d7f5d3SJohn Marino }
367*86d7f5d3SJohn Marino
_dev_topology_attribute(const char * attribute,const char * sysfs_dir,struct device * dev)368*86d7f5d3SJohn Marino static unsigned long _dev_topology_attribute(const char *attribute,
369*86d7f5d3SJohn Marino const char *sysfs_dir,
370*86d7f5d3SJohn Marino struct device *dev)
371*86d7f5d3SJohn Marino {
372*86d7f5d3SJohn Marino const char *sysfs_fmt_str = "%s/dev/block/%d:%d/%s";
373*86d7f5d3SJohn Marino char path[PATH_MAX+1], buffer[64];
374*86d7f5d3SJohn Marino FILE *fp;
375*86d7f5d3SJohn Marino struct stat info;
376*86d7f5d3SJohn Marino dev_t uninitialized_var(primary);
377*86d7f5d3SJohn Marino unsigned long result = 0UL;
378*86d7f5d3SJohn Marino
379*86d7f5d3SJohn Marino if (!attribute || !*attribute)
380*86d7f5d3SJohn Marino return_0;
381*86d7f5d3SJohn Marino
382*86d7f5d3SJohn Marino if (!sysfs_dir || !*sysfs_dir)
383*86d7f5d3SJohn Marino return_0;
384*86d7f5d3SJohn Marino
385*86d7f5d3SJohn Marino if (dm_snprintf(path, PATH_MAX, sysfs_fmt_str, sysfs_dir,
386*86d7f5d3SJohn Marino (int)MAJOR(dev->dev), (int)MINOR(dev->dev),
387*86d7f5d3SJohn Marino attribute) < 0) {
388*86d7f5d3SJohn Marino log_error("dm_snprintf %s failed", attribute);
389*86d7f5d3SJohn Marino return 0;
390*86d7f5d3SJohn Marino }
391*86d7f5d3SJohn Marino
392*86d7f5d3SJohn Marino /*
393*86d7f5d3SJohn Marino * check if the desired sysfs attribute exists
394*86d7f5d3SJohn Marino * - if not: either the kernel doesn't have topology support
395*86d7f5d3SJohn Marino * or the device could be a partition
396*86d7f5d3SJohn Marino */
397*86d7f5d3SJohn Marino if (stat(path, &info) == -1) {
398*86d7f5d3SJohn Marino if (errno != ENOENT) {
399*86d7f5d3SJohn Marino log_sys_error("stat", path);
400*86d7f5d3SJohn Marino return 0;
401*86d7f5d3SJohn Marino }
402*86d7f5d3SJohn Marino if (!get_primary_dev(sysfs_dir, dev, &primary))
403*86d7f5d3SJohn Marino return 0;
404*86d7f5d3SJohn Marino
405*86d7f5d3SJohn Marino /* get attribute from partition's primary device */
406*86d7f5d3SJohn Marino if (dm_snprintf(path, PATH_MAX, sysfs_fmt_str, sysfs_dir,
407*86d7f5d3SJohn Marino (int)MAJOR(primary), (int)MINOR(primary),
408*86d7f5d3SJohn Marino attribute) < 0) {
409*86d7f5d3SJohn Marino log_error("primary dm_snprintf %s failed", attribute);
410*86d7f5d3SJohn Marino return 0;
411*86d7f5d3SJohn Marino }
412*86d7f5d3SJohn Marino if (stat(path, &info) == -1) {
413*86d7f5d3SJohn Marino if (errno != ENOENT)
414*86d7f5d3SJohn Marino log_sys_error("stat", path);
415*86d7f5d3SJohn Marino return 0;
416*86d7f5d3SJohn Marino }
417*86d7f5d3SJohn Marino }
418*86d7f5d3SJohn Marino
419*86d7f5d3SJohn Marino if (!(fp = fopen(path, "r"))) {
420*86d7f5d3SJohn Marino log_sys_error("fopen", path);
421*86d7f5d3SJohn Marino return 0;
422*86d7f5d3SJohn Marino }
423*86d7f5d3SJohn Marino
424*86d7f5d3SJohn Marino if (!fgets(buffer, sizeof(buffer), fp)) {
425*86d7f5d3SJohn Marino log_sys_error("fgets", path);
426*86d7f5d3SJohn Marino goto out;
427*86d7f5d3SJohn Marino }
428*86d7f5d3SJohn Marino
429*86d7f5d3SJohn Marino if (sscanf(buffer, "%lu", &result) != 1) {
430*86d7f5d3SJohn Marino log_error("sysfs file %s not in expected format: %s", path,
431*86d7f5d3SJohn Marino buffer);
432*86d7f5d3SJohn Marino goto out;
433*86d7f5d3SJohn Marino }
434*86d7f5d3SJohn Marino
435*86d7f5d3SJohn Marino log_very_verbose("Device %s %s is %lu bytes.",
436*86d7f5d3SJohn Marino dev_name(dev), attribute, result);
437*86d7f5d3SJohn Marino
438*86d7f5d3SJohn Marino out:
439*86d7f5d3SJohn Marino if (fclose(fp))
440*86d7f5d3SJohn Marino log_sys_error("fclose", path);
441*86d7f5d3SJohn Marino
442*86d7f5d3SJohn Marino return result >> SECTOR_SHIFT;
443*86d7f5d3SJohn Marino }
444*86d7f5d3SJohn Marino
dev_alignment_offset(const char * sysfs_dir,struct device * dev)445*86d7f5d3SJohn Marino unsigned long dev_alignment_offset(const char *sysfs_dir,
446*86d7f5d3SJohn Marino struct device *dev)
447*86d7f5d3SJohn Marino {
448*86d7f5d3SJohn Marino return _dev_topology_attribute("alignment_offset",
449*86d7f5d3SJohn Marino sysfs_dir, dev);
450*86d7f5d3SJohn Marino }
451*86d7f5d3SJohn Marino
dev_minimum_io_size(const char * sysfs_dir,struct device * dev)452*86d7f5d3SJohn Marino unsigned long dev_minimum_io_size(const char *sysfs_dir,
453*86d7f5d3SJohn Marino struct device *dev)
454*86d7f5d3SJohn Marino {
455*86d7f5d3SJohn Marino return _dev_topology_attribute("queue/minimum_io_size",
456*86d7f5d3SJohn Marino sysfs_dir, dev);
457*86d7f5d3SJohn Marino }
458*86d7f5d3SJohn Marino
dev_optimal_io_size(const char * sysfs_dir,struct device * dev)459*86d7f5d3SJohn Marino unsigned long dev_optimal_io_size(const char *sysfs_dir,
460*86d7f5d3SJohn Marino struct device *dev)
461*86d7f5d3SJohn Marino {
462*86d7f5d3SJohn Marino return _dev_topology_attribute("queue/optimal_io_size",
463*86d7f5d3SJohn Marino sysfs_dir, dev);
464*86d7f5d3SJohn Marino }
465*86d7f5d3SJohn Marino
466*86d7f5d3SJohn Marino #else
467*86d7f5d3SJohn Marino
get_primary_dev(const char * sysfs_dir,struct device * dev,dev_t * result)468*86d7f5d3SJohn Marino int get_primary_dev(const char *sysfs_dir,
469*86d7f5d3SJohn Marino struct device *dev, dev_t *result)
470*86d7f5d3SJohn Marino {
471*86d7f5d3SJohn Marino return 0;
472*86d7f5d3SJohn Marino }
473*86d7f5d3SJohn Marino
dev_alignment_offset(const char * sysfs_dir,struct device * dev)474*86d7f5d3SJohn Marino unsigned long dev_alignment_offset(const char *sysfs_dir,
475*86d7f5d3SJohn Marino struct device *dev)
476*86d7f5d3SJohn Marino {
477*86d7f5d3SJohn Marino return 0UL;
478*86d7f5d3SJohn Marino }
479*86d7f5d3SJohn Marino
dev_minimum_io_size(const char * sysfs_dir,struct device * dev)480*86d7f5d3SJohn Marino unsigned long dev_minimum_io_size(const char *sysfs_dir,
481*86d7f5d3SJohn Marino struct device *dev)
482*86d7f5d3SJohn Marino {
483*86d7f5d3SJohn Marino return 0UL;
484*86d7f5d3SJohn Marino }
485*86d7f5d3SJohn Marino
dev_optimal_io_size(const char * sysfs_dir,struct device * dev)486*86d7f5d3SJohn Marino unsigned long dev_optimal_io_size(const char *sysfs_dir,
487*86d7f5d3SJohn Marino struct device *dev)
488*86d7f5d3SJohn Marino {
489*86d7f5d3SJohn Marino return 0UL;
490*86d7f5d3SJohn Marino }
491*86d7f5d3SJohn Marino
492*86d7f5d3SJohn Marino #endif
493