• Home
  • History
  • Annotate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/ap/gpl/hdparm-9.43/

Lines Matching defs:*

2  * Device geometry helpers for hdparm and friends.
3 * Copyright (c) Mark Lord 2008
5 * You may use/distribute this freely, under the terms of either
6 * (your choice) the GNU General Public License version 2,
7 * or a BSD style license.
9 #define _FILE_OFFSET_BITS 64
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <string.h>
13 #include <stdio.h>
14 #include <fcntl.h>
15 #include <errno.h>
16 #include <dirent.h>
17 #include <sys/stat.h>
18 #include <sys/ioctl.h>
19 #include <linux/types.h>
20 #include <linux/fs.h>
22 #include "hdparm.h"
24 static int get_driver_major (const char *driver, unsigned int *major)
26 static const char proc_devices[] = "/proc/devices";
27 char buf[256];
28 int err = 0;
29 FILE *fp = fopen(proc_devices, "r");
31 if (fp == NULL) {
32 err = EIO;
33 } else {
34 while (fgets(buf, sizeof(buf) - 1, fp)) {
35 int len = strlen(buf);
36 if (len > 5 && buf[len - 1] == '\n') {
37 buf[len - 1] = '\0';
38 if (buf[3] == ' ' && 0 == strcmp(buf + 4, driver)) {
39 *major = atoi(buf);
40 break;
45 if (err)
46 perror(proc_devices);
47 if (fp)
48 fclose(fp);
49 return err;
52 static unsigned int md_major (void)
54 static unsigned int maj = 0;
56 if (!maj) {
57 unsigned int val;
58 if (0 == get_driver_major("md", &val))
59 maj = val;
61 return maj;
64 int fd_is_raid (int fd)
66 struct stat st;
68 if (!md_major())
69 return 0; /* not a RAID device */
70 if (fstat(fd, &st)) {
71 perror("fstat()");
72 return 0; /* ugh.. shouldn't happen */
74 return (major(st.st_rdev) == md_major());
77 static int get_sector_count (int fd, __u64 *nsectors)
79 int err;
80 unsigned int nsects32 = 0;
81 __u64 nbytes64 = 0;
83 if (0 == sysfs_get_attr(fd, "size", "%llu", nsectors, NULL, 0))
84 return 0;
85 #ifdef BLKGETSIZE64
86 if (0 == ioctl(fd, BLKGETSIZE64, &nbytes64)) { // returns bytes
87 *nsectors = nbytes64 / 512;
88 return 0;
90 #endif
91 err = ioctl(fd, BLKGETSIZE, &nsects32); // returns sectors
92 if (err == 0) {
93 *nsectors = nsects32;
94 } else {
95 err = errno;
96 perror(" BLKGETSIZE failed");
98 return err;
102 * "md" (RAID) devices have per-member "start" offsets.
103 * Realistically, we can only support raid1 arrays here,
104 * and only then when all members have the same "start" offsets.
106 static int get_raid1_start_lba (int fd, __u64 *start_lba)
108 char buf[32];
109 unsigned int member, raid_disks;
110 __u64 start = 0, offset = 0;
112 if (sysfs_get_attr(fd, "md/level", "%s", buf, NULL, 0)
113 || sysfs_get_attr(fd, "md/raid_disks", "%u", &raid_disks, NULL, 0))
114 return ENODEV;
115 if (strcmp(buf, "raid1") || !raid_disks)
116 return EINVAL;
117 for (member = 0; member < raid_disks; ++member) {
118 __u64 member_start, member_offset;
119 char member_path[32];
120 sprintf(member_path, "md/rd%u/offset", member);
121 if (sysfs_get_attr(fd, member_path, "%llu", &member_offset, NULL, 0))
122 member_offset = 0;
123 sprintf(member_path, "md/rd%u/block/dev", member);
124 if (sysfs_get_attr(fd, member_path, "%s", buf, NULL, 0))
125 return EINVAL;
126 if (md_major() == (unsigned)atoi(buf)) /* disallow recursive RAIDs */
127 return EINVAL;
128 sprintf(member_path, "md/rd%u/block/start", member);
129 if (sysfs_get_attr(fd, member_path, "%llu", &member_start, NULL, 0))
130 return ENODEV;
131 if (member == 0) {
132 start = member_start;
133 offset = member_offset;
134 } else if (member_start != start || member_offset != offset)
135 return EINVAL;
136 /* FIXME? Should --fibmap should account for member_offset in calculations? */
138 *start_lba = start;
139 return 0;
142 int get_dev_geometry (int fd, __u32 *cyls, __u32 *heads, __u32 *sects,
143 __u64 *start_lba, __u64 *nsectors)
145 static struct local_hd_geometry g;
146 static struct local_hd_big_geometry bg;
147 int err = 0, try_getgeo_big_first = 1;
149 if (nsectors) {
150 err = get_sector_count(fd, nsectors);
151 if (err)
152 return err;
155 if (start_lba) {
157 * HDIO_GETGEO uses 32-bit fields on 32-bit architectures,
158 * so it cannot be relied upon for start_lba with very large drives >= 2TB.
160 __u64 result;
161 if (0 == sysfs_get_attr(fd, "start", "%llu", &result, NULL, 0)
162 || 0 == get_raid1_start_lba(fd, &result))
164 *start_lba = result;
165 start_lba = NULL;
166 try_getgeo_big_first = 0; /* if kernel has sysfs, it probably lacks GETGEO_BIG */
167 } else if (fd_is_raid(fd)) {
168 *start_lba = START_LBA_UNKNOWN; /* RAID: no such thing as a "start_lba" */
169 start_lba = NULL;
170 try_getgeo_big_first = 0; /* no point even trying it on RAID */
174 if (cyls || heads || sects || start_lba) {
175 /* Skip HDIO_GETGEO_BIG (doesn't exist) on kernels with sysfs (>= 2.6.xx) */
176 if (try_getgeo_big_first && !ioctl(fd, HDIO_GETGEO_BIG, &bg)) {
177 if (cyls) *cyls = bg.cylinders;
178 if (heads) *heads = bg.heads;
179 if (sects) *sects = bg.sectors;
180 if (start_lba) *start_lba = bg.start;
181 } else if (!ioctl(fd, HDIO_GETGEO, &g)) {
182 if (cyls) *cyls = g.cylinders;
183 if (heads) *heads = g.heads;
184 if (sects) *sects = g.sectors;
185 if (start_lba) *start_lba = g.start;
186 } else if (!try_getgeo_big_first && !ioctl(fd, HDIO_GETGEO_BIG, &bg)) {
187 if (cyls) *cyls = bg.cylinders;
188 if (heads) *heads = bg.heads;
189 if (sects) *sects = bg.sectors;
190 if (start_lba) *start_lba = bg.start;
191 } else {
192 err = errno;
193 perror(" HDIO_GETGEO failed");
194 return err;
197 * On all (32 and 64 bit) systems, the cyls value is bit-limited.
198 * So try and correct it using other info we have at hand.
200 if (nsectors && cyls && heads && sects) {
201 __u64 hs = (*heads) * (*sects);
202 __u64 cyl = (*cyls);
203 __u64 chs = cyl * hs;
204 if (chs < (*nsectors))
205 *cyls = (*nsectors) / hs;
209 return 0;
212 static int find_dev_in_directory (dev_t dev, const char *dir, char *path, int verbose)
214 DIR *dp;
215 struct dirent *entry;
216 unsigned int maj = major(dev), min = minor(dev);
218 *path = '\0';
219 if (!(dp = opendir(dir))) {
220 int err = errno;
221 if (verbose)
222 perror(dir);
223 return err;
225 while ((entry = readdir(dp)) != NULL) {
226 if (entry->d_type == DT_UNKNOWN || entry->d_type == DT_BLK) {
227 struct stat st;
228 sprintf(path, "%s/%s", dir, entry->d_name);
229 if (stat(path, &st)) {
230 if (verbose)
231 perror(path);
232 } else if (S_ISBLK(st.st_mode)) {
233 if (maj == (unsigned)major(st.st_rdev) && min == (unsigned)minor(st.st_rdev)) {
234 closedir(dp);
235 return 0;
240 closedir(dp);
241 *path = '\0';
242 if (verbose)
243 fprintf(stderr, "%d,%d: device not found in %s\n", major(dev), minor(dev), dir);
244 return ENOENT;
247 int get_dev_t_geometry (dev_t dev, __u32 *cyls, __u32 *heads, __u32 *sects,
248 __u64 *start_lba, __u64 *nsectors)
250 char path[PATH_MAX];
251 int fd, err;
253 err = find_dev_in_directory (dev, "/dev", path, 1);
254 if (err)
255 return err;
257 fd = open(path, O_RDONLY|O_NONBLOCK);
258 if (fd == -1) {
259 err = errno;
260 perror(path);
261 return err;
264 err = get_dev_geometry(fd, cyls, heads, sects, start_lba, nsectors);
265 close(fd);
266 return err;