Coverage Report

Created: 2024-05-21 06:33

/src/util-linux/libblkid/src/superblocks/xfs.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 1999 by Andries Brouwer
3
 * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
4
 * Copyright (C) 2001 by Andreas Dilger
5
 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
6
 * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
7
 * Copyright (C) 2013 Eric Sandeen <sandeen@redhat.com>
8
 *
9
 * This file may be redistributed under the terms of the
10
 * GNU Lesser General Public License.
11
 */
12
13
#include <stdio.h>
14
#include <stdlib.h>
15
#include <unistd.h>
16
#include <string.h>
17
#include <errno.h>
18
#include <ctype.h>
19
#include <stdint.h>
20
21
#include "superblocks.h"
22
#include "crc32c.h"
23
24
struct xfs_super_block {
25
  uint32_t  sb_magicnum;  /* magic number == XFS_SB_MAGIC */
26
  uint32_t  sb_blocksize; /* logical block size, bytes */
27
  uint64_t  sb_dblocks; /* number of data blocks */
28
  uint64_t  sb_rblocks; /* number of realtime blocks */
29
  uint64_t  sb_rextents;  /* number of realtime extents */
30
  unsigned char sb_uuid[16];  /* file system unique id */
31
  uint64_t  sb_logstart;  /* starting block of log if internal */
32
  uint64_t  sb_rootino; /* root inode number */
33
  uint64_t  sb_rbmino;  /* bitmap inode for realtime extents */
34
  uint64_t  sb_rsumino; /* summary inode for rt bitmap */
35
  uint32_t  sb_rextsize;  /* realtime extent size, blocks */
36
  uint32_t  sb_agblocks;  /* size of an allocation group */
37
  uint32_t  sb_agcount; /* number of allocation groups */
38
  uint32_t  sb_rbmblocks; /* number of rt bitmap blocks */
39
  uint32_t  sb_logblocks; /* number of log blocks */
40
41
  uint16_t  sb_versionnum;  /* header version == XFS_SB_VERSION */
42
  uint16_t  sb_sectsize;  /* volume sector size, bytes */
43
  uint16_t  sb_inodesize; /* inode size, bytes */
44
  uint16_t  sb_inopblock; /* inodes per block */
45
  char    sb_fname[12]; /* file system name */
46
  uint8_t   sb_blocklog;  /* log2 of sb_blocksize */
47
  uint8_t   sb_sectlog; /* log2 of sb_sectsize */
48
  uint8_t   sb_inodelog;  /* log2 of sb_inodesize */
49
  uint8_t   sb_inopblog;  /* log2 of sb_inopblock */
50
  uint8_t   sb_agblklog;  /* log2 of sb_agblocks (rounded up) */
51
  uint8_t   sb_rextslog;  /* log2 of sb_rextents */
52
  uint8_t   sb_inprogress;  /* mkfs is in progress, don't mount */
53
  uint8_t   sb_imax_pct;  /* max % of fs for inode space */
54
          /* statistics */
55
  uint64_t  sb_icount;  /* allocated inodes */
56
  uint64_t  sb_ifree; /* free inodes */
57
  uint64_t  sb_fdblocks;  /* free data blocks */
58
  uint64_t  sb_frextents; /* free realtime extents */
59
  uint64_t  sb_uquotino;  /* inode for user quotas */
60
  uint64_t  sb_gquotino;  /* inode for group or project quotas */
61
  uint16_t  sb_qflags;  /* quota flags */
62
  uint8_t   sb_flags; /* misc flags */
63
  uint8_t   sb_shared_vn; /* reserved, zeroed */
64
  uint32_t  sb_inoalignmt;  /* inode alignment */
65
  uint32_t  sb_unit;  /* stripe or raid unit */
66
  uint32_t  sb_width; /* stripe or raid width */
67
  uint8_t   sb_dirblklog; /* directory block allocation granularity */
68
  uint8_t   sb_logsectlog;  /* log sector sector size */
69
  uint16_t  sb_logsectsize; /* log sector size */
70
  uint32_t  sb_logsunit;  /* log device stripe or raid unit */
71
  uint32_t  sb_features2; /* additional version flags */
72
  uint32_t  sb_bad_features2; /* mirror of sb_features2 */
73
74
  /* version 5 fields */
75
  uint32_t  sb_features_compat;   /* rw compatible flags */
76
  uint32_t  sb_features_ro_compat;    /* ro compatible flags */
77
  uint32_t  sb_features_incompat;   /* rw incompatible flags */
78
  uint32_t  sb_features_log_incompat; /* rw log incompatible flags */
79
  uint32_t  sb_crc;       /* superblock checksum */
80
  uint32_t  sb_spino_align;     /* sparse inode alignment */
81
  uint64_t  sb_pquotino;      /* project quote inode */
82
  uint64_t  sb_lsn;     /* superblock update sequence number */
83
  unsigned char sb_meta_uuid[16];   /* superblock meta uuid */
84
  uint64_t  sb_rrmapino;    /* realtime reversemapping inode */
85
} __attribute__((packed));
86
87
1.42k
#define XFS_MIN_BLOCKSIZE_LOG 9  /* i.e. 512 bytes */
88
1.41k
#define XFS_MAX_BLOCKSIZE_LOG 16  /* i.e. 65536 bytes */
89
1.01k
#define XFS_MIN_BLOCKSIZE (1 << XFS_MIN_BLOCKSIZE_LOG)
90
1.01k
#define XFS_MAX_BLOCKSIZE (1 << XFS_MAX_BLOCKSIZE_LOG)
91
1.61k
#define XFS_MIN_SECTORSIZE_LOG  9  /* i.e. 512 bytes */
92
1.57k
#define XFS_MAX_SECTORSIZE_LOG  15  /* i.e. 32768 bytes */
93
1.10k
#define XFS_MIN_SECTORSIZE  (1 << XFS_MIN_SECTORSIZE_LOG)
94
1.08k
#define XFS_MAX_SECTORSIZE  (1 << XFS_MAX_SECTORSIZE_LOG)
95
96
1.29k
#define XFS_DINODE_MIN_LOG  8
97
1.28k
#define XFS_DINODE_MAX_LOG  11
98
925
#define XFS_DINODE_MIN_SIZE (1 << XFS_DINODE_MIN_LOG)
99
922
#define XFS_DINODE_MAX_SIZE (1 << XFS_DINODE_MAX_LOG)
100
101
345
#define XFS_MAX_RTEXTSIZE (1024 * 1024 * 1024)  /* 1GB */
102
#define XFS_DFL_RTEXTSIZE (64 * 1024)         /* 64kB */
103
341
#define XFS_MIN_RTEXTSIZE (4 * 1024)    /* 4kB */
104
105
207
#define XFS_MIN_AG_BLOCKS 64
106
885
#define XFS_MAX_DBLOCKS(s) ((uint64_t)(s)->sb_agcount * (s)->sb_agblocks)
107
207
#define XFS_MIN_DBLOCKS(s) ((uint64_t)((s)->sb_agcount - 1) *  \
108
207
       (s)->sb_agblocks + XFS_MIN_AG_BLOCKS)
