aboutsummaryrefslogtreecommitdiffstats
path: root/design/XFS_Filesystem_Structure/journaling_log.asciidoc
blob: 8d5f50d26308c9c73314d2ebbd72b0614bf8589a (plain)
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
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
[[Journaling_Log]]
= Journaling Log

[NOTE]
Only v2 log format is covered here.

The XFS journal exists on disk as a reserved extent of blocks within the
filesystem, or as a separate journal device.  The journal itself can be thought
of as a series of log records; each log record contains a part of or a whole
transaction.  A transaction consists of a series of log operation headers
(``log items''), formatting structures, and raw data.  The first operation in a
transaction establishes the transaction ID and the last operation is a commit
record.  The operations recorded between the start and commit operations
represent the metadata changes made by the transaction.  If the commit
operation is missing, the transaction is incomplete and cannot be recovered.

[[Log_Records]]
== Log Records

The XFS log is split into a series of log records.  Log records seem to
correspond to an in-core log buffer, which can be up to 256KiB in size.  Each
record has a log sequence number, which is the same LSN recorded in the v5
metadata integrity fields.

Log sequence numbers are a 64-bit quantity consisting of two 32-bit quantities.
The upper 32 bits are the ``cycle number'', which increments every time XFS
cycles through the log.  The lower 32 bits are the ``block number'', which is
assigned when a transaction is committed, and should correspond to the block
offset within the log.

A log record begins with the following header, which occupies 512 bytes on
disk:

[source, c]
----
typedef struct xlog_rec_header {
     __be32                    h_magicno;
     __be32                    h_cycle;
     __be32                    h_version;
     __be32                    h_len;
     __be64                    h_lsn;
     __be64                    h_tail_lsn;
     __le32                    h_crc;
     __be32                    h_prev_block;
     __be32                    h_num_logops;
     __be32                    h_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE];
     /* new fields */
     __be32                    h_fmt;
     uuid_t                    h_fs_uuid;
     __be32                    h_size;
} xlog_rec_header_t;
----

*h_magicno*::
The magic number of log records, 0xfeedbabe.

*h_cycle*::
Cycle number of this log record.

*h_version*::
Log record version, currently 2.

*h_len*::
Length of the log record, in bytes.  Must be aligned to a 64-bit boundary.

*h_lsn*::
Log sequence number of this record.

*h_tail_lsn*::
Log sequence number of the first log record with uncommitted buffers.

*h_crc*::
Checksum of the log record header, the cycle data, and the log records
themselves.

*h_prev_block*::
Block number of the previous log record.

*h_num_logops*::
The number of log operations in this record.

*h_cycle_data*::
The first u32 of each log sector must contain the cycle number.  Since log
item buffers are formatted without regard to this requirement, the original
contents of the first four bytes of each sector in the log are copied into the
corresponding element of this array.  After that, the first four bytes of those
sectors are stamped with the cycle number.  This process is reversed at
recovery time.  If there are more sectors in this log record than there are
slots in this array, the cycle data continues for as many sectors are needed;
each sector is formatted as type +xlog_rec_ext_header+.

*h_fmt*::
Format of the log record.  This is one of the following values:

.Log record formats
[options="header"]
|=====
| Format value        | Log format
| +XLOG_FMT_UNKNOWN+  | Unknown.  Perhaps this log is corrupt.
| +XLOG_FMT_LINUX_LE+ | Little-endian Linux.
| +XLOG_FMT_LINUX_BE+ | Big-endian Linux.
| +XLOG_FMT_IRIX_BE+  | Big-endian Irix.
|=====

*h_fs_uuid*::
Filesystem UUID.

*h_size*::
In-core log record size.  This is somewhere between 16 and 256KiB, with 32KiB
being the default.

As mentioned earlier, if this log record is longer than 256 sectors, the cycle
data overflows into the next sector(s) in the log.  Each of those sectors is
formatted as follows:

[source, c]
----
typedef struct xlog_rec_ext_header {
    __be32                     xh_cycle;
    __be32                     xh_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE];
} xlog_rec_ext_header_t;
----

*xh_cycle*::
Cycle number of this log record.  Should match +h_cycle+.

*xh_cycle_data*::
Overflow cycle data.

[[Log_Operations]]
== Log Operations

Within a log record, log operations are recorded as a series consisting of an
operation header immediately followed by a data region.  The operation header
has the following format:

[source, c]
----
typedef struct xlog_op_header {
     __be32                    oh_tid;
     __be32                    oh_len;
     __u8                      oh_clientid;
     __u8                      oh_flags;
     __u16                     oh_res2;
} xlog_op_header_t;
----

*oh_tid*::
Transaction ID of this operation.

*oh_len*::
Number of bytes in the data region.

*oh_clientid*::
The originator of this operation.  This can be one of the following:

.Log Operation Client ID
[options="header"]
|=====
| Client ID         | Originator
| +XFS_TRANSACTION+ | Operation came from a transaction.
| +XFS_VOLUME+      | ???
| +XFS_LOG+         | ???
|=====

*oh_flags*::
Specifies flags associated with this operation.  This can be a combination of
the following values (though most likely only one will be set at a time):

.Log Operation Flags
[options="header"]
|=====
| Flag                  | Description
| +XLOG_START_TRANS+    | Start a new transaction.  The next operation header should describe a transaction header.
| +XLOG_COMMIT_TRANS+   | Commit this transaction.
| +XLOG_CONTINUE_TRANS+ | Continue this trans into new log record.
| +XLOG_WAS_CONT_TRANS+ | This transaction started in a previous log record.
| +XLOG_END_TRANS+      | End of a continued transaction.
| +XLOG_UNMOUNT_TRANS+  | Transaction to unmount a filesystem.
|=====

*oh_res2*::
Padding.

The data region follows immediately after the operation header and is exactly
+oh_len+ bytes long.  These payloads are in host-endian order, which means that
one cannot replay the log from an unclean XFS filesystem on a system with a
different byte order.

[[Log_Items]]
== Log Items

Following are the types of log item payloads that can follow an
+xlog_op_header+.  Except for buffer data and inode cores, all log items have a
magic number to distinguish themselves.  Buffer data items only appear after
+xfs_buf_log_format+ items; and inode core items only appear after
+xfs_inode_log_format+ items.

