@@ -174,6 +174,8 @@ typedef struct xfs_sb {
174
174
xfs_lsn_t sb_lsn ; /* last write sequence */
175
175
uuid_t sb_meta_uuid ; /* metadata file system unique id */
176
176
177
+ xfs_ino_t sb_metadirino ; /* metadata directory tree root */
178
+
177
179
/* must be padded to 64 bit alignment */
178
180
} xfs_sb_t ;
179
181
@@ -259,6 +261,8 @@ struct xfs_dsb {
259
261
__be64 sb_lsn ; /* last write sequence */
260
262
uuid_t sb_meta_uuid ; /* metadata file system unique id */
261
263
264
+ __be64 sb_metadirino ; /* metadata directory tree root */
265
+
262
266
/* must be padded to 64 bit alignment */
263
267
};
264
268
@@ -278,7 +282,7 @@ struct xfs_dsb {
278
282
279
283
#define XFS_SB_VERSION_NUM (sbp ) ((sbp)->sb_versionnum & XFS_SB_VERSION_NUMBITS)
280
284
281
- static inline bool xfs_sb_is_v5 (struct xfs_sb * sbp )
285
+ static inline bool xfs_sb_is_v5 (const struct xfs_sb * sbp )
282
286
{
283
287
return XFS_SB_VERSION_NUM (sbp ) == XFS_SB_VERSION_5 ;
284
288
}
@@ -287,12 +291,12 @@ static inline bool xfs_sb_is_v5(struct xfs_sb *sbp)
287
291
* Detect a mismatched features2 field. Older kernels read/wrote
288
292
* this into the wrong slot, so to be safe we keep them in sync.
289
293
*/
290
- static inline bool xfs_sb_has_mismatched_features2 (struct xfs_sb * sbp )
294
+ static inline bool xfs_sb_has_mismatched_features2 (const struct xfs_sb * sbp )
291
295
{
292
296
return sbp -> sb_bad_features2 != sbp -> sb_features2 ;
293
297
}
294
298
295
- static inline bool xfs_sb_version_hasmorebits (struct xfs_sb * sbp )
299
+ static inline bool xfs_sb_version_hasmorebits (const struct xfs_sb * sbp )
296
300
{
297
301
return xfs_sb_is_v5 (sbp ) ||
298
302
(sbp -> sb_versionnum & XFS_SB_VERSION_MOREBITSBIT );
@@ -342,8 +346,8 @@ static inline void xfs_sb_version_addprojid32(struct xfs_sb *sbp)
342
346
#define XFS_SB_FEAT_COMPAT_UNKNOWN ~XFS_SB_FEAT_COMPAT_ALL
343
347
static inline bool
344
348
xfs_sb_has_compat_feature (
345
- struct xfs_sb * sbp ,
346
- uint32_t feature )
349
+ const struct xfs_sb * sbp ,
350
+ uint32_t feature )
347
351
{
348
352
return (sbp -> sb_features_compat & feature ) != 0 ;
349
353
}
@@ -360,8 +364,8 @@ xfs_sb_has_compat_feature(
360
364
#define XFS_SB_FEAT_RO_COMPAT_UNKNOWN ~XFS_SB_FEAT_RO_COMPAT_ALL
361
365
static inline bool
362
366
xfs_sb_has_ro_compat_feature (
363
- struct xfs_sb * sbp ,
364
- uint32_t feature )
367
+ const struct xfs_sb * sbp ,
368
+ uint32_t feature )
365
369
{
366
370
return (sbp -> sb_features_ro_compat & feature ) != 0 ;
367
371
}
@@ -374,6 +378,7 @@ xfs_sb_has_ro_compat_feature(
374
378
#define XFS_SB_FEAT_INCOMPAT_NREXT64 (1 << 5) /* large extent counters */
375
379
#define XFS_SB_FEAT_INCOMPAT_EXCHRANGE (1 << 6) /* exchangerange supported */
376
380
#define XFS_SB_FEAT_INCOMPAT_PARENT (1 << 7) /* parent pointers */
381
+ #define XFS_SB_FEAT_INCOMPAT_METADIR (1 << 8) /* metadata dir tree */
377
382
#define XFS_SB_FEAT_INCOMPAT_ALL \
378
383
(XFS_SB_FEAT_INCOMPAT_FTYPE | \
379
384
XFS_SB_FEAT_INCOMPAT_SPINODES | \
@@ -387,8 +392,8 @@ xfs_sb_has_ro_compat_feature(
387
392
#define XFS_SB_FEAT_INCOMPAT_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_ALL
388
393
static inline bool
389
394
xfs_sb_has_incompat_feature (
390
- struct xfs_sb * sbp ,
391
- uint32_t feature )
395
+ const struct xfs_sb * sbp ,
396
+ uint32_t feature )
392
397
{
393
398
return (sbp -> sb_features_incompat & feature ) != 0 ;
394
399
}
@@ -399,8 +404,8 @@ xfs_sb_has_incompat_feature(
399
404
#define XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_LOG_ALL
400
405
static inline bool
401
406
xfs_sb_has_incompat_log_feature (
402
- struct xfs_sb * sbp ,
403
- uint32_t feature )
407
+ const struct xfs_sb * sbp ,
408
+ uint32_t feature )
404
409
{
405
410
return (sbp -> sb_features_log_incompat & feature ) != 0 ;
406
411
}
@@ -420,7 +425,7 @@ xfs_sb_add_incompat_log_features(
420
425
sbp -> sb_features_log_incompat |= features ;
421
426
}
422
427
423
- static inline bool xfs_sb_version_haslogxattrs (struct xfs_sb * sbp )
428
+ static inline bool xfs_sb_version_haslogxattrs (const struct xfs_sb * sbp )
424
429
{
425
430
return xfs_sb_is_v5 (sbp ) && (sbp -> sb_features_log_incompat &
426
431
XFS_SB_FEAT_INCOMPAT_LOG_XATTRS );
@@ -790,6 +795,27 @@ static inline time64_t xfs_bigtime_to_unix(uint64_t ondisk_seconds)
790
795
return (time64_t )ondisk_seconds - XFS_BIGTIME_EPOCH_OFFSET ;
791
796
}
792
797
798
+ enum xfs_metafile_type {
799
+ XFS_METAFILE_UNKNOWN , /* unknown */
800
+ XFS_METAFILE_DIR , /* metadir directory */
801
+ XFS_METAFILE_USRQUOTA , /* user quota */
802
+ XFS_METAFILE_GRPQUOTA , /* group quota */
803
+ XFS_METAFILE_PRJQUOTA , /* project quota */
804
+ XFS_METAFILE_RTBITMAP , /* rt bitmap */
805
+ XFS_METAFILE_RTSUMMARY , /* rt summary */
806
+
807
+ XFS_METAFILE_MAX
808
+ } __packed ;
809
+
810
+ #define XFS_METAFILE_TYPE_STR \
811
+ { XFS_METAFILE_UNKNOWN, "unknown" }, \
812
+ { XFS_METAFILE_DIR, "dir" }, \
813
+ { XFS_METAFILE_USRQUOTA, "usrquota" }, \
814
+ { XFS_METAFILE_GRPQUOTA, "grpquota" }, \
815
+ { XFS_METAFILE_PRJQUOTA, "prjquota" }, \
816
+ { XFS_METAFILE_RTBITMAP, "rtbitmap" }, \
817
+ { XFS_METAFILE_RTSUMMARY, "rtsummary" }
818
+
793
819
/*
794
820
* On-disk inode structure.
795
821
*
@@ -812,7 +838,7 @@ struct xfs_dinode {
812
838
__be16 di_mode ; /* mode and type of file */
813
839
__u8 di_version ; /* inode version */
814
840
__u8 di_format ; /* format of di_c data */
815
- __be16 di_onlink ; /* old number of links to file */
841
+ __be16 di_metatype ; /* XFS_METAFILE_*; was di_onlink */
816
842
__be32 di_uid ; /* owner's user id */
817
843
__be32 di_gid ; /* owner's group id */
818
844
__be32 di_nlink ; /* number of links to file */
@@ -1088,21 +1114,60 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev)
1088
1114
* Values for di_flags2 These start by being exposed to userspace in the upper
1089
1115
* 16 bits of the XFS_XFLAG_s range.
1090
1116
*/
1091
- #define XFS_DIFLAG2_DAX_BIT 0 /* use DAX for this inode */
1092
- #define XFS_DIFLAG2_REFLINK_BIT 1 /* file's blocks may be shared */
1093
- #define XFS_DIFLAG2_COWEXTSIZE_BIT 2 /* copy on write extent size hint */
1094
- #define XFS_DIFLAG2_BIGTIME_BIT 3 /* big timestamps */
1095
- #define XFS_DIFLAG2_NREXT64_BIT 4 /* large extent counters */
1117
+ /* use DAX for this inode */
1118
+ #define XFS_DIFLAG2_DAX_BIT 0
1119
+
1120
+ /* file's blocks may be shared */
1121
+ #define XFS_DIFLAG2_REFLINK_BIT 1
1096
1122
1097
- #define XFS_DIFLAG2_DAX (1 << XFS_DIFLAG2_DAX_BIT)
1098
- #define XFS_DIFLAG2_REFLINK (1 << XFS_DIFLAG2_REFLINK_BIT)
1099
- #define XFS_DIFLAG2_COWEXTSIZE (1 << XFS_DIFLAG2_COWEXTSIZE_BIT)
1100
- #define XFS_DIFLAG2_BIGTIME (1 << XFS_DIFLAG2_BIGTIME_BIT)
1101
- #define XFS_DIFLAG2_NREXT64 (1 << XFS_DIFLAG2_NREXT64_BIT)
1123
+ /* copy on write extent size hint */
1124
+ #define XFS_DIFLAG2_COWEXTSIZE_BIT 2
1125
+
1126
+ /* big timestamps */
1127
+ #define XFS_DIFLAG2_BIGTIME_BIT 3
1128
+
1129
+ /* large extent counters */
1130
+ #define XFS_DIFLAG2_NREXT64_BIT 4
1131
+
1132
+ /*
1133
+ * The inode contains filesystem metadata and can be found through the metadata
1134
+ * directory tree. Metadata inodes must satisfy the following constraints:
1135
+ *
1136
+ * - V5 filesystem (and ftype) are enabled;
1137
+ * - The only valid modes are regular files and directories;
1138
+ * - The access bits must be zero;
1139
+ * - DMAPI event and state masks are zero;
1140
+ * - The user and group IDs must be zero;
1141
+ * - The project ID can be used as a u32 annotation;
1142
+ * - The immutable, sync, noatime, nodump, nodefrag flags must be set.
1143
+ * - The dax flag must not be set.
1144
+ * - Directories must have nosymlinks set.
1145
+ *
1146
+ * These requirements are chosen defensively to minimize the ability of
1147
+ * userspace to read or modify the contents, should a metadata file ever
1148
+ * escape to userspace.
1149
+ *
1150
+ * There are further constraints on the directory tree itself:
1151
+ *
1152
+ * - Metadata inodes must never be resolvable through the root directory;
1153
+ * - They must never be accessed by userspace;
1154
+ * - Metadata directory entries must have correct ftype.
1155
+ *
1156
+ * Superblock-rooted metadata files must have the METADATA iflag set even
1157
+ * though they do not have a parent directory.
1158
+ */
1159
+ #define XFS_DIFLAG2_METADATA_BIT 5
1160
+
1161
+ #define XFS_DIFLAG2_DAX (1ULL << XFS_DIFLAG2_DAX_BIT)
1162
+ #define XFS_DIFLAG2_REFLINK (1ULL << XFS_DIFLAG2_REFLINK_BIT)
1163
+ #define XFS_DIFLAG2_COWEXTSIZE (1ULL << XFS_DIFLAG2_COWEXTSIZE_BIT)
1164
+ #define XFS_DIFLAG2_BIGTIME (1ULL << XFS_DIFLAG2_BIGTIME_BIT)
1165
+ #define XFS_DIFLAG2_NREXT64 (1ULL << XFS_DIFLAG2_NREXT64_BIT)
1166
+ #define XFS_DIFLAG2_METADATA (1ULL << XFS_DIFLAG2_METADATA_BIT)
1102
1167
1103
1168
#define XFS_DIFLAG2_ANY \
1104
1169
(XFS_DIFLAG2_DAX | XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE | \
1105
- XFS_DIFLAG2_BIGTIME | XFS_DIFLAG2_NREXT64)
1170
+ XFS_DIFLAG2_BIGTIME | XFS_DIFLAG2_NREXT64 | XFS_DIFLAG2_METADATA )
1106
1171
1107
1172
static inline bool xfs_dinode_has_bigtime (const struct xfs_dinode * dip )
1108
1173
{
@@ -1117,6 +1182,12 @@ static inline bool xfs_dinode_has_large_extent_counts(
1117
1182
(dip -> di_flags2 & cpu_to_be64 (XFS_DIFLAG2_NREXT64 ));
1118
1183
}
1119
1184
1185
+ static inline bool xfs_dinode_is_metadir (const struct xfs_dinode * dip )
1186
+ {
1187
+ return dip -> di_version >= 3 &&
1188
+ (dip -> di_flags2 & cpu_to_be64 (XFS_DIFLAG2_METADATA ));
1189
+ }
1190
+
1120
1191
/*
1121
1192
* Inode number format:
1122
1193
* low inopblog bits - offset in block
0 commit comments