109
110
9
#define XFS_SB_VERSION_MOREBITSBIT  0x8000
111
6
#define XFS_SB_VERSION2_CRCBIT    0x00000100
112
113
114
static void sb_from_disk(const struct xfs_super_block *from,
115
       struct xfs_super_block *to)
116
553
{
117
118
553
  to->sb_magicnum = be32_to_cpu(from->sb_magicnum);
119
553
  to->sb_blocksize = be32_to_cpu(from->sb_blocksize);
120
553
  to->sb_dblocks = be64_to_cpu(from->sb_dblocks);
121
553
  to->sb_rblocks = be64_to_cpu(from->sb_rblocks);
122
553
  to->sb_rextents = be64_to_cpu(from->sb_rextents);
123
553
  to->sb_logstart = be64_to_cpu(from->sb_logstart);
124
553
  to->sb_rootino = be64_to_cpu(from->sb_rootino);
125
553
  to->sb_rbmino = be64_to_cpu(from->sb_rbmino);
126
553
  to->sb_rsumino = be64_to_cpu(from->sb_rsumino);
127
553
  to->sb_rextsize = be32_to_cpu(from->sb_rextsize);
128
553
  to->sb_agblocks = be32_to_cpu(from->sb_agblocks);
129
553
  to->sb_agcount = be32_to_cpu(from->sb_agcount);
130
553
  to->sb_rbmblocks = be32_to_cpu(from->sb_rbmblocks);
131
553
  to->sb_logblocks = be32_to_cpu(from->sb_logblocks);
132
553
  to->sb_versionnum = be16_to_cpu(from->sb_versionnum);
133
553
  to->sb_sectsize = be16_to_cpu(from->sb_sectsize);
134
553
  to->sb_inodesize = be16_to_cpu(from->sb_inodesize);
135
553
  to->sb_inopblock = be16_to_cpu(from->sb_inopblock);
136
553
  to->sb_blocklog = from->sb_blocklog;
137
553
  to->sb_sectlog = from->sb_sectlog;
138
553
  to->sb_inodelog = from->sb_inodelog;
139
553
  to->sb_inopblog = from->sb_inopblog;
140
553
  to->sb_agblklog = from->sb_agblklog;
141
553
  to->sb_rextslog = from->sb_rextslog;
142
553
  to->sb_inprogress = from->sb_inprogress;
143
553
  to->sb_imax_pct = from->sb_imax_pct;
144
553
  to->sb_icount = be64_to_cpu(from->sb_icount);
145
553
  to->sb_ifree = be64_to_cpu(from->sb_ifree);
146
553
  to->sb_fdblocks = be64_to_cpu(from->sb_fdblocks);
147
553
  to->sb_frextents = be64_to_cpu(from->sb_frextents);
148
553
  to->sb_uquotino = be64_to_cpu(from->sb_uquotino);
149
553
  to->sb_gquotino = be64_to_cpu(from->sb_gquotino);
150
553
  to->sb_qflags = be16_to_cpu(from->sb_qflags);
151
553
  to->sb_flags = from-> sb_flags;
152
553
  to->sb_shared_vn = from-> sb_shared_vn;
153
553
  to->sb_inoalignmt = be32_to_cpu(from->sb_inoalignmt);
154
553
  to->sb_unit = be32_to_cpu(from->sb_unit);
155
553
  to->sb_width = be32_to_cpu(from->sb_width);
156
553
  to->sb_dirblklog = from-> sb_dirblklog;
157
553
  to->sb_logsectlog = from-> sb_logsectlog;
158
553
  to->sb_logsectsize = be16_to_cpu(from->sb_logsectsize);
159
553
  to->sb_logsunit = be32_to_cpu(from->sb_logsunit);
160
553
  to->sb_features2 = be32_to_cpu(from->sb_features2);
161
553
  to->sb_bad_features2 = be32_to_cpu(from->sb_bad_features2);
162
553
  to->sb_features_compat = be32_to_cpu(from->sb_features_compat);
163
553
  to->sb_features_ro_compat = be32_to_cpu(from->sb_features_ro_compat);
164
553
  to->sb_features_incompat = be32_to_cpu(from->sb_features_incompat);
165
553
  to->sb_features_log_incompat = be32_to_cpu(from->sb_features_log_incompat);
166
553
  to->sb_crc = be32_to_cpu(from->sb_crc);
167
553
  to->sb_spino_align = be32_to_cpu(from->sb_spino_align);
168
553
  to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
169
553
  to->sb_lsn = be64_to_cpu(from->sb_lsn);
170
553
  to->sb_rrmapino = be64_to_cpu(from->sb_rrmapino);
171
553
}
172
173
static int xfs_verify_sb(const struct xfs_super_block *ondisk, blkid_probe pr,
174
    const struct blkid_idmag *mag)
