@@ -398,7 +398,8 @@ xfs_sb_has_ro_compat_feature(
XFS_SB_FEAT_INCOMPAT_BIGTIME| \
XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR| \
XFS_SB_FEAT_INCOMPAT_NREXT64| \
- XFS_SB_FEAT_INCOMPAT_PARENT)
+ XFS_SB_FEAT_INCOMPAT_PARENT | \
+ XFS_SB_FEAT_INCOMPAT_METADIR)
#define XFS_SB_FEAT_INCOMPAT_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_ALL
static inline bool
@@ -271,6 +271,17 @@ option set.
When the option
.B \-m finobt=0
is used, the inode btree counter feature is not supported and is disabled.
+.TP
+.BI metadir= value
+This option creates an internal directory tree to store filesystem metadata.
+.IP
+By default,
+.B mkfs.xfs
+will not enable this feature.
+If the option
+.B \-m crc=0
+is used, the metadata directory feature is not supported and is disabled.
+
.TP
.BI uuid= value
Use the given value as the filesystem UUID for the newly created filesystem.
@@ -6,6 +6,7 @@ bigtime=0
crc=1
finobt=1
inobtcount=0
+metadir=0
reflink=0
rmapbt=0
@@ -6,6 +6,7 @@ bigtime=0
crc=1
finobt=1
inobtcount=0
+metadir=0
reflink=1
rmapbt=0
@@ -6,6 +6,7 @@ bigtime=1
crc=1
finobt=1
inobtcount=1
+metadir=0
reflink=1
rmapbt=0
@@ -17,6 +17,7 @@ static void fail(char *msg, int i);
static struct xfs_trans * getres(struct xfs_mount *mp, uint blocks);
static void rsvfile(xfs_mount_t *mp, xfs_inode_t *ip, long long len);
static char *newregfile(char **pp, int *len);
+static int metadir_create(struct xfs_mount *mp);
static void rtinit(xfs_mount_t *mp);
static void rtfreesp_init(struct xfs_mount *mp);
static long filesize(int fd);
@@ -705,8 +706,15 @@ parseproto(
* RT initialization. Do this here to ensure that
* the RT inodes get placed after the root inode.
*/
- if (isroot)
+ if (isroot) {
+ error = metadir_create(mp);
+ if (error)
+ fail(
+ _("Creation of the metadata directory inode failed"),
+ error);
+
rtinit(mp);
+ }
tp = NULL;
for (;;) {
name = getdirentname(pp);
@@ -744,6 +752,41 @@ parse_proto(
parseproto(mp, NULL, fsx, pp, NULL);
}
+/* Create a new metadata root directory. */
+static int
+metadir_create(
+ struct xfs_mount *mp)
+{
+ struct xfs_imeta_update upd;
+ struct xfs_inode *ip = NULL;
+ int error;
+
+ if (!xfs_has_metadir(mp))
+ return 0;
+
+ error = -libxfs_imeta_start_create(mp, &XFS_IMETA_METADIR, &upd);
+ if (error)
+ return error;
+
+ error = -libxfs_imeta_create(&upd, S_IFDIR, &ip);
+ if (error)
+ goto out_cancel;
+
+ error = -libxfs_imeta_commit_update(&upd);
+ if (error)
+ goto out_rele;
+
+ mp->m_metadirip = ip;
+ return 0;
+
+out_cancel:
+ libxfs_imeta_cancel_update(&upd, error);
+out_rele:
+ if (ip)
+ libxfs_irele(ip);
+ return error;
+}
+
/* Create the realtime bitmap inode. */
static void
rtbitmap_create(
@@ -147,6 +147,7 @@ enum {
M_REFLINK,
M_INOBTCNT,
M_BIGTIME,
+ M_METADIR,
M_MAX_OPTS,
};
@@ -801,6 +802,7 @@ static struct opt_params mopts = {
[M_REFLINK] = "reflink",
[M_INOBTCNT] = "inobtcount",
[M_BIGTIME] = "bigtime",
+ [M_METADIR] = "metadir",
[M_MAX_OPTS] = NULL,
},
.subopt_params = {
@@ -844,6 +846,12 @@ static struct opt_params mopts = {
.maxval = 1,
.defaultval = 1,
},
+ { .index = M_METADIR,
+ .conflicts = { { NULL, LAST_CONFLICT } },
+ .minval = 0,
+ .maxval = 1,
+ .defaultval = 1,
+ },
},
};
@@ -896,6 +904,7 @@ struct sb_feat_args {
bool reflink; /* XFS_SB_FEAT_RO_COMPAT_REFLINK */
bool inobtcnt; /* XFS_SB_FEAT_RO_COMPAT_INOBTCNT */
bool bigtime; /* XFS_SB_FEAT_INCOMPAT_BIGTIME */
+ bool metadir; /* XFS_SB_FEAT_INCOMPAT_METADIR */
bool nodalign;
bool nortalign;
bool nrext64;
@@ -1028,7 +1037,7 @@ usage( void )
/* blocksize */ [-b size=num]\n\
/* config file */ [-c options=xxx]\n\
/* metadata */ [-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1,\n\
- inobtcount=0|1,bigtime=0|1]\n\
+ inobtcount=0|1,bigtime=0|1,metadir=0|1]\n\
/* data subvol */ [-d agcount=n,agsize=n,file,name=xxx,size=num,\n\
(sunit=value,swidth=value|su=num,sw=num|noalign),\n\
sectsize=num,concurrency=num]\n\
@@ -1845,6 +1854,9 @@ meta_opts_parser(
case M_BIGTIME:
cli->sb_feat.bigtime = getnum(value, opts, subopt);
break;
+ case M_METADIR:
+ cli->sb_feat.metadir = getnum(value, opts, subopt);
+ break;
default:
return -EINVAL;
}
@@ -2384,6 +2396,13 @@ _("64 bit extent count not supported without CRC support\n"));
usage();
}
cli->sb_feat.nrext64 = false;
+
+ if (cli->sb_feat.metadir) {
+ fprintf(stderr,
+_("metadata directory not supported without CRC support\n"));
+ usage();
+ }
+ cli->sb_feat.metadir = false;
}
if (!cli->sb_feat.finobt) {
@@ -3508,6 +3527,8 @@ sb_set_features(
sbp->sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_PARENT;
sbp->sb_versionnum |= XFS_SB_VERSION_ATTRBIT;
}
+ if (fp->metadir)
+ sbp->sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_METADIR;
/*
* Sparse inode chunk support has two main inode alignment requirements.
@@ -3957,6 +3978,7 @@ finish_superblock_setup(
platform_uuid_copy(&sbp->sb_meta_uuid, &cfg->uuid);
sbp->sb_logstart = cfg->logstart;
sbp->sb_rootino = sbp->sb_rbmino = sbp->sb_rsumino = NULLFSINO;
+ sbp->sb_metadirino = NULLFSINO;
sbp->sb_agcount = (xfs_agnumber_t)cfg->agcount;
sbp->sb_rbmblocks = cfg->rtbmblocks;
sbp->sb_logblocks = (xfs_extlen_t)cfg->logblocks;