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