175
553
{
176
553
  struct xfs_super_block sb, *sbp = &sb;
177
178
  /* beXX_to_cpu(), but don't convert UUID and fsname! */
179
553
  sb_from_disk(ondisk, sbp);
180
181
  /* sanity checks, we don't want to rely on magic string only */
182
553
  if (sbp->sb_agcount <= 0          ||
183
553
      sbp->sb_sectsize < XFS_MIN_SECTORSIZE      ||
184
553
      sbp->sb_sectsize > XFS_MAX_SECTORSIZE      ||
185
553
      sbp->sb_sectlog < XFS_MIN_SECTORSIZE_LOG      ||
186
553
      sbp->sb_sectlog > XFS_MAX_SECTORSIZE_LOG      ||
187
553
      sbp->sb_sectsize != (1 << sbp->sb_sectlog)      ||
188
553
      sbp->sb_blocksize < XFS_MIN_BLOCKSIZE      ||
189
553
      sbp->sb_blocksize > XFS_MAX_BLOCKSIZE      ||
190
553
      sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG      ||
191
553
      sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG      ||
192
553
      sbp->sb_blocksize != (1ULL << sbp->sb_blocklog)    ||
193
553
      sbp->sb_inodesize < XFS_DINODE_MIN_SIZE      ||
194
553
      sbp->sb_inodesize > XFS_DINODE_MAX_SIZE      ||
195
553
      sbp->sb_inodelog < XFS_DINODE_MIN_LOG      ||
196
553
      sbp->sb_inodelog > XFS_DINODE_MAX_LOG      ||
197
553
      sbp->sb_inodesize != (1 << sbp->sb_inodelog)    ||
198
553
      (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog)  ||
199
553
      (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE)  ||
200
553
      (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE)  ||
201
553
      (sbp->sb_imax_pct > 100 /* zero sb_imax_pct is valid */)  ||
202
553
      sbp->sb_dblocks == 0          ||
203
553
      sbp->sb_dblocks > XFS_MAX_DBLOCKS(sbp)     ||
204
553
      sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp))