.Log Operation Magic Numbers
[options="header"]
|=====
| Magic				| Hexadecimal	| Operation Type
| +XFS_TRANS_HEADER_MAGIC+	| 0x5452414e	| xref:Log_Transaction_Headers[Log Transaction Header]
| +XFS_LI_EFI+			| 0x1236        | xref:EFI_Log_Item[Extent Freeing Intent]
| +XFS_LI_EFD+			| 0x1237        | xref:EFD_Log_Item[Extent Freeing Done]
| +XFS_LI_IUNLINK+		| 0x1238        |  Unknown?
| +XFS_LI_INODE+		| 0x123b        | xref:Inode_Log_Item[Inode Updates]
| +XFS_LI_BUF+			| 0x123c        | xref:Buffer_Log_Item[Buffer Writes]
| +XFS_LI_DQUOT+		| 0x123d        | xref:Quota_Update_Log_Item[Update Quota]
| +XFS_LI_QUOTAOFF+		| 0x123e        | xref:Quota_Off_Log_Item[Quota Off]
| +XFS_LI_ICREATE+		| 0x123f        | xref:Inode_Create_Log_Item[Inode Creation]
| +XFS_LI_RUI+			| 0x1240        | xref:RUI_Log_Item[Reverse Mapping Update Intent]
| +XFS_LI_RUD+			| 0x1241        | xref:RUD_Log_Item[Reverse Mapping Update Done]
| +XFS_LI_CUI+			| 0x1242        | xref:CUI_Log_Item[Reference Count Update Intent]
| +XFS_LI_CUD+			| 0x1243        | xref:CUD_Log_Item[Reference Count Update Done]
| +XFS_LI_BUI+			| 0x1244        | xref:BUI_Log_Item[File Block Mapping Update Intent]
| +XFS_LI_BUD+			| 0x1245        | xref:BUD_Log_Item[File Block Mapping Update Done]
| +XFS_LI_ATTRI+		| 0x1246        | xref:ATTRI_Log_Item[Extended Attribute Update Intent]
| +XFS_LI_ATTRD+		| 0x1247        | xref:ATTRD_Log_Item[Extended Attribute Update Done]
| +XFS_LI_XMI+			| 0x1248        | xref:XMI_Log_Item[File Mapping Exchange Intent]
| +XFS_LI_XMD+			| 0x1249        | xref:XMD_Log_Item[File Mapping Exchange Done]
|=====

Note that all log items (except for transaction headers) MUST start with
the following header structure.  The type and size fields are baked into
each log item header, but there is not a separately defined header.

[source, c]
----
struct xfs_log_item {
     __uint16_t                magic;
     __uint16_t                size;
};
----

[[Log_Transaction_Headers]]
=== Transaction Headers

A transaction header is an operation payload that starts a transaction.

[source, c]
----
typedef struct xfs_trans_header {
     uint                      th_magic;
     uint                      th_type;
     __int32_t                 th_tid;
     uint                      th_num_items;
} xfs_trans_header_t;
----

*th_magic*::
The signature of a transaction header, ``TRAN'' (0x5452414e).  Note that this
value is in host-endian order, not big-endian like the rest of XFS.

*th_type*::
Transaction type.  This is one of the following values:

[options="header"]
|=====
| Type                         | Description
| +XFS_TRANS_SETATTR_NOT_SIZE+ | Set an inode attribute that isn't the inode's size.
| +XFS_TRANS_SETATTR_SIZE+     | Setting the size attribute of an inode.
| +XFS_TRANS_INACTIVE+         | Freeing blocks from an unlinked inode.
| +XFS_TRANS_CREATE+           | Create a file.
| +XFS_TRANS_CREATE_TRUNC+     |  Unused?
| +XFS_TRANS_TRUNCATE_FILE+    | Truncate a quota file.
| +XFS_TRANS_REMOVE+           | Remove a file.
| +XFS_TRANS_LINK+             | Link an inode into a directory.
| +XFS_TRANS_RENAME+           | Rename a path.
| +XFS_TRANS_MKDIR+            | Create a directory.
| +XFS_TRANS_RMDIR+            | Remove a directory.
| +XFS_TRANS_SYMLINK+          | Create a symbolic link.
| +XFS_TRANS_SET_DMATTRS+      | Set the DMAPI attributes of an inode.
| +XFS_TRANS_GROWFS+           | Expand the filesystem.
| +XFS_TRANS_STRAT_WRITE+      | Convert an unwritten extent or delayed-allocate some blocks to handle a write.
| +XFS_TRANS_DIOSTRAT+         | Allocate some blocks to handle a direct I/O write.
| +XFS_TRANS_WRITEID+          | Update an inode's preallocation flag.
| +XFS_TRANS_ADDAFORK+         | Add an attribute fork to an inode.
| +XFS_TRANS_ATTRINVAL+        | Erase the attribute fork of an inode.
| +XFS_TRANS_ATRUNCATE+        |  Unused?
| +XFS_TRANS_ATTR_SET+         | Set an extended attribute.
| +XFS_TRANS_ATTR_RM+          | Remove an extended attribute.
| +XFS_TRANS_ATTR_FLAG+        |  Unused?
| +XFS_TRANS_CLEAR_AGI_BUCKET+ | Clear a bad inode pointer in the AGI unlinked inode hash bucket.
| +XFS_TRANS_SB_CHANGE+        | Write the superblock to disk.
| +XFS_TRANS_QM_QUOTAOFF+      | Start disabling quotas.
| +XFS_TRANS_QM_DQALLOC+       | Allocate a disk quota structure.
| +XFS_TRANS_QM_SETQLIM+       | Adjust quota limits.
| +XFS_TRANS_QM_DQCLUSTER+     |  Unused?
| +XFS_TRANS_QM_QINOCREATE+    | Create a (quota) inode with reference taken.
| +XFS_TRANS_QM_QUOTAOFF_END+  | Finish disabling quotas.
| +XFS_TRANS_FSYNC_TS+         | Update only inode timestamps.
| +XFS_TRANS_GROWFSRT_ALLOC+   | Grow the realtime bitmap and summary data for growfs.
| +XFS_TRANS_GROWFSRT_ZERO+    | Zero space in the realtime bitmap and summary data.
| +XFS_TRANS_GROWFSRT_FREE+    | Free space in the realtime bitmap and summary data.
| +XFS_TRANS_SWAPEXT+          | Swap data fork of two inodes.
| +XFS_TRANS_CHECKPOINT+       | Checkpoint the log.
| +XFS_TRANS_ICREATE+          |  Unknown?
| +XFS_TRANS_CREATE_TMPFILE+   | Create a temporary file.
|=====

*th_tid*::
Transaction ID.

*th_num_items*::
The number of operations appearing after this operation, not including the
commit operation.  In effect, this tracks the number of metadata change
operations in this transaction.

[[EFI_Log_Item]]
=== Intent to Free an Extent

The next two operation types work together to handle the freeing of filesystem
blocks.  Naturally, the ranges of blocks to be freed can be expressed in terms
of extents:

[source, c]
----
typedef struct xfs_extent_32 {
     __uint64_t                ext_start;
     __uint32_t                ext_len;
} __attribute__((packed)) xfs_extent_32_t;

