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