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