typedef struct xfs_extent_64 {
     __uint64_t                ext_start;
     __uint32_t                ext_len;
     __uint32_t                ext_pad;
} xfs_extent_64_t;
----

*ext_start*::
Start block of this extent.

*ext_len*::
Length of this extent.

The ``extent freeing intent'' operation comes first; it tells the log that XFS
wants to free some extents.  This record is crucial for correct log recovery
because it prevents the log from replaying blocks that are subsequently freed.
If the log lacks a corresponding ``extent freeing done'' operation, the
recovery process will free the extents.

[source, c]
----
typedef struct xfs_efi_log_format {
     __uint16_t                efi_type;
     __uint16_t                efi_size;
     __uint32_t                efi_nextents;
     __uint64_t                efi_id;
     xfs_extent_t              efi_extents[1];
} xfs_efi_log_format_t;
----

*efi_type*::
The signature of an EFI operation, 0x1236.  For a realtime extent, this
value will be 0x124a.  This value is in host-endian order, not big-endian like
the rest of XFS.

*efi_size*::
Size of this log item.  Should be 1.

*efi_nextents*::
Number of extents to free.

*efi_id*::
A 64-bit number that binds the corresponding EFD log item to this EFI log item.

*efi_extents*::
Variable-length array of extents to be freed.  The array length is given by
+efi_nextents+.  The record type will be either +xfs_extent_64_t+ or
+xfs_extent_32_t+; this can be determined from the log item size (+oh_len+) and
the number of extents (+efi_nextents+).

[[EFD_Log_Item]]
=== Completion of Intent to Free an Extent

The ``extent freeing done'' operation complements the ``extent freeing intent''
operation.  This second operation indicates that the block freeing actually
happened, so that log recovery needn't try to free the blocks.  Typically, the
operations to update the free space B+trees follow immediately after the EFD.

[source, c]
----
typedef struct xfs_efd_log_format {
     __uint16_t                efd_type;
     __uint16_t                efd_size;
     __uint32_t                efd_nextents;
     __uint64_t                efd_efi_id;
     xfs_extent_t              efd_extents[1];
} xfs_efd_log_format_t;
----

*efd_type*::
The signature of an EFD operation, 0x1237.  For a realtime EFD, this value will
be 0x124b.  This value is in host-endian order, not big-endian like the rest of
XFS.

*efd_size*::
Size of this log item.  Should be 1.

*efd_nextents*::
Number of extents to free.

*efd_id*::
A 64-bit number that binds the corresponding EFI log item to this EFD log item.

*efd_extents*::
Variable-length array of extents to be freed.  The array length is given by
+efd_nextents+.  The record type will be either +xfs_extent_64_t+ or
+xfs_extent_32_t+; this can be determined from the log item size (+oh_len+) and
the number of extents (+efd_nextents+).

[[RUI_Log_Item]]
=== Reverse Mapping Updates Intent

The next two operation types work together to handle deferred reverse mapping
updates.  Naturally, the mappings to be updated can be expressed in terms of
mapping extents:

[source, c]
----
struct xfs_map_extent {
     __uint64_t                me_owner;
     __uint64_t                me_startblock;
     __uint64_t                me_startoff;
     __uint32_t                me_len;
     __uint32_t                me_flags;
};
----

*me_owner*::
Owner of this reverse mapping.  See the values in the section about
xref:Reverse_Mapping_Btree[reverse mapping] for more information.

*me_startblock*::
Filesystem block of this mapping.

*me_startoff*::
Logical block offset of this mapping.

*me_len*::
The length of this mapping.

*me_flags*::
The lower byte of this field is a type code indicating what sort of
reverse mapping operation we want.  The upper three bytes are flag bits.

.Reverse mapping update log intent types
[options="header"]
|=====
| Value				| Description
| +XFS_RMAP_EXTENT_MAP+		| Add a reverse mapping for file data.
| +XFS_RMAP_EXTENT_MAP_SHARED+	| Add a reverse mapping for file data for a file with shared blocks.
| +XFS_RMAP_EXTENT_UNMAP+	| Remove a reverse mapping for file data.
| +XFS_RMAP_EXTENT_UNMAP_SHARED+	| Remove a reverse mapping for file data for a file with shared blocks.
| +XFS_RMAP_EXTENT_CONVERT+	| Convert a reverse mapping for file data between unwritten and normal.
| +XFS_RMAP_EXTENT_CONVERT_SHARED+	| Convert a reverse mapping for file data between unwritten and normal for a file with shared blocks.
| +XFS_RMAP_EXTENT_ALLOC+	| Add a reverse mapping for non-file data.
| +XFS_RMAP_EXTENT_FREE+	| Remove a reverse mapping for non-file data.
|=====

.Reverse mapping update log intent flags
[options="header"]
|=====
| Value				| Description
| +XFS_RMAP_EXTENT_ATTR_FORK+	| Extent is for the attribute fork.
| +XFS_RMAP_EXTENT_BMBT_BLOCK+	| Extent is for a block mapping btree block.
| +XFS_RMAP_EXTENT_UNWRITTEN+	| Extent is unwritten.
|=====

The ``rmap update intent'' operation comes first; it tells the log that XFS
wants to update some reverse mappings.  This record is crucial for correct log
recovery because it enables us to spread a complex metadata update across
multiple transactions while ensuring that a crash midway through the complex
update will be replayed fully during log recovery.

[source, c]
----
struct xfs_rui_log_format {
     __uint16_t                rui_type;
     __uint16_t                rui_size;
     __uint32_t                rui_nextents;
     __uint64_t                rui_id;
     struct xfs_map_extent     rui_extents[1];
};
----

*rui_type*::
The signature of an RUI operation, 0x1240.  For a realtime RUI, this value will
be 0x124c.  This value is in host-endian order, not big-endian like the rest of
XFS.

*rui_size*::
Size of this log item.  Should be 1.

*rui_nextents*::
Number of reverse mappings.

*rui_id*::
A 64-bit number that binds the corresponding RUD log item to this RUI log item.

*rui_extents*::
Variable-length array of reverse mappings to update.

[[RUD_Log_Item]]
=== Completion of Reverse Mapping Updates

The ``reverse mapping update done'' operation complements the ``reverse mapping
update intent'' operation.  This second operation indicates that the update
actually happened, so that log recovery needn't replay the update.  The RUD and
the actual updates are typically found in a new transaction following the
transaction in which the RUI was logged.

[source, c]
----
struct xfs_rud_log_format {
      __uint16_t               rud_type;
      __uint16_t               rud_size;
      __uint32_t               __pad;
      __uint64_t               rud_rui_id;
};
----

*rud_type*::
The signature of an RUD operation, 0x1241.  For a realtime RUD, this value will
be 0x124d.  This value is in host-endian order, not big-endian like the rest of
XFS.

