]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - libfrog/topology.c
libfrog: move topology code out of libxcmd
[thirdparty/xfsprogs-dev.git] / libfrog / topology.c
1 /*
2 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include "libxfs.h"
20 #include "libxcmd.h"
21 #ifdef ENABLE_BLKID
22 # include <blkid/blkid.h>
23 #endif /* ENABLE_BLKID */
24 #include "xfs_multidisk.h"
25
26 #define TERABYTES(count, blog) ((uint64_t)(count) << (40 - (blog)))
27 #define GIGABYTES(count, blog) ((uint64_t)(count) << (30 - (blog)))
28 #define MEGABYTES(count, blog) ((uint64_t)(count) << (20 - (blog)))
29
30 void
31 calc_default_ag_geometry(
32 int blocklog,
33 uint64_t dblocks,
34 int multidisk,
35 uint64_t *agsize,
36 uint64_t *agcount)
37 {
38 uint64_t blocks = 0;
39 int shift = 0;
40
41 /*
42 * First handle the high extreme - the point at which we will
43 * always use the maximum AG size.
44 *
45 * This applies regardless of storage configuration.
46 */
47 if (dblocks >= TERABYTES(32, blocklog)) {
48 blocks = XFS_AG_MAX_BLOCKS(blocklog);
49 goto done;
50 }
51
52 /*
53 * For a single underlying storage device over 4TB in size
54 * use the maximum AG size. Between 128MB and 4TB, just use
55 * 4 AGs and scale up smoothly between min/max AG sizes.
56 */
57 if (!multidisk) {
58 if (dblocks >= TERABYTES(4, blocklog)) {
59 blocks = XFS_AG_MAX_BLOCKS(blocklog);
60 goto done;
61 } else if (dblocks >= MEGABYTES(128, blocklog)) {
62 shift = XFS_NOMULTIDISK_AGLOG;
63 goto calc_blocks;
64 }
65 }
66
67 /*
68 * For the multidisk configs we choose an AG count based on the number
69 * of data blocks available, trying to keep the number of AGs higher
70 * than the single disk configurations. This makes the assumption that
71 * larger filesystems have more parallelism available to them.
72 */
73 shift = XFS_MULTIDISK_AGLOG;
74 if (dblocks <= GIGABYTES(512, blocklog))
75 shift--;
76 if (dblocks <= GIGABYTES(8, blocklog))
77 shift--;
78 if (dblocks < MEGABYTES(128, blocklog))
79 shift--;
80 if (dblocks < MEGABYTES(64, blocklog))
81 shift--;
82 if (dblocks < MEGABYTES(32, blocklog))
83 shift--;
84
85 /*
86 * If dblocks is not evenly divisible by the number of
87 * desired AGs, round "blocks" up so we don't lose the
88 * last bit of the filesystem. The same principle applies
89 * to the AG count, so we don't lose the last AG!
90 */
91 calc_blocks:
92 ASSERT(shift >= 0 && shift <= XFS_MULTIDISK_AGLOG);
93 blocks = dblocks >> shift;
94 if (dblocks & xfs_mask32lo(shift)) {
95 if (blocks < XFS_AG_MAX_BLOCKS(blocklog))
96 blocks++;
97 }
98 done:
99 *agsize = blocks;
100 *agcount = dblocks / blocks + (dblocks % blocks != 0);
101 }
102
103 /*
104 * Check for existing filesystem or partition table on device.
105 * Returns:
106 * 1 for existing fs or partition
107 * 0 for nothing found
108 * -1 for internal error
109 */
110 #ifdef ENABLE_BLKID
111 int
112 check_overwrite(
113 const char *device)
114 {
115 const char *type;
116 blkid_probe pr = NULL;
117 int ret;
118 int fd;
119 long long size;
120 int bsz;
121
122 if (!device || !*device)
123 return 0;
124
125 ret = -1; /* will reset on success of all setup calls */
126
127 fd = open(device, O_RDONLY);
128 if (fd < 0)
129 goto out;
130 platform_findsizes((char *)device, fd, &size, &bsz);
131 close(fd);
132
133 /* nothing to overwrite on a 0-length device */
134 if (size == 0) {
135 ret = 0;
136 goto out;
137 }
138
139 pr = blkid_new_probe_from_filename(device);
140 if (!pr)
141 goto out;
142
143 ret = blkid_probe_enable_partitions(pr, 1);
144 if (ret < 0)
145 goto out;
146
147 ret = blkid_do_fullprobe(pr);
148 if (ret < 0)
149 goto out;
150
151 /*
152 * Blkid returns 1 for nothing found and 0 when it finds a signature,
153 * but we want the exact opposite, so reverse the return value here.
154 *
155 * In addition print some useful diagnostics about what actually is
156 * on the device.
157 */
158 if (ret) {
159 ret = 0;
160 goto out;
161 }
162
163 if (!blkid_probe_lookup_value(pr, "TYPE", &type, NULL)) {
164 fprintf(stderr,
165 _("%s: %s appears to contain an existing "
166 "filesystem (%s).\n"), progname, device, type);
167 } else if (!blkid_probe_lookup_value(pr, "PTTYPE", &type, NULL)) {
168 fprintf(stderr,
169 _("%s: %s appears to contain a partition "
170 "table (%s).\n"), progname, device, type);
171 } else {
172 fprintf(stderr,
173 _("%s: %s appears to contain something weird "
174 "according to blkid\n"), progname, device);
175 }
176 ret = 1;
177 out:
178 if (pr)
179 blkid_free_probe(pr);
180 if (ret == -1)
181 fprintf(stderr,
182 _("%s: probe of %s failed, cannot detect "
183 "existing filesystem.\n"), progname, device);
184 return ret;
185 }
186
187 static void blkid_get_topology(
188 const char *device,
189 int *sunit,
190 int *swidth,
191 int *lsectorsize,
192 int *psectorsize,
193 int force_overwrite)
194 {
195
196 blkid_topology tp;
197 blkid_probe pr;
198 unsigned long val;
199 struct stat statbuf;
200
201 /* can't get topology info from a file */
202 if (!stat(device, &statbuf) && S_ISREG(statbuf.st_mode)) {
203 fprintf(stderr,
204 _("%s: Warning: trying to probe topology of a file %s!\n"),
205 progname, device);
206 return;
207 }
208
209 pr = blkid_new_probe_from_filename(device);
210 if (!pr)
211 return;
212
213 tp = blkid_probe_get_topology(pr);
214 if (!tp)
215 goto out_free_probe;
216
217 val = blkid_topology_get_logical_sector_size(tp);
218 *lsectorsize = val;
219 val = blkid_topology_get_physical_sector_size(tp);
220 *psectorsize = val;
221 val = blkid_topology_get_minimum_io_size(tp);
222 *sunit = val;
223 val = blkid_topology_get_optimal_io_size(tp);
224 *swidth = val;
225
226 /*
227 * If the reported values are the same as the physical sector size
228 * do not bother to report anything. It will only cause warnings
229 * if people specify larger stripe units or widths manually.
230 */
231 if (*sunit == *psectorsize || *swidth == *psectorsize) {
232 *sunit = 0;
233 *swidth = 0;
234 }
235
236 /*
237 * Blkid reports the information in terms of bytes, but we want it in
238 * terms of 512 bytes blocks (only to convert it to bytes later..)
239 */
240 *sunit = *sunit >> 9;
241 *swidth = *swidth >> 9;
242
243 if (blkid_topology_get_alignment_offset(tp) != 0) {
244 fprintf(stderr,
245 _("warning: device is not properly aligned %s\n"),
246 device);
247
248 if (!force_overwrite) {
249 fprintf(stderr,
250 _("Use -f to force usage of a misaligned device\n"));
251
252 exit(EXIT_FAILURE);
253 }
254 /* Do not use physical sector size if the device is misaligned */
255 *psectorsize = *lsectorsize;
256 }
257
258 blkid_free_probe(pr);
259 return;
260
261 out_free_probe:
262 blkid_free_probe(pr);
263 fprintf(stderr,
264 _("warning: unable to probe device topology for device %s\n"),
265 device);
266 }
267 #else /* ifdef ENABLE_BLKID */
268 /*
269 * Without blkid, we can't do a good check for signatures.
270 * So instead of some messy attempts, just disable any checks
271 * and always return 'nothing found'.
272 */
273 # warning BLKID is disabled, so signature detection and block device\
274 access are not working!
275 int
276 check_overwrite(
277 const char *device)
278 {
279 return 1;
280 }
281
282 static void blkid_get_topology(
283 const char *device,
284 int *sunit,
285 int *swidth,
286 int *lsectorsize,
287 int *psectorsize,
288 int force_overwrite)
289 {
290 /*
291 * Shouldn't make any difference (no blkid = no block device access),
292 * but make sure this dummy replacement returns with at least some
293 * sanity.
294 */
295 *lsectorsize = *psectorsize = 512;
296 }
297
298 #endif /* ENABLE_BLKID */
299
300 void get_topology(
301 libxfs_init_t *xi,
302 struct fs_topology *ft,
303 int force_overwrite)
304 {
305 struct stat statbuf;
306 char *dfile = xi->volname ? xi->volname : xi->dname;
307
308 /*
309 * If our target is a regular file, use platform_findsizes
310 * to try to obtain the underlying filesystem's requirements
311 * for direct IO; we'll set our sector size to that if possible.
312 */
313 if (xi->disfile ||
314 (!stat(dfile, &statbuf) && S_ISREG(statbuf.st_mode))) {
315 int fd;
316 int flags = O_RDONLY;
317 long long dummy;
318
319 /* with xi->disfile we may not have the file yet! */
320 if (xi->disfile)
321 flags |= O_CREAT;
322
323 fd = open(dfile, flags, 0666);
324 if (fd >= 0) {
325 platform_findsizes(dfile, fd, &dummy, &ft->lsectorsize);
326 close(fd);
327 ft->psectorsize = ft->lsectorsize;
328 } else
329 ft->psectorsize = ft->lsectorsize = BBSIZE;
330 } else {
331 blkid_get_topology(dfile, &ft->dsunit, &ft->dswidth,
332 &ft->lsectorsize, &ft->psectorsize,
333 force_overwrite);
334 }
335
336 if (xi->rtname && !xi->risfile) {
337 int sunit, lsectorsize, psectorsize;
338
339 blkid_get_topology(xi->rtname, &sunit, &ft->rtswidth,
340 &lsectorsize, &psectorsize, force_overwrite);
341 }
342 }