205
493
    return 0;
206
207
60
  if ((sbp->sb_versionnum & 0x0f) == 5) {
208
9
    uint32_t expected, crc;
209
9
    const unsigned char *csummed;
210
211
9
    if (!(sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT))
212
3
      return 0;
213
6
    if (!(sbp->sb_features2 & XFS_SB_VERSION2_CRCBIT))
214
3
      return 0;
215
216
3
    expected = sbp->sb_crc;
217
3
    csummed = blkid_probe_get_sb_buffer(pr, mag, sbp->sb_sectsize);
218
3
    if (!csummed)
219
0
      return 0;
220
221
3
    crc = ul_crc32c_exclude_offset(~0LL, csummed, sbp->sb_sectsize,
222
3
                             offsetof(struct xfs_super_block, sb_crc),
223
3
                             sizeof_member(struct xfs_super_block, sb_crc));
224
3
    crc = bswap_32(crc ^ ~0LL);
225
226
3
    if (!blkid_probe_verify_csum(pr, crc, expected))
227
3
      return 0;
228
3
  }
229
230
51
  return 1;
231
60
}
232
233
static uint64_t xfs_fssize(const struct xfs_super_block *xs)
234
51
{
235
51
  uint32_t lsize = xs->sb_logstart ? xs->sb_logblocks : 0;
236
51
  uint64_t avail_blocks = be64_to_cpu(xs->sb_dblocks) - be32_to_cpu(lsize);
237
51
  uint64_t fssize = avail_blocks*be32_to_cpu(xs->sb_blocksize);
238
239
51
  return fssize;
240
51
}
241
242
static int probe_xfs(blkid_probe pr, const struct blkid_idmag *mag)
243
553
{
244
553
  const struct xfs_super_block *xs;
245
246
553
  xs = blkid_probe_get_sb(pr, mag, struct xfs_super_block);
247
553
  if (!xs)
248
0
    return errno ? -errno : 1;
249
250
553
  if (!xfs_verify_sb(xs, pr, mag))
251
502
    return 1;
252
253
51
  if (*xs->sb_fname != '\0')
254
36
    blkid_probe_set_label(pr, (unsigned char *) xs->sb_fname,
255
36
        sizeof(xs->sb_fname));
256
51
  blkid_probe_set_uuid(pr, xs->sb_uuid);
257
51
  blkid_probe_set_fssize(pr, xfs_fssize(xs));
258
51
  blkid_probe_set_fslastblock(pr, be64_to_cpu(xs->sb_dblocks));
259
51
  blkid_probe_set_fsblocksize(pr, be32_to_cpu(xs->sb_blocksize));
260
51
  blkid_probe_set_block_size(pr, be16_to_cpu(xs->sb_sectsize));
261
51
  return 0;
262
553
}
263
264
const struct blkid_idinfo xfs_idinfo =
265
{
266
  .name   = "xfs",
267
  .usage    = BLKID_USAGE_FILESYSTEM,
268
  .probefunc  = probe_xfs,
269
  .magics   =
270
  {
271
    { .magic = "XFSB", .len = 4 },
272
    { NULL }
273
  }
274
};
275
276
struct xlog_rec_header {
277
  uint32_t  h_magicno;
278
  uint32_t  h_dummy1[1];
279
  uint32_t  h_version;
280
  uint32_t  h_len;
281
  uint32_t  h_dummy2[71];
282
  uint32_t  h_fmt;
283
  unsigned char h_uuid[16];
284
} __attribute__((packed));
285
286
#define XLOG_HEADER_MAGIC_NUM 0xFEEDbabe
287
288
/*
289
 * For very small filesystems, the minimum log size
290
 * can be smaller, but that seems vanishingly unlikely
291
 * when used with an external log (which is used for
292
 * performance reasons; tiny conflicts with that goal).
293
 */