*rud_size*::
Size of this log item.  Should be 1.

*rud_rui_id*::
A 64-bit number that binds the corresponding RUI log item to this RUD log item.

[[CUI_Log_Item]]
=== Reference Count Updates Intent

The next two operation types work together to handle reference count updates.
Naturally, the ranges of extents having reference count updates can be
expressed in terms of physical extents:

[source, c]
----
struct xfs_phys_extent {
     __uint64_t                pe_startblock;
     __uint32_t                pe_len;
     __uint32_t                pe_flags;
};
----

*pe_startblock*::
Filesystem block of this extent.

*pe_len*::
The length of this extent.

*pe_flags*::
The lower byte of this field is a type code indicating what sort of
reverse mapping operation we want.  The upper three bytes are flag bits.

.Reference count update log intent types
[options="header"]
|=====
| Value				  | Description
| +XFS_REFCOUNT_EXTENT_INCREASE+  | Increase the reference count for this extent.
| +XFS_REFCOUNT_EXTENT_DECREASE+  | Decrease the reference count for this extent.
| +XFS_REFCOUNT_EXTENT_ALLOC_COW+ | Reserve an extent for staging copy on write.
| +XFS_REFCOUNT_EXTENT_FREE_COW+  | Unreserve an extent for staging copy on write.
|=====

The ``reference count update intent'' operation comes first; it tells the log
that XFS wants to update some reference counts.  This record is crucial for
correct log recovery because it enables us to spread a complex metadata update
across multiple transactions while ensuring that a crash midway through the
complex update will be replayed fully during log recovery.

[source, c]
----
struct xfs_cui_log_format {
     __uint16_t                cui_type;
     __uint16_t                cui_size;
     __uint32_t                cui_nextents;
     __uint64_t                cui_id;
     struct xfs_map_extent     cui_extents[1];
};
----

*cui_type*::
The signature of an CUI operation, 0x1242.  For a realtime CUI, this vlaue is
0x124e.  This value is in host-endian order, not big-endian like the rest of
XFS.

*cui_size*::
Size of this log item.  Should be 1.

*cui_nextents*::
Number of reference count updates.

*cui_id*::
A 64-bit number that binds the corresponding RUD log item to this RUI log item.

*cui_extents*::
Variable-length array of reference count update information.

[[CUD_Log_Item]]
=== Completion of Reference Count Updates

The ``reference count update done'' operation complements the ``reference count
update intent'' operation.  This second operation indicates that the update
actually happened, so that log recovery needn't replay the update.  The CUD and
the actual updates are typically found in a new transaction following the
transaction in which the CUI was logged.

[source, c]
----
struct xfs_cud_log_format {
      __uint16_t               cud_type;
      __uint16_t               cud_size;
      __uint32_t               __pad;
      __uint64_t               cud_cui_id;
};
----

*cud_type*::
The signature of an RUD operation, 0x1243.  For a realtime CUD, this value is
0x124f.  This value is in host-endian order, not big-endian like the rest of
XFS.

*cud_size*::
Size of this log item.  Should be 1.

*cud_cui_id*::
A 64-bit number that binds the corresponding CUI log item to this CUD log item.

[[BUI_Log_Item]]
=== File Block Mapping Intent

The next two operation types work together to handle deferred file block
mapping updates.  The extents to be mapped are expressed via the
+xfs_map_extent+ structure discussed in the section about
xref:RUI_Log_Item[reverse mapping intents].

The lower byte of the +me_flags+ field is a type code indicating what sort of
file block mapping operation we want.  The upper three bytes are flag bits.

.File block mapping update log intent types
[options="header"]
|=====
| Value				| Description
| +XFS_BMAP_EXTENT_MAP+		| Add a mapping for file data.
| +XFS_BMAP_EXTENT_UNMAP+	| Remove a mapping for file data.
|=====

.File block mapping update log intent flags
[options="header"]
|=====
| Value				| Description
| +XFS_BMAP_EXTENT_ATTR_FORK+	| Extent is for the attribute fork.
| +XFS_BMAP_EXTENT_UNWRITTEN+	| Extent is unwritten.
| +XFS_BMAP_EXTENT_REALTIME+	| Mapping applies to the data fork of a
realtime file.  This flag cannot be combined with +XFS_BMAP_EXTENT_ATTR_FORK+.
|=====

The ``file block mapping update intent'' operation comes first; it tells the
log that XFS wants to map or unmap some extents in a file.  This record is
crucial for correct log recovery because it enables us to spread a complex
metadata update across multiple transactions while ensuring that a crash midway
through the complex update will be replayed fully during log recovery.

[source, c]
----
struct xfs_bui_log_format {
     __uint16_t                bui_type;
     __uint16_t                bui_size;
     __uint32_t                bui_nextents;
     __uint64_t                bui_id;
     struct xfs_map_extent     bui_extents[1];
};
----

*bui_type*::
The signature of an BUI operation, 0x1244.  This value is in host-endian order,
not big-endian like the rest of XFS.

*bui_size*::
Size of this log item.  Should be 1.

*bui_nextents*::
Number of file mappings.  Should be 1.

*bui_id*::
A 64-bit number that binds the corresponding BUD log item to this BUI log item.

*bui_extents*::
Variable-length array of file block mappings to update.  There should only
be one mapping present.

[[BUD_Log_Item]]
=== Completion of File Block Mapping Updates

The ``file block mapping update done'' operation complements the ``file block
mapping update intent'' operation.  This second operation indicates that the
update actually happened, so that log recovery needn't replay the update.  The
BUD and the actual updates are typically found in a new transaction following
the transaction in which the BUI was logged.

[source, c]
----
struct xfs_bud_log_format {
      __uint16_t               bud_type;
      __uint16_t               bud_size;
      __uint32_t               __pad;
      __uint64_t               bud_bui_id;
};
----

*bud_type*::
The signature of an BUD operation, 0x1245.  This value is in host-endian order,
not big-endian like the rest of XFS.

*bud_size*::
Size of this log item.  Should be 1.

*bud_bui_id*::
A 64-bit number that binds the corresponding BUI log item to this BUD log item.

[[ATTRI_Log_Item]]
=== Extended Attribute Update Intent

The next two operation types work together to handle atomic extended attribute
updates.

The lower byte of the +alfi_op_flags+ field is a type code indicating what sort
of file block mapping operation we want.

