Blame view

kernel/linux-imx6_3.14.28/Documentation/filesystems/xfs-self-describing-metadata.txt 16.5 KB
6b13f685e   김민수   BSP 최초 추가
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
  XFS Self Describing Metadata
  ----------------------------
  
  Introduction
  ------------
  
  The largest scalability problem facing XFS is not one of algorithmic
  scalability, but of verification of the filesystem structure. Scalabilty of the
  structures and indexes on disk and the algorithms for iterating them are
  adequate for supporting PB scale filesystems with billions of inodes, however it
  is this very scalability that causes the verification problem.
  
  Almost all metadata on XFS is dynamically allocated. The only fixed location
  metadata is the allocation group headers (SB, AGF, AGFL and AGI), while all
  other metadata structures need to be discovered by walking the filesystem
  structure in different ways. While this is already done by userspace tools for
  validating and repairing the structure, there are limits to what they can
  verify, and this in turn limits the supportable size of an XFS filesystem.
  
  For example, it is entirely possible to manually use xfs_db and a bit of
  scripting to analyse the structure of a 100TB filesystem when trying to
  determine the root cause of a corruption problem, but it is still mainly a
  manual task of verifying that things like single bit errors or misplaced writes
  weren't the ultimate cause of a corruption event. It may take a few hours to a
  few days to perform such forensic analysis, so for at this scale root cause
  analysis is entirely possible.
  
  However, if we scale the filesystem up to 1PB, we now have 10x as much metadata
  to analyse and so that analysis blows out towards weeks/months of forensic work.
  Most of the analysis work is slow and tedious, so as the amount of analysis goes
  up, the more likely that the cause will be lost in the noise.  Hence the primary
  concern for supporting PB scale filesystems is minimising the time and effort
  required for basic forensic analysis of the filesystem structure.
  
  
  Self Describing Metadata
  ------------------------
  
  One of the problems with the current metadata format is that apart from the
  magic number in the metadata block, we have no other way of identifying what it
  is supposed to be. We can't even identify if it is the right place. Put simply,
  you can't look at a single metadata block in isolation and say "yes, it is
  supposed to be there and the contents are valid".
  
  Hence most of the time spent on forensic analysis is spent doing basic
  verification of metadata values, looking for values that are in range (and hence
  not detected by automated verification checks) but are not correct. Finding and
  understanding how things like cross linked block lists (e.g. sibling
  pointers in a btree end up with loops in them) are the key to understanding what
  went wrong, but it is impossible to tell what order the blocks were linked into
  each other or written to disk after the fact.
  
  Hence we need to record more information into the metadata to allow us to
  quickly determine if the metadata is intact and can be ignored for the purpose
  of analysis. We can't protect against every possible type of error, but we can
  ensure that common types of errors are easily detectable.  Hence the concept of
  self describing metadata.
  
  The first, fundamental requirement of self describing metadata is that the
  metadata object contains some form of unique identifier in a well known
  location. This allows us to identify the expected contents of the block and
  hence parse and verify the metadata object. IF we can't independently identify
  the type of metadata in the object, then the metadata doesn't describe itself
  very well at all!
  
  Luckily, almost all XFS metadata has magic numbers embedded already - only the
  AGFL, remote symlinks and remote attribute blocks do not contain identifying
  magic numbers. Hence we can change the on-disk format of all these objects to
  add more identifying information and detect this simply by changing the magic
  numbers in the metadata objects. That is, if it has the current magic number,
  the metadata isn't self identifying. If it contains a new magic number, it is
  self identifying and we can do much more expansive automated verification of the
  metadata object at runtime, during forensic analysis or repair.
  
  As a primary concern, self describing metadata needs some form of overall
  integrity checking. We cannot trust the metadata if we cannot verify that it has
  not been changed as a result of external influences. Hence we need some form of
  integrity check, and this is done by adding CRC32c validation to the metadata
  block. If we can verify the block contains the metadata it was intended to
  contain, a large amount of the manual verification work can be skipped.
  
  CRC32c was selected as metadata cannot be more than 64k in length in XFS and
  hence a 32 bit CRC is more than sufficient to detect multi-bit errors in
  metadata blocks. CRC32c is also now hardware accelerated on common CPUs so it is
  fast. So while CRC32c is not the strongest of possible integrity checks that
  could be used, it is more than sufficient for our needs and has relatively
  little overhead. Adding support for larger integrity fields and/or algorithms
  does really provide any extra value over CRC32c, but it does add a lot of
  complexity and so there is no provision for changing the integrity checking
  mechanism.
  
  Self describing metadata needs to contain enough information so that the
  metadata block can be verified as being in the correct place without needing to
  look at any other metadata. This means it needs to contain location information.
  Just adding a block number to the metadata is not sufficient to protect against
  mis-directed writes - a write might be misdirected to the wrong LUN and so be
  written to the "correct block" of the wrong filesystem. Hence location
  information must contain a filesystem identifier as well as a block number.
  
  Another key information point in forensic analysis is knowing who the metadata
  block belongs to. We already know the type, the location, that it is valid
  and/or corrupted, and how long ago that it was last modified. Knowing the owner
  of the block is important as it allows us to find other related metadata to
  determine the scope of the corruption. For example, if we have a extent btree
  object, we don't know what inode it belongs to and hence have to walk the entire
  filesystem to find the owner of the block. Worse, the corruption could mean that
  no owner can be found (i.e. it's an orphan block), and so without an owner field
  in the metadata we have no idea of the scope of the corruption. If we have an
  owner field in the metadata object, we can immediately do top down validation to
  determine the scope of the problem.
  
  Different types of metadata have different owner identifiers. For example,
  directory, attribute and extent tree blocks are all owned by an inode, whilst
  freespace btree blocks are owned by an allocation group. Hence the size and
  contents of the owner field are determined by the type of metadata object we are
  looking at.  The owner information can also identify misplaced writes (e.g.
  freespace btree block written to the wrong AG).
  
  Self describing metadata also needs to contain some indication of when it was
  written to the filesystem. One of the key information points when doing forensic
  analysis is how recently the block was modified. Correlation of set of corrupted
  metadata blocks based on modification times is important as it can indicate
  whether the corruptions are related, whether there's been multiple corruption
  events that lead to the eventual failure, and even whether there are corruptions
  present that the run-time verification is not detecting.
  
  For example, we can determine whether a metadata object is supposed to be free
  space or still allocated if it is still referenced by its owner by looking at
  when the free space btree block that contains the block was last written
  compared to when the metadata object itself was last written.  If the free space
  block is more recent than the object and the object's owner, then there is a
  very good chance that the block should have been removed from the owner.
  
  To provide this "written timestamp", each metadata block gets the Log Sequence
  Number (LSN) of the most recent transaction it was modified on written into it.
  This number will always increase over the life of the filesystem, and the only
  thing that resets it is running xfs_repair on the filesystem. Further, by use of
  the LSN we can tell if the corrupted metadata all belonged to the same log
  checkpoint and hence have some idea of how much modification occurred between
  the first and last instance of corrupt metadata on disk and, further, how much
  modification occurred between the corruption being written and when it was
  detected.
  
  Runtime Validation
  ------------------
  
  Validation of self-describing metadata takes place at runtime in two places:
  
  	- immediately after a successful read from disk
  	- immediately prior to write IO submission
  
  The verification is completely stateless - it is done independently of the
  modification process, and seeks only to check that the metadata is what it says
  it is and that the metadata fields are within bounds and internally consistent.
  As such, we cannot catch all types of corruption that can occur within a block
  as there may be certain limitations that operational state enforces of the
  metadata, or there may be corruption of interblock relationships (e.g. corrupted
  sibling pointer lists). Hence we still need stateful checking in the main code
  body, but in general most of the per-field validation is handled by the
  verifiers.
  
  For read verification, the caller needs to specify the expected type of metadata
  that it should see, and the IO completion process verifies that the metadata
  object matches what was expected. If the verification process fails, then it
  marks the object being read as EFSCORRUPTED. The caller needs to catch this
  error (same as for IO errors), and if it needs to take special action due to a
  verification error it can do so by catching the EFSCORRUPTED error value. If we
  need more discrimination of error type at higher levels, we can define new
  error numbers for different errors as necessary.
  
  The first step in read verification is checking the magic number and determining
  whether CRC validating is necessary. If it is, the CRC32c is calculated and
  compared against the value stored in the object itself. Once this is validated,
  further checks are made against the location information, followed by extensive
  object specific metadata validation. If any of these checks fail, then the
  buffer is considered corrupt and the EFSCORRUPTED error is set appropriately.
  
  Write verification is the opposite of the read verification - first the object
  is extensively verified and if it is OK we then update the LSN from the last
  modification made to the object, After this, we calculate the CRC and insert it
  into the object. Once this is done the write IO is allowed to continue. If any
  error occurs during this process, the buffer is again marked with a EFSCORRUPTED
  error for the higher layers to catch.
  
  Structures
  ----------
  
  A typical on-disk structure needs to contain the following information:
  
  struct xfs_ondisk_hdr {
          __be32  magic;		/* magic number */
          __be32  crc;		/* CRC, not logged */
          uuid_t  uuid;		/* filesystem identifier */
          __be64  owner;		/* parent object */
          __be64  blkno;		/* location on disk */
          __be64  lsn;		/* last modification in log, not logged */
  };
  
  Depending on the metadata, this information may be part of a header structure
  separate to the metadata contents, or may be distributed through an existing
  structure. The latter occurs with metadata that already contains some of this
  information, such as the superblock and AG headers.
  
  Other metadata may have different formats for the information, but the same
  level of information is generally provided. For example:
  
  	- short btree blocks have a 32 bit owner (ag number) and a 32 bit block
  	  number for location. The two of these combined provide the same
  	  information as @owner and @blkno in eh above structure, but using 8
  	  bytes less space on disk.
  
  	- directory/attribute node blocks have a 16 bit magic number, and the
  	  header that contains the magic number has other information in it as
  	  well. hence the additional metadata headers change the overall format
  	  of the metadata.
  
  A typical buffer read verifier is structured as follows:
  
  #define XFS_FOO_CRC_OFF		offsetof(struct xfs_ondisk_hdr, crc)
  
  static void
  xfs_foo_read_verify(
  	struct xfs_buf	*bp)
  {
         struct xfs_mount *mp = bp->b_target->bt_mount;
  
          if ((xfs_sb_version_hascrc(&mp->m_sb) &&
               !xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length),
  					XFS_FOO_CRC_OFF)) ||
              !xfs_foo_verify(bp)) {
                  XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
                  xfs_buf_ioerror(bp, EFSCORRUPTED);
          }
  }
  
  The code ensures that the CRC is only checked if the filesystem has CRCs enabled
  by checking the superblock of the feature bit, and then if the CRC verifies OK
  (or is not needed) it verifies the actual contents of the block.
  
  The verifier function will take a couple of different forms, depending on
  whether the magic number can be used to determine the format of the block. In
  the case it can't, the code is structured as follows:
  
  static bool
  xfs_foo_verify(
  	struct xfs_buf		*bp)
  {
          struct xfs_mount	*mp = bp->b_target->bt_mount;
          struct xfs_ondisk_hdr	*hdr = bp->b_addr;
  
          if (hdr->magic != cpu_to_be32(XFS_FOO_MAGIC))
                  return false;
  
          if (!xfs_sb_version_hascrc(&mp->m_sb)) {
  		if (!uuid_equal(&hdr->uuid, &mp->m_sb.sb_uuid))
  			return false;
  		if (bp->b_bn != be64_to_cpu(hdr->blkno))
  			return false;
  		if (hdr->owner == 0)
  			return false;
  	}
  
  	/* object specific verification checks here */
  
          return true;
  }
  
  If there are different magic numbers for the different formats, the verifier
  will look like:
  
  static bool
  xfs_foo_verify(
  	struct xfs_buf		*bp)
  {
          struct xfs_mount	*mp = bp->b_target->bt_mount;
          struct xfs_ondisk_hdr	*hdr = bp->b_addr;
  
          if (hdr->magic == cpu_to_be32(XFS_FOO_CRC_MAGIC)) {
  		if (!uuid_equal(&hdr->uuid, &mp->m_sb.sb_uuid))
  			return false;
  		if (bp->b_bn != be64_to_cpu(hdr->blkno))
  			return false;
  		if (hdr->owner == 0)
  			return false;
  	} else if (hdr->magic != cpu_to_be32(XFS_FOO_MAGIC))
  		return false;
  
  	/* object specific verification checks here */
  
          return true;
  }
  
  Write verifiers are very similar to the read verifiers, they just do things in
  the opposite order to the read verifiers. A typical write verifier:
  
  static void
  xfs_foo_write_verify(
  	struct xfs_buf	*bp)
  {
  	struct xfs_mount	*mp = bp->b_target->bt_mount;
  	struct xfs_buf_log_item	*bip = bp->b_fspriv;
  
  	if (!xfs_foo_verify(bp)) {
  		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
  		xfs_buf_ioerror(bp, EFSCORRUPTED);
  		return;
  	}
  
  	if (!xfs_sb_version_hascrc(&mp->m_sb))
  		return;
  
  
  	if (bip) {
  		struct xfs_ondisk_hdr	*hdr = bp->b_addr;
  		hdr->lsn = cpu_to_be64(bip->bli_item.li_lsn);
  	}
  	xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), XFS_FOO_CRC_OFF);
  }
  
  This will verify the internal structure of the metadata before we go any
  further, detecting corruptions that have occurred as the metadata has been
  modified in memory. If the metadata verifies OK, and CRCs are enabled, we then
  update the LSN field (when it was last modified) and calculate the CRC on the
  metadata. Once this is done, we can issue the IO.
  
  Inodes and Dquots
  -----------------
  
  Inodes and dquots are special snowflakes. They have per-object CRC and
  self-identifiers, but they are packed so that there are multiple objects per
  buffer. Hence we do not use per-buffer verifiers to do the work of per-object
  verification and CRC calculations. The per-buffer verifiers simply perform basic
  identification of the buffer - that they contain inodes or dquots, and that
  there are magic numbers in all the expected spots. All further CRC and
  verification checks are done when each inode is read from or written back to the
  buffer.
  
  The structure of the verifiers and the identifiers checks is very similar to the
  buffer code described above. The only difference is where they are called. For
  example, inode read verification is done in xfs_iread() when the inode is first
  read out of the buffer and the struct xfs_inode is instantiated. The inode is
  already extensively verified during writeback in xfs_iflush_int, so the only
  addition here is to add the LSN and CRC to the inode as it is copied back into
  the buffer.
  
  XXX: inode unlinked list modification doesn't recalculate the inode CRC! None of
  the unlinked list modifications check or update CRCs, neither during unlink nor
  log recovery. So, it's gone unnoticed until now. This won't matter immediately -
  repair will probably complain about it - but it needs to be fixed.