294
#define XFS_MIN_LOG_BYTES (10 * 1024 * 1024)
295
296
#define XLOG_FMT_LINUX_LE 1
297
#define XLOG_FMT_LINUX_BE 2
298
#define XLOG_FMT_IRIX_BE  3
299
300
330
#define XLOG_VERSION_1    1
301
330
#define XLOG_VERSION_2    2  /* Large IClogs, Log sunit */
302
330
#define XLOG_VERSION_OKBITS (XLOG_VERSION_1 | XLOG_VERSION_2)
303
304
static int xlog_valid_rec_header(struct xlog_rec_header *rhead)
305
2.52M
{
306
2.52M
  uint32_t hlen;
307
308
2.52M
  if (rhead->h_magicno != cpu_to_be32(XLOG_HEADER_MAGIC_NUM))
309
2.52M
    return 0;
310
311
386
  if (!rhead->h_version ||
312
386
            (be32_to_cpu(rhead->h_version) & (~XLOG_VERSION_OKBITS)))
313
200
    return 0;
314
315
  /* LR body must have data or it wouldn't have been written */
316
186
  hlen = be32_to_cpu(rhead->h_len);
317
186
  if (hlen <= 0 || hlen > INT_MAX)
318
59
    return 0;
319
320
127
  if (rhead->h_fmt != cpu_to_be32(XLOG_FMT_LINUX_LE) &&
321
127
      rhead->h_fmt != cpu_to_be32(XLOG_FMT_LINUX_BE) &&
322
127
      rhead->h_fmt != cpu_to_be32(XLOG_FMT_IRIX_BE))
323
123
    return 0;
324
325
4
  return 1;
326
127
}
327
328
/* xlog record header will be in some sector in the first 256k */
329
static int probe_xfs_log(blkid_probe pr,
330
    const struct blkid_idmag *mag __attribute__((__unused__)))
331
5.99k
{
332
5.99k
  int i;
333
5.99k
  struct xlog_rec_header *rhead;
334
5.99k
  const unsigned char *buf;
335
336
5.99k
  buf = blkid_probe_get_buffer(pr, 0, 256*1024);
337
5.99k
  if (!buf)
338
0
    return errno ? -errno : 1;
339
340
  /* check the first 512 512-byte sectors */
341
2.53M
  for (i = 0; i < 512; i++) {
342
    /* this is regular XFS (maybe with some sectors shift), ignore */
343
2.52M
    if (memcmp(&buf[i*512], "XFSB", 4) == 0)
344
1.10k
      return 1;
345
346
2.52M
    rhead = (struct xlog_rec_header *)&buf[i*512];
347
348
2.52M
    if (xlog_valid_rec_header(rhead)) {
349
4
      blkid_probe_set_uuid_as(pr, rhead->h_uuid, "LOGUUID");
350
351
4
      if (blkid_probe_set_magic(pr, i * 512,
352
4
            sizeof(rhead->h_magicno),
353
4
            (unsigned char *) &rhead->h_magicno))
354
0
        return 1;
355
356
4
      return 0;
357
4
    }
358
2.52M
  }
359
360
4.88k
  return 1;
361
5.99k
}
362
363
const struct blkid_idinfo xfs_log_idinfo =
364
{
365
  .name   = "xfs_external_log",
366
  .usage    = BLKID_USAGE_OTHER,
367
  .probefunc  = probe_xfs_log,
368
  .magics   = BLKID_NONE_MAGIC,
369
  .minsz    = XFS_MIN_LOG_BYTES,
370
};