.Extended attribute update log intent types
[options="header"]
|=====
| Value					| Description
| +XFS_ATTRI_OP_FLAGS_SET+		| Associate an attribute name with the
given value, creating an entry for the name if necessary.
| +XFS_ATTRI_OP_FLAGS_REMOVE+		| Remove an attribute name and any
value associated with it.
| +XFS_ATTRI_OP_FLAGS_REPLACE+		| Remove any value associated with an
attribute name, then associate the name with the given value.
| +XFS_ATTRI_OP_FLAGS_PPTR_SET+		| Add a parent pointer associating a directory entry name with a file handle to the parent directory.  The (name, handle) tuple must not exist in the attribute structure.
| +XFS_ATTRI_OP_FLAGS_PPTR_REMOVE+	| Remove a parent pointer from the attribute structure.  The (name, handle) tuple must already exist.
| +XFS_ATTRI_OP_FLAGS_PPTR_REPLACE+	| Remove a specific (name, handle) tuple from
the attribute structure, then add a new (name, handle) tuple to the attribute structure.
The two names and handles need not be the same.
|=====

The ``extended attribute update intent'' operation comes first; it tells the
log that XFS wants to update one of a file's extended attributes.  This record
is crucial for correct log recovery because it enables us to spread a complex
metadata update across multiple transactions while ensuring that a crash midway
through the complex update will be replayed fully during log recovery.

[source, c]
----
struct xfs_attri_log_format {
     uint16_t                  alfi_type;
     uint16_t                  alfi_size;
     uint32_t                  alfi_igen;
     uint64_t                  alfi_id;
     uint64_t                  alfi_ino;
     uint32_t                  alfi_op_flags;
     union {
          uint32_t             alfi_name_len;
          struct {
              uint16_t         alfi_old_name_len;
              uint16_t         alfi_new_name_len;
          };
     };
     uint32_t                  alfi_value_len;
     uint32_t                  alfi_attr_filter;
};
----

*alfi_type*::
The signature of an ATTRI operation, 0x1246.  This value is in host-endian
order, not big-endian like the rest of XFS.

*alfi_size*::
Size of this log item.  Should be 1.

*alfi_igen*::
Generation number of the file being updated.

*alfi_id*::
A 64-bit number that binds the corresponding ATTRD log item to this ATTRI log
item.

*alfi_ino*::
Inode number of the file being updated.

*alfi_op_flags*::
The operation being performed.  The lower byte must be one of the
+XFS_ATTRI_OP_FLAGS_*+ flags defined above.  The upper bytes must be zero.

*alfi_name_len*::
Length of the name of the extended attribute.  This must not be zero.
The attribute name itself is captured in the next log item.
This field is not defined for the PPTR_REPLACE opcode.

*alfi_old_name_len*::
For PPTR_REPLACE, this is the length of the old name.

*alfi_new_name_len*::
For PPTR_REPLACE, this is the length of the new name.

*alfi_value_len*::
Length of the value of the extended attribute.  This must be zero for remove
operations, and nonzero for set and replace operations.  The attribute value
itself is captured in the log item immediately after the item containing the
name.

*alfi_attr_filter*::
Attribute namespace filter flags.  This must be one of +ATTR_ROOT+,
+ATTR_SECURE+, or +ATTR_INCOMPLETE+.

For a SET or REPLACE opcode, there should be two regions after the ATTRI intent
item.  The first region contains the attribute name and the second contains the
attribute value.

For a REMOVE opcode, there should only be one region after the ATTRI intent
item, and it will contain the attribute name.

For an PPTR_SET or PPTR_REMOVE opcode, there should be two regions after the
ATTRI intent item.  The first region contains the dirent name as the attribute
name.  The second region contains a file handle to the parent directory as the
attribute value.

For an PPTR_REPLACE opcode, there should be between four regions after the
ATTRI intent item.  The first region contains the dirent name to remove.
The second region contains the dirent name to create.  The third region
contains the parent directory file handle to remove.  The fourth region
contains the parent directory file handle to add.

[[ATTRD_Log_Item]]
=== Completion of Extended Attribute Updates

The ``extended attribute update done'' operation complements the ``extended
attribute update intent'' operation.  This second operation indicates that the
update actually happened, so that log recovery needn't replay the update.  The
ATTRD and the actual updates are typically found in a new transaction following
the transaction in which the ATTRI was logged.

[source, c]
----
struct xfs_attrd_log_format {
      __uint16_t               alfd_type;
      __uint16_t               alfd_size;
      __uint32_t               __pad;
      __uint64_t               alfd_alf_id;
};
----

*alfd_type*::
The signature of an ATTRD operation, 0x1247.  This value is in host-endian
order, not big-endian like the rest of XFS.

*alfd_size*::
Size of this log item.  Should be 1.

*alfd_alf_id*::
A 64-bit number that binds the corresponding ATTRI log item to this ATTRD log
item.

=== Extended Attribute Name and Value

These regions contain the name and value components of the extended attribute
being updated, as needed.  There are no magic numbers; each region contains the
data and nothing else.

[[XMI_Log_Item]]
=== File Mapping Exchange Intent

These two log items work together to track the exchange of mapped extents
between the forks of two files.  Each operation requires a separate XMI/XMD
pair.  The log intent item has the following format:

[source, c]
----
struct xfs_xmi_log_format {
     uint16_t                  xmi_type;
     uint16_t                  xmi_size;
     uint32_t                  __pad;
     uint64_t                  xmi_id;
     uint64_t                  xmi_inode1;
     uint64_t                  xmi_inode2;
     uint32_t                  xmi_igen1;
     uint32_t                  xmi_igen2;
     uint64_t                  xmi_startoff1;
     uint64_t                  xmi_startoff2;
     uint64_t                  xmi_blockcount;
     uint64_t                  xmi_flags;
     int64_t                   xmi_isize1;
     int64_t                   xmi_isize2;
};
----

*xmi_type*::
The signature of an XMI operation, 0x1248.  This value is in host-endian order,
not big-endian like the rest of XFS.

*xmi_size*::
Size of this log item.  Should be 1.

*__pad*::
Must be zero.

*xmi_id*::
A 64-bit number that binds the corresponding XMD log item to this XMI log item.

*xmi_inode1*::
Inode number of the first file involved in the operation.

*xmi_inode2*::
Inode number of the second file involved in the operation.

*xmi_igen1*::
Generation number of the first file involved in the operation.

*xmi_igen2*::
Generation number of the second file involved in the operation.

*xmi_startoff1*::
Starting point within the first file, in units of filesystem blocks.

*xmi_startoff2*::
Starting point within the second file, in units of filesystem blocks.

*xmi_blockcount*::
The length to be exchanged, in units of filesystem blocks.

*xmi_flags*::
Behavioral changes to the operation, as follows:

.File Extent Swap Intent Item Flags
[options="header"]
|=====
| Value				    | Description
| +XFS_EXCHMAPS_ATTR_FORK+	    | Exchange extents between attribute forks.
| +XFS_EXCHMAPS_SET_SIZES+	    | Exchange the file sizes of the two files
after the operation completes.
| +XFS_EXCHMAPS_INO1_WRITTEN+	    | Exchange the mappings of two files only
if the file allocation units mapped to file1's range have been written.
| +XFS_EXCHMAPS_CLEAR_INO1_REFLINK+ | Clear the reflink flag from inode1 after
the operation.
| +XFS_EXCHMAPS_CLEAR_INO2_REFLINK+ | Clear the reflink flag from inode2 after
the operation.
|=====

*xmi_isize1*::
The original size of the first file, in bytes.  This is zero if the
+XFS_EXCHMAPS_SET_SIZES+ flag is not set.

*xmi_isize2*::
The original size of the second file, in bytes.  This is zero if the
+XFS_EXCHMAPS_SET_SIZES+ flag is not set.

[[XMD_Log_Item]]
=== Completion of File Mapping Exchange

The ``file mapping exchange done'' operation complements the ``file mapping
exchange intent'' operation.  This second operation indicates that the update
actually happened, so that log recovery needn't replay the update.  The XMD
item and the actual updates are typically found in a new transaction following
the transaction in which the XMI was logged.  The completion has this format:

[source, c]
----
struct xfs_xmd_log_format {
     uint16_t                  xmd_type;
     uint16_t                  xmd_size;
     uint32_t                  __pad;
     uint64_t                  xmd_xmi_id;
};
----

*xmd_type*::
The signature of an XMD operation, 0x1249.  This value is in host-endian order,
not big-endian like the rest of XFS.

*xmd_size*::
Size of this log item.  Should be 1.

*__pad*::
Must be zero.

*xmd_xmi_id*::
A 64-bit number that binds the corresponding XMI log item to this XMD log item.

[[Inode_Log_Item]]
=== Inode Updates

This operation records changes to an inode record.  There are several types of
inode updates, each corresponding to different parts of the inode record.
Allowing updates to proceed at a sub-inode granularity reduces contention for
the inode, since different parts of the inode can be updated simultaneously.

The actual buffer data are stored in subsequent log items.

The inode log format header is as follows:

[source, c]
----
typedef struct xfs_inode_log_format_64 {
     __uint16_t                ilf_type;
     __uint16_t                ilf_size;
     __uint32_t                ilf_fields;
     __uint16_t                ilf_asize;
     __uint16_t                ilf_dsize;
     __uint32_t                ilf_pad;
     __uint64_t                ilf_ino;
     union {
          __uint32_t           ilfu_rdev;
          uuid_t               ilfu_uuid;
     } ilf_u;
     __int64_t                 ilf_blkno;
     __int32_t                 ilf_len;
     __int32_t                 ilf_boffset;
} xfs_inode_log_format_64_t;
----

*ilf_type*::
The signature of an inode update operation, 0x123b.  This value is in
host-endian order, not big-endian like the rest of XFS.

*ilf_size*::
Number of operations involved in this update, including this format operation.

*ilf_fields*::
Specifies which parts of the inode are being updated.  This can be certain
combinations of the following:

[options="header"]
|=====
| Flag                 | Inode changes to log include:
| +XFS_ILOG_CORE+      | The standard inode fields.
| +XFS_ILOG_DDATA+     | Data fork's local data.
| +XFS_ILOG_DEXT+      | Data fork's extent list.
| +XFS_ILOG_DBROOT+    | Data fork's B+tree root.
| +XFS_ILOG_DEV+       | Data fork's device number.
| +XFS_ILOG_UUID+      | Data fork's UUID contents.
| +XFS_ILOG_ADATA+     | Attribute fork's local data.
| +XFS_ILOG_AEXT+      | Attribute fork's extent list.
| +XFS_ILOG_ABROOT+    | Attribute fork's B+tree root.
| +XFS_ILOG_DOWNER+    | Change the data fork owner on replay.
| +XFS_ILOG_AOWNER+    | Change the attr fork owner on replay.
| +XFS_ILOG_TIMESTAMP+ | Timestamps are dirty, but not necessarily anything else.  Should never appear on disk.
| +XFS_ILOG_NONCORE+   | ( +XFS_ILOG_DDATA+ \| +XFS_ILOG_DEXT+ \| +XFS_ILOG_DBROOT+ \| +XFS_ILOG_DEV+ \| +XFS_ILOG_UUID+ \| +XFS_ILOG_ADATA+ \| +XFS_ILOG_AEXT+ \| +XFS_ILOG_ABROOT+ \| +XFS_ILOG_DOWNER+ \| +XFS_ILOG_AOWNER+ )
| +XFS_ILOG_DFORK+     | ( +XFS_ILOG_DDATA+ \| +XFS_ILOG_DEXT+ \| +XFS_ILOG_DBROOT+ )
| +XFS_ILOG_AFORK+     | ( +XFS_ILOG_ADATA+ \| +XFS_ILOG_AEXT+ \| +XFS_ILOG_ABROOT+ )
| +XFS_ILOG_ALL+       | ( +XFS_ILOG_CORE+ \| +XFS_ILOG_DDATA+ \| +XFS_ILOG_DEXT+ \| +XFS_ILOG_DBROOT+ \| +XFS_ILOG_DEV+ \| +XFS_ILOG_UUID+ \| +XFS_ILOG_ADATA+ \| +XFS_ILOG_AEXT+ \| +XFS_ILOG_ABROOT+ \| +XFS_ILOG_TIMESTAMP+ \| +XFS_ILOG_DOWNER+ \| +XFS_ILOG_AOWNER+ )
|=====

*ilf_asize*::
Size of the attribute fork, in bytes.

*ilf_dsize*::
Size of the data fork, in bytes.

*ilf_ino*::
Absolute node number.

*ilfu_rdev*::
Device number information, for a device file update.

*ilfu_uuid*::
UUID, for a UUID update?

*ilf_blkno*::
Block number of the inode buffer, in sectors.

*ilf_len*::
Length of inode buffer, in sectors.

*ilf_boffset*::
Byte offset of the inode in the buffer.

Be aware that there is a nearly identical +xfs_inode_log_format_32+ which may
appear on disk.  It is the same as +xfs_inode_log_format_64+, except that it is
missing the +ilf_pad+ field and is 52 bytes long as opposed to 56 bytes.

[[Inode_Data_Log_Item]]
=== Inode Data Log Item

This region contains the new contents of a part of an inode, as described in
the xref:Inode_Log_Item[previous section].  There are no magic numbers.

If +XFS_ILOG_CORE+ is set in +ilf_fields+, the corresponding data buffer must
be in the format +struct xfs_icdinode+, which has the same format as the first
96 bytes of an xref:On-disk_Inode[inode], but is recorded in host byte order.

[[Buffer_Log_Item]]
=== Buffer Log Item

This operation writes parts of a buffer to disk.  The regions to write are
tracked in the data map; the actual buffer data are stored in subsequent log
items.

[source, c]
----
typedef struct xfs_buf_log_format {
     unsigned short            blf_type;
     unsigned short            blf_size;
     ushort                    blf_flags;
     ushort                    blf_len;
     __int64_t                 blf_blkno;
     unsigned int              blf_map_size;
     unsigned int              blf_data_map[XFS_BLF_DATAMAP_SIZE];
} xfs_buf_log_format_t;
----

*blf_type*::
Magic number to specify a buffer log item, 0x123c.

*blf_size*::
Number of buffer data items following this item.

*blf_flags*::
Specifies flags associated with the buffer item.  This can be any of the
following:

[options="header"]
|=====
| Flag                 | Description
| +XFS_BLF_INODE_BUF+  | Inode buffer.  These must be recovered before replaying items that change this buffer.
| +XFS_BLF_CANCEL+     | Don't recover this buffer, blocks are being freed.
| +XFS_BLF_UDQUOT_BUF+ | User quota buffer, don't recover if there's a subsequent quotaoff.
| +XFS_BLF_PDQUOT_BUF+ | Project quota buffer, don't recover if there's a subsequent quotaoff.
| +XFS_BLF_GDQUOT_BUF+ | Group quota buffer, don't recover if there's a subsequent quotaoff.
|=====

*blf_len*::
Number of sectors affected by this buffer.

*blf_blkno*::
Block number to write, in sectors.

*blf_map_size*::
The size of +blf_data_map+, in 32-bit words.

*blf_data_map*::
This variable-sized array acts as a dirty bitmap for the logged buffer.  Each
1 bit represents a dirty region in the buffer, and each run of 1 bits
corresponds to a subsequent log item containing the new contents of the buffer
area.  Each bit represents +XFS_BLF_CHUNK+ (i.e. 128) bytes.

[[Buffer_Data_Log_Item]]
=== Buffer Data Log Item

This region contains the new contents of a part of a buffer, as described in
the xref:Buffer_Log_Item[previous section].  There are no magic numbers.

[[Quota_Update_Log_Item]]
=== Update Quota File

This updates a block in a quota file.  The buffer data must be in the next log
item.

[source, c]
----
typedef struct xfs_dq_logformat {
     __uint16_t                qlf_type;
     __uint16_t                qlf_size;
     xfs_dqid_t                qlf_id;
     __int64_t                 qlf_blkno;
     __int32_t                 qlf_len;
     __uint32_t                qlf_boffset;
} xfs_dq_logformat_t;
----

*qlf_type*::
The signature of an inode create operation, 0x123e.  This value is in
host-endian order, not big-endian like the rest of XFS.

*qlf_size*::
Size of this log item.  Should be 2.

*qlf_id*::
The user/group/project ID to alter.

*qlf_blkno*::
Block number of the quota buffer, in sectors.

*qlf_len*::
Length of the quota buffer, in sectors.

*qlf_boffset*::
Buffer offset of the quota data to update, in bytes.

[[Quota_Update_Data_Log_Item]]
=== Quota Update Data Log Item

This region contains the new contents of a part of a buffer, as described in
the xref:Quota_Update_Log_Item[previous section].  There are no magic numbers.

[[Quota_Off_Log_Item]]
=== Disable Quota Log Item

A request to disable quota controls has the following format:

[source, c]
----
typedef struct xfs_qoff_logformat {
     unsigned short            qf_type;
     unsigned short            qf_size;
     unsigned int              qf_flags;
     char                      qf_pad[12];
} xfs_qoff_logformat_t;
----

*qf_type*::
The signature of an inode create operation, 0x123d.  This value is in
host-endian order, not big-endian like the rest of XFS.

*qf_size*::
Size of this log item.  Should be 1.

*qf_flags*::
Specifies which quotas are being turned off.  Can be a combination of the
following:

[options="header"]
|=====
| Flag                 | Quota type to disable
| +XFS_UQUOTA_ACCT+    | User quotas.
| +XFS_PQUOTA_ACCT+    | Project quotas.
| +XFS_GQUOTA_ACCT+    | Group quotas.
|=====

[[Inode_Create_Log_Item]]
=== Inode Creation Log Item

This log item is created when inodes are allocated in-core.  When replaying
this item, the specified inode records will be zeroed and some of the inode
fields populated with default values.

[source, c]
----
struct xfs_icreate_log {
     __uint16_t                icl_type;
     __uint16_t                icl_size;
     __be32                    icl_ag;
     __be32                    icl_agbno;
     __be32                    icl_count;
     __be32                    icl_isize;
     __be32                    icl_length;
     __be32                    icl_gen;
};
----

*icl_type*::
The signature of an inode create operation, 0x123f.  This value is in
host-endian order, not big-endian like the rest of XFS.

*icl_size*::
Size of this log item.  Should be 1.

*icl_ag*::
AG number of the inode chunk to create.

*icl_agbno*::
AG block number of the inode chunk.

*icl_count*::
Number of inodes to initialize.

*icl_isize*::
Size of each inode, in bytes.

*icl_length*::
Length of the extent being initialized, in blocks.

*icl_gen*::
Inode generation number to write into the new inodes.

== xfs_logprint Example

Here's an example of dumping the XFS log contents with +xfs_logprint+:

----
# xfs_logprint /dev/sda
xfs_logprint: /dev/sda contains a mounted and writable filesystem
xfs_logprint:
    data device: 0xfc03
    log device: 0xfc03 daddr: 900931640 length: 879816

cycle: 48	version: 2		lsn: 48,0	tail_lsn: 47,879760
length of Log Record: 19968	prev offset: 879808		num ops: 53
uuid: 24afeec2-f418-46a2-a573-10091f5e200e   format: little endian linux
h_size: 32768
----

This is the log record header.

----
Oper (0): tid: 30483aec  len: 0  clientid: TRANS  flags: START 
----

This operation indicates that we're starting a transaction, so the next
operation should record the transaction header.

----
Oper (1): tid: 30483aec  len: 16  clientid: TRANS  flags: none
TRAN:    type: CHECKPOINT       tid: 30483aec       num_items: 50
----

This operation records a transaction header.  There should be fifty operations
in this transaction and the transaction ID is 0x30483aec.

----
Oper (2): tid: 30483aec  len: 24  clientid: TRANS  flags: none
BUF:  #regs: 2   start blkno: 145400496 (0x8aaa2b0)  len: 8  bmap size: 1  flags: 0x2000
Oper (3): tid: 30483aec  len: 3712  clientid: TRANS  flags: none
BUF DATA
...
Oper (4): tid: 30483aec  len: 24  clientid: TRANS  flags: none
BUF:  #regs: 3   start blkno: 59116912 (0x3860d70)  len: 8  bmap size: 1  flags: 0x2000
Oper (5): tid: 30483aec  len: 128  clientid: TRANS  flags: none
BUF DATA
 0 43544241 49010000 fa347000 2c357000 3a40b200 13000000 2343c200 13000000 
 8 3296d700 13000000 375deb00 13000000 8a551501 13000000 56be1601 13000000 
10 af081901 13000000 ec741c01 13000000 9e911c01 13000000 69073501 13000000 
18 4e539501 13000000  6549501 13000000 5d0e7f00 14000000 c6908200 14000000 

Oper (6): tid: 30483aec  len: 640  clientid: TRANS  flags: none
BUF DATA
 0 7f47c800 21000000 23c0e400 21000000 2d0dfe00 21000000 e7060c01 21000000 
 8 34b91801 21000000 9cca9100 22000000 26e69800 22000000 4c969900 22000000 
...
90 1cf69900 27000000 42f79c00 27000000  6a99e00 27000000  6a99e00 27000000 
98  6a99e00 27000000  6a99e00 27000000  6a99e00 27000000  6a99e00 27000000 
----

Operations 4-6 describe two updates to a single dirty buffer at disk address
59,116,912.  The first chunk of dirty data is 128 bytes long.  Notice how the
first four bytes of the first chunk is 0x43544241?  Remembering that log items
are in host byte order, reverse that to 0x41425443, which is the magic number
for the free space B+tree ordered by size.

The second chunk is 640 bytes.  There are more buffer changes, so we'll skip
ahead a few operations:

----
Oper (19): tid: 30483aec  len: 56  clientid: TRANS  flags: none
INODE: #regs: 2   ino: 0x63a73b4e  flags: 0x1   dsize: 40
        blkno: 1412688704  len: 16  boff: 7168
Oper (20): tid: 30483aec  len: 96  clientid: TRANS  flags: none
INODE CORE
magic 0x494e mode 0100600 version 2 format 3
nlink 1 uid 1000 gid 1000
atime 0x5633d58d mtime 0x563a391b ctime 0x563a391b
size 0x109dc8 nblocks 0x111 extsize 0x0 nextents 0x1b
naextents 0x0 forkoff 0 dmevmask 0x0 dmstate 0x0
flags 0x0 gen 0x389071be
----

This is an update to the core of inode 0x63a73b4e.  There were similar inode
core updates after this, so we'll skip ahead a bit:

----
Oper (32): tid: 30483aec  len: 56  clientid: TRANS  flags: none
INODE: #regs: 3   ino: 0x4bde428  flags: 0x5   dsize: 16
        blkno: 79553568  len: 16  boff: 4096
Oper (33): tid: 30483aec  len: 96  clientid: TRANS  flags: none
INODE CORE
magic 0x494e mode 0100644 version 2 format 2
nlink 1 uid 1000 gid 1000
atime 0x563a3924 mtime 0x563a3931 ctime 0x563a3931
size 0x1210 nblocks 0x2 extsize 0x0 nextents 0x1
naextents 0x0 forkoff 0 dmevmask 0x0 dmstate 0x0
flags 0x0 gen 0x2829c6f9
Oper (34): tid: 30483aec  len: 16  clientid: TRANS  flags: none
EXTENTS inode data
----

This inode update changes both the core and also the data fork.  Since we're
changing the block map, it's unsurprising that one of the subsequent operations
is an EFI:

----
Oper (37): tid: 30483aec  len: 32  clientid: TRANS  flags: none
EFI:  #regs: 1    num_extents: 1  id: 0xffff8801147b5c20
(s: 0x720daf, l: 1) 
\----------------------------------------------------------------------------
Oper (38): tid: 30483aec  len: 32  clientid: TRANS  flags: none
EFD:  #regs: 1    num_extents: 1  id: 0xffff8801147b5c20
\----------------------------------------------------------------------------
Oper (39): tid: 30483aec  len: 24  clientid: TRANS  flags: none
BUF:  #regs: 2   start blkno: 8 (0x8)  len: 8  bmap size: 1  flags: 0x2800
Oper (40): tid: 30483aec  len: 128  clientid: TRANS  flags: none
AGF Buffer: XAGF  
ver: 1  seq#: 0  len: 56308224  
root BNO: 18174905  CNT: 18175030
level BNO: 2  CNT: 2
1st: 41  last: 46  cnt: 6  freeblks: 35790503  longest: 19343245
\----------------------------------------------------------------------------
Oper (41): tid: 30483aec  len: 24  clientid: TRANS  flags: none
BUF:  #regs: 3   start blkno: 145398760 (0x8aa9be8)  len: 8  bmap size: 1  flags: 0x2000
Oper (42): tid: 30483aec  len: 128  clientid: TRANS  flags: none
BUF DATA
Oper (43): tid: 30483aec  len: 128  clientid: TRANS  flags: none
BUF DATA
\----------------------------------------------------------------------------
Oper (44): tid: 30483aec  len: 24  clientid: TRANS  flags: none
BUF:  #regs: 3   start blkno: 145400224 (0x8aaa1a0)  len: 8  bmap size: 1  flags: 0x2000
Oper (45): tid: 30483aec  len: 128  clientid: TRANS  flags: none
BUF DATA
Oper (46): tid: 30483aec  len: 3584  clientid: TRANS  flags: none
BUF DATA
\----------------------------------------------------------------------------
Oper (47): tid: 30483aec  len: 24  clientid: TRANS  flags: none
BUF:  #regs: 3   start blkno: 59066216 (0x3854768)  len: 8  bmap size: 1  flags: 0x2000
Oper (48): tid: 30483aec  len: 128  clientid: TRANS  flags: none
BUF DATA
Oper (49): tid: 30483aec  len: 768  clientid: TRANS  flags: none
BUF DATA
----

Here we see an EFI, followed by an EFD, followed by updates to the AGF and the
free space B+trees.  Most probably, we just unmapped a few blocks from a file.

----
Oper (50): tid: 30483aec  len: 56  clientid: TRANS  flags: none
INODE: #regs: 2   ino: 0x3906f20  flags: 0x1   dsize: 16
        blkno: 59797280  len: 16  boff: 0
Oper (51): tid: 30483aec  len: 96  clientid: TRANS  flags: none
INODE CORE
magic 0x494e mode 0100644 version 2 format 2
nlink 1 uid 1000 gid 1000
atime 0x563a3938 mtime 0x563a3938 ctime 0x563a3938
size 0x0 nblocks 0x0 extsize 0x0 nextents 0x0
naextents 0x0 forkoff 0 dmevmask 0x0 dmstate 0x0
flags 0x0 gen 0x35ed661
\----------------------------------------------------------------------------
Oper (52): tid: 30483aec  len: 0  clientid: TRANS  flags: COMMIT 
----

One more inode core update and this transaction commits.