*
* For the five existing metadata inodes (real time bitmap & summary; and the
* user, group, and quotas) we'll continue to maintain the in-core superblock
- * inodes for reads and only require xfs_imeta_create and xfs_imeta_unlink to
+ * inodes for reads and only require xfs_imeta_dir_create to
* persist changes. New metadata inode types must only use the xfs_imeta_*
* functions.
*
* to user space.
*/
-/* Static metadata inode paths */
-static const unsigned char *rtbitmap_path[] = {"realtime", "bitmap"};
-static const unsigned char *rtsummary_path[] = {"realtime", "summary"};
-static const unsigned char *usrquota_path[] = {"quota", "user"};
-static const unsigned char *grpquota_path[] = {"quota", "group"};
-static const unsigned char *prjquota_path[] = {"quota", "project"};
-
-XFS_IMETA_DEFINE_PATH(XFS_IMETA_RTBITMAP, rtbitmap_path);
-XFS_IMETA_DEFINE_PATH(XFS_IMETA_RTSUMMARY, rtsummary_path);
-XFS_IMETA_DEFINE_PATH(XFS_IMETA_USRQUOTA, usrquota_path);
-XFS_IMETA_DEFINE_PATH(XFS_IMETA_GRPQUOTA, grpquota_path);
-XFS_IMETA_DEFINE_PATH(XFS_IMETA_PRJQUOTA, prjquota_path);
-
-const struct xfs_imeta_path XFS_IMETA_METADIR = {
- .im_depth = 0,
- .im_ftype = XFS_DIR3_FT_DIR,
-};
-
-/* Are these two paths equal? */
-STATIC bool
-xfs_imeta_path_compare(
- const struct xfs_imeta_path *a,
- const struct xfs_imeta_path *b)
-{
- unsigned int i;
-
- if (a == b)
- return true;
-
- if (a->im_depth != b->im_depth)
- return false;
-
- for (i = 0; i < a->im_depth; i++)
- if (a->im_path[i] != b->im_path[i] &&
- strcmp(a->im_path[i], b->im_path[i]))
- return false;
-
- return true;
-}
-
-/* Is this path ok? */
-static inline bool
-xfs_imeta_path_check(
- const struct xfs_imeta_path *path)
-{
- return path->im_depth <= XFS_IMETA_MAX_DEPTH;
-}
-
-/* Functions for storing and retrieving superblock inode values. */
-
-/* Mapping of metadata inode paths to in-core superblock values. */
-static const struct xfs_imeta_sbmap {
- const struct xfs_imeta_path *path;
- unsigned int offset;
-} xfs_imeta_sbmaps[] = {
- {
- .path = &XFS_IMETA_RTBITMAP,
- .offset = offsetof(struct xfs_sb, sb_rbmino),
- },
- {
- .path = &XFS_IMETA_RTSUMMARY,
- .offset = offsetof(struct xfs_sb, sb_rsumino),
- },
- {
- .path = &XFS_IMETA_USRQUOTA,
- .offset = offsetof(struct xfs_sb, sb_uquotino),
- },
- {
- .path = &XFS_IMETA_GRPQUOTA,
- .offset = offsetof(struct xfs_sb, sb_gquotino),
- },
- {
- .path = &XFS_IMETA_PRJQUOTA,
- .offset = offsetof(struct xfs_sb, sb_pquotino),
- },
- {
- .path = &XFS_IMETA_METADIR,
- .offset = offsetof(struct xfs_sb, sb_metadirino),
- },
- { NULL, 0 },
-};
-
-/* Return a pointer to the in-core superblock inode value. */
-static inline xfs_ino_t *
-xfs_imeta_sbmap_to_inop(
- struct xfs_mount *mp,
- const struct xfs_imeta_sbmap *map)
-{
- return (xfs_ino_t *)(((char *)&mp->m_sb) + map->offset);
-}
-
-/* Compute location of metadata inode pointer in the in-core superblock */
-static inline xfs_ino_t *
-xfs_imeta_path_to_sb_inop(
- struct xfs_mount *mp,
- const struct xfs_imeta_path *path)
-{
- const struct xfs_imeta_sbmap *p;
-
- for (p = xfs_imeta_sbmaps; p->path; p++)
- if (xfs_imeta_path_compare(p->path, path))
- return xfs_imeta_sbmap_to_inop(mp, p);
-
- return NULL;
-}
-
-/* Look up a superblock metadata inode by its path. */
-STATIC int
-xfs_imeta_sb_lookup(
- struct xfs_mount *mp,
- const struct xfs_imeta_path *path,
- xfs_ino_t *inop)
-{
- xfs_ino_t *sb_inop;
-
- sb_inop = xfs_imeta_path_to_sb_inop(mp, path);
- if (!sb_inop)
- return -EINVAL;
-
- trace_xfs_imeta_sb_lookup(mp, sb_inop);
- *inop = *sb_inop;
- return 0;
-}
-
/* Update inode pointers in the superblock. */
static inline void
xfs_imeta_log_sb(
* Create a new metadata inode and set a superblock pointer to this new inode.
* The superblock field must not already be pointing to an inode.
*/
-STATIC int
+int
xfs_imeta_sb_create(
- struct xfs_imeta_update *upd,
- umode_t mode)
+ struct xfs_trans **tpp,
+ xfs_ino_t *sb_inop,
+ umode_t mode,
+ struct xfs_inode **ipp)
{
+ struct xfs_mount *mp = (*tpp)->t_mountp;
struct xfs_icreate_args args = {
.nlink = S_ISDIR(mode) ? 2 : 1,
};
- struct xfs_mount *mp = upd->mp;
- xfs_ino_t *sb_inop;
xfs_ino_t ino;
int error;
/* Files rooted in the superblock do not have parents. */
xfs_icreate_args_rootfile(&args, mp, mode, false);
- /* Reject if the sb already points to some inode. */
- sb_inop = xfs_imeta_path_to_sb_inop(mp, upd->path);
- if (!sb_inop)
- return -EINVAL;
-
+ /* Reject if the sb already points to an inode. */
if (*sb_inop != NULLFSINO)
return -EEXIST;
/* Create a new inode and set the sb pointer. */
- error = xfs_dialloc(&upd->tp, NULL, mode, &ino);
+ error = xfs_dialloc(tpp, NULL, mode, &ino);
if (error)
return error;
- error = xfs_icreate(upd->tp, ino, &args, &upd->ip);
+ error = xfs_icreate(*tpp, ino, &args, ipp);
if (error)
return error;
- upd->ip_locked = true;
+
+ if (S_ISDIR(mode)) {
+ ASSERT(sb_inop == &mp->m_sb.sb_metadirino);
+
+ xfs_imeta_set_iflag(*tpp, *ipp);
+ error = xfs_dir_init(*tpp, *ipp, *ipp);
+ if (error)
+ return error;
+ }
/*
* If we ever need the ability to create rt metadata files on a
/* Update superblock pointer. */
*sb_inop = ino;
- xfs_imeta_log_sb(upd->tp);
-
- trace_xfs_imeta_sb_create(upd);
- return 0;
-}
-
-/*
- * Clear the given inode pointer from the superblock and drop the link count
- * of the metadata inode.
- */
-STATIC int
-xfs_imeta_sb_unlink(
- struct xfs_imeta_update *upd)
-{
- struct xfs_mount *mp = upd->mp;
- xfs_ino_t *sb_inop;
+ xfs_imeta_log_sb(*tpp);
- ASSERT(xfs_isilocked(upd->ip, XFS_ILOCK_EXCL));
-
- sb_inop = xfs_imeta_path_to_sb_inop(mp, upd->path);
- if (!sb_inop)
- return -EINVAL;
-
- /* Reject if the sb doesn't point to the inode that was passed in. */
- if (*sb_inop != upd->ip->i_ino)
- return -ENOENT;
-
- trace_xfs_imeta_sb_unlink(upd);
-
- *sb_inop = NULLFSINO;
- xfs_imeta_log_sb(upd->tp);
- return xfs_droplink(upd->tp, upd->ip);
-}
-
-/* Set the given inode pointer in the superblock. */
-STATIC int
-xfs_imeta_sb_link(
- struct xfs_imeta_update *upd)
-{
- struct xfs_mount *mp = upd->mp;
- xfs_ino_t *sb_inop;
-
- ASSERT(xfs_isilocked(upd->ip, XFS_ILOCK_EXCL));
-
- sb_inop = xfs_imeta_path_to_sb_inop(mp, upd->path);
- if (!sb_inop)
- return -EINVAL;
- if (*sb_inop != NULLFSINO)
- return -EEXIST;
-
- trace_xfs_imeta_sb_link(upd);
-
- xfs_bumplink(upd->tp, upd->ip);
- xfs_imeta_log_sb(upd->tp);
-
- *sb_inop = upd->ip->i_ino;
+ trace_xfs_imeta_sb_create(mp, sb_inop);
return 0;
}
/* Functions for storing and retrieving metadata directory inode values. */
-static inline void
-xfs_imeta_set_xname(
- struct xfs_name *xname,
- const struct xfs_imeta_path *path,
- unsigned int path_idx,
- unsigned char ftype)
-{
- xname->name = (const unsigned char *)path->im_path[path_idx];
- xname->len = strlen(path->im_path[path_idx]);
- xname->type = ftype;
-}
-
/*
- * Look up the inode number and filetype for an exact name in a directory.
+ * Given a parent directory @dp and a metadata inode path component @name,
+ * Look up the inode number in the directory, returning it in @ino.
+ * @xname.type must match the directory entry's ftype.
+ *
* Caller must hold ILOCK_EXCL.
*/
static inline int
-xfs_imeta_dir_lookup(
+xfs_imeta_dir_lookup_locked(
struct xfs_trans *tp,
struct xfs_inode *dp,
struct xfs_name *xname,
if (xfs_is_shutdown(dp->i_mount))
return -EIO;
+ if (!S_ISDIR(VFS_I(dp)->i_mode)) {
+ xfs_fs_mark_sick(dp->i_mount, XFS_SICK_FS_METADIR);
+ return -EFSCORRUPTED;
+ }
+
if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
error = xfs_dir2_sf_lookup(&args);
goto out_unlock;
return error;
*ino = args.inumber;
- xname->type = args.filetype;
- return 0;
-}
-/*
- * Given a parent directory @dp and a metadata inode path component @xname,
- * Look up the inode number in the directory, returning it in @ino.
- * @xname.type must match the directory entry's ftype.
- *
- * Caller must hold ILOCK_EXCL.
- */
-static inline int
-xfs_imeta_dir_lookup_component(
- struct xfs_trans *tp,
- struct xfs_inode *dp,
- struct xfs_name *xname,
- xfs_ino_t *ino)
-{
- int type_wanted = xname->type;
- int error;
-
- if (!S_ISDIR(VFS_I(dp)->i_mode)) {
- xfs_fs_mark_sick(dp->i_mount, XFS_SICK_FS_METADIR);
- return -EFSCORRUPTED;
- }
-
- error = xfs_imeta_dir_lookup(tp, dp, xname, ino);
- if (error)
- return error;
if (!xfs_verify_ino(dp->i_mount, *ino)) {
xfs_fs_mark_sick(dp->i_mount, XFS_SICK_FS_METADIR);
return -EFSCORRUPTED;
}
- if (type_wanted != XFS_DIR3_FT_UNKNOWN && xname->type != type_wanted) {
+ if (xname->type != XFS_DIR3_FT_UNKNOWN &&
+ args.filetype != xname->type) {
xfs_fs_mark_sick(dp->i_mount, XFS_SICK_FS_METADIR);
return -EFSCORRUPTED;
}
return 0;
}
-/*
- * Traverse a metadata directory tree path, returning the inode corresponding
- * to the parent of the last path component. If any of the path components do
- * not exist, return -ENOENT. Caller must supply a transaction to avoid
- * livelocks on btree cycles.
- *
- * @dp is returned without any locks held.
- */
-int
-xfs_imeta_dir_parent(
- struct xfs_trans *tp,
- const struct xfs_imeta_path *path,
- struct xfs_inode **dpp)
-{
- struct xfs_name xname;
- struct xfs_mount *mp = tp->t_mountp;
- struct xfs_inode *dp = NULL;
- xfs_ino_t ino;
- unsigned int i;
- int error;
-
- /* Caller wanted the root, we're done! */
- if (path->im_depth == 0)
- goto out;
-
- /* No metadata directory means no parent. */
- if (mp->m_metadirip == NULL)
- return -ENOENT;
-
- /* Grab a new reference to the metadir root dir. */
- error = xfs_imeta_iget(tp, mp->m_metadirip->i_ino, XFS_DIR3_FT_DIR,
- &dp);
- if (error)
- return error;
-
- for (i = 0; i < path->im_depth - 1; i++) {
- struct xfs_inode *ip = NULL;
-
- xfs_ilock(dp, XFS_ILOCK_EXCL);
-
- /* Look up the name in the current directory. */
- xfs_imeta_set_xname(&xname, path, i, XFS_DIR3_FT_DIR);
- error = xfs_imeta_dir_lookup_component(tp, dp, &xname, &ino);
- if (error)
- goto out_rele;
-
- /*
- * Grab the child inode while we still have the parent
- * directory locked.
- */
- error = xfs_imeta_iget(tp, ino, XFS_DIR3_FT_DIR, &ip);
- if (error)
- goto out_rele;
-
- xfs_iunlock(dp, XFS_ILOCK_EXCL);
- xfs_imeta_irele(dp);
- dp = ip;
- }
-
-out:
- *dpp = dp;
- return 0;
-
-out_rele:
- xfs_iunlock(dp, XFS_ILOCK_EXCL);
- xfs_imeta_irele(dp);
- return error;
-}
-
/*
* Look up a metadata inode from the metadata directory. If the last path
* component doesn't exist, return NULLFSINO. If any other part of the path
* does not exist, return -ENOENT so we can distinguish the two.
*/
-STATIC int
-xfs_imeta_dir_lookup_int(
+int
+xfs_imeta_dir_lookup(
struct xfs_trans *tp,
- const struct xfs_imeta_path *path,
- xfs_ino_t *inop)
+ struct xfs_inode *dp,
+ const char *name,
+ uint8_t ftype,
+ struct xfs_inode **ipp)
{
- struct xfs_name xname;
- struct xfs_inode *dp = NULL;
- xfs_ino_t ino;
+ struct xfs_mount *mp = tp->t_mountp;
+ struct xfs_name xname = {
+ .name = (const unsigned char *)name,
+ .len = strlen(name),
+ .type = ftype,
+ };
int error;
+ xfs_ino_t ino;
- /* metadir ino is recorded in superblock */
- if (xfs_imeta_path_compare(path, &XFS_IMETA_METADIR))
- return xfs_imeta_sb_lookup(tp->t_mountp, path, inop);
-
- ASSERT(path->im_depth > 0);
-
- /* Find the parent of the last path component. */
- error = xfs_imeta_dir_parent(tp, path, &dp);
- if (error)
- return error;
+ ASSERT(xfs_has_metadir(mp));
xfs_ilock(dp, XFS_ILOCK_EXCL);
-
- /* Look up the name in the current directory. */
- xfs_imeta_set_xname(&xname, path, path->im_depth - 1, path->im_ftype);
- error = xfs_imeta_dir_lookup_component(tp, dp, &xname, &ino);
- switch (error) {
- case 0:
- *inop = ino;
- break;
- case -ENOENT:
- *inop = NULLFSINO;
- error = 0;
- break;
- }
-
+ error = xfs_imeta_dir_lookup_locked(tp, dp, &xname, &ino);
xfs_iunlock(dp, XFS_ILOCK_EXCL);
- xfs_imeta_irele(dp);
- return error;
-}
-/*
- * Load all the metadata inode pointers that are cached in the in-core
- * superblock but live somewhere in the metadata directory tree.
- */
-STATIC int
-xfs_imeta_dir_mount(
- struct xfs_trans *tp)
-{
- struct xfs_mount *mp = tp->t_mountp;
- const struct xfs_imeta_sbmap *p;
- xfs_ino_t *sb_inop;
- int err2;
- int error = 0;
-
- for (p = xfs_imeta_sbmaps; p->path && p->path->im_depth > 0; p++) {
- if (p->path == &XFS_IMETA_METADIR)
- continue;
- sb_inop = xfs_imeta_sbmap_to_inop(mp, p);
- err2 = xfs_imeta_dir_lookup_int(tp, p->path, sb_inop);
- if (err2 == -ENOENT) {
- *sb_inop = NULLFSINO;
- continue;
- }
- if (!error && err2)
- error = err2;
- }
+ if (error)
+ return error;
- return error;
+ if (!xfs_verify_ino(mp, ino))
+ return -EFSCORRUPTED;
+ return xfs_imeta_iget(tp, ino, ftype, ipp);
}
/* Set up an inode to be recognized as a metadata directory inode. */
ip->i_diflags2 &= ~XFS_DIFLAG2_METADIR;
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
}
+
/*
- * Create a new metadata inode accessible via the given metadata directory path.
- * Callers must ensure that the directory entry does not already exist; a new
- * one will be created.
+ * Create a metadata inode with the given @mode, and insert it into the
+ * metadata directory tree at the given @path. The path (up to the final
+ * component) must already exist.
+ *
+ * The new metadata inode will be attached to the update structure @upd->ip,
+ * with the ILOCK held until the caller releases it. @ipp is set to upd->ip
+ * as a convenience for callers.
+ *
+ * Callers must ensure that the root dquots are allocated, if applicable.
+ *
+ * NOTE: This function may return a new inode to the caller even if it returns
+ * a negative error code. If an inode is passed back, the caller must finish
+ * setting up the inode before releasing it.
*/
-STATIC int
+int
xfs_imeta_dir_create(
struct xfs_imeta_update *upd,
umode_t mode)
.pip = upd->dp,
.nlink = S_ISDIR(mode) ? 2 : 1,
};
- struct xfs_name xname;
+ struct xfs_name xname = {
+ .name = (const unsigned char *)upd->name,
+ .len = strlen(upd->name),
+ .type = XFS_DIR3_FT_UNKNOWN,
+ };
struct xfs_dir_update du = {
.dp = upd->dp,
.name = &xname,
.ppargs = upd->ppargs,
};
- struct xfs_mount *mp = upd->mp;
- xfs_ino_t *sb_inop;
+ struct xfs_mount *mp = upd->dp->i_mount;
xfs_ino_t ino;
unsigned int resblks;
int error;
+ ASSERT(xfs_has_metadir(mp));
ASSERT(xfs_isilocked(upd->dp, XFS_ILOCK_EXCL));
- /* metadir ino is recorded in superblock; only mkfs gets to do this */
- if (xfs_imeta_path_compare(upd->path, &XFS_IMETA_METADIR)) {
- error = xfs_imeta_sb_create(upd, mode);
- if (error)
- return error;
-
- /* Set the metadata iflag, initialize directory. */
- xfs_imeta_set_iflag(upd->tp, upd->ip);
- return xfs_dir_init(upd->tp, upd->ip, upd->ip);
- }
-
- ASSERT(upd->path->im_depth > 0);
-
xfs_icreate_args_rootfile(&args, mp, mode, xfs_has_parent(mp));
/* Check that the name does not already exist in the directory. */
- xfs_imeta_set_xname(&xname, upd->path, upd->path->im_depth - 1,
- XFS_DIR3_FT_UNKNOWN);
- error = xfs_imeta_dir_lookup_component(upd->tp, upd->dp, &xname, &ino);
+ error = xfs_imeta_dir_lookup_locked(upd->tp, upd->dp, &xname, &ino);
switch (error) {
case -ENOENT:
break;
case 0:
- error = -EEXIST;
- fallthrough;
+ return -EEXIST;
default:
return error;
}
- /*
- * A newly created regular or special file just has one directory
- * entry pointing to them, but a directory also the "." entry
- * pointing to itself.
- */
error = xfs_dialloc(&upd->tp, upd->dp, mode, &ino);
if (error)
return error;
return error;
du.ip = upd->ip;
xfs_imeta_set_iflag(upd->tp, upd->ip);
- upd->ip_locked = true;
/*
* Join the directory inode to the transaction. We do not do it
trace_xfs_imeta_dir_create(upd);
- /* Update the in-core superblock value if there is one. */
- sb_inop = xfs_imeta_path_to_sb_inop(mp, upd->path);
- if (sb_inop)
- *sb_inop = ino;
return 0;
}
-/*
- * Remove the given entry from the metadata directory and drop the link count
- * of the metadata inode.
- */
-STATIC int
-xfs_imeta_dir_unlink(
- struct xfs_imeta_update *upd)
-{
- struct xfs_name xname;
- struct xfs_dir_update du = {
- .dp = upd->dp,
- .name = &xname,
- .ip = upd->ip,
- .ppargs = upd->ppargs,
- };
- struct xfs_mount *mp = upd->mp;
- xfs_ino_t *sb_inop;
- xfs_ino_t ino;
- unsigned int resblks;
- int error;
-
- ASSERT(xfs_isilocked(upd->dp, XFS_ILOCK_EXCL));
- ASSERT(xfs_isilocked(upd->ip, XFS_ILOCK_EXCL));
-
- /* Metadata directory root cannot be unlinked. */
- if (xfs_imeta_path_compare(upd->path, &XFS_IMETA_METADIR)) {
- ASSERT(0);
- xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR);
- return -EFSCORRUPTED;
- }
-
- ASSERT(upd->path->im_depth > 0);
-
- /* Look up the name in the current directory. */
- xfs_imeta_set_xname(&xname, upd->path, upd->path->im_depth - 1,
- xfs_mode_to_ftype(VFS_I(upd->ip)->i_mode));
- error = xfs_imeta_dir_lookup_component(upd->tp, upd->dp, &xname, &ino);
- switch (error) {
- case 0:
- if (ino != upd->ip->i_ino)
- error = -ENOENT;
- break;
- case -ENOENT:
- xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR);
- error = -EFSCORRUPTED;
- break;
- }
- if (error)
- return error;
-
- resblks = xfs_remove_space_res(mp, xname.len);
- error = xfs_dir_remove_child(upd->tp, resblks, &du);
- if (error)
- return error;
-
- trace_xfs_imeta_dir_unlink(upd);
-
- /* Update the in-core superblock value if there is one. */
- sb_inop = xfs_imeta_path_to_sb_inop(mp, upd->path);
- if (sb_inop)
- *sb_inop = NULLFSINO;
- return 0;
-}
-
-/* Set the given path in the metadata directory to point to an inode. */
-STATIC int
-xfs_imeta_dir_link(
- struct xfs_imeta_update *upd)
-{
- struct xfs_name xname;
- struct xfs_dir_update du = {
- .dp = upd->dp,
- .name = &xname,
- .ip = upd->ip,
- .ppargs = upd->ppargs,
- };
- struct xfs_mount *mp = upd->mp;
- xfs_ino_t *sb_inop;
- xfs_ino_t ino;
- unsigned int resblks;
- int error;
-
- ASSERT(xfs_isilocked(upd->dp, XFS_ILOCK_EXCL));
- ASSERT(xfs_isilocked(upd->ip, XFS_ILOCK_EXCL));
-
- /* Metadata directory root cannot be linked. */
- if (xfs_imeta_path_compare(upd->path, &XFS_IMETA_METADIR)) {
- ASSERT(0);
- xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR);
- return -EFSCORRUPTED;
- }
-
- ASSERT(upd->path->im_depth > 0);
-
- /* Look up the name in the current directory. */
- xfs_imeta_set_xname(&xname, upd->path, upd->path->im_depth - 1,
- xfs_mode_to_ftype(VFS_I(upd->ip)->i_mode));
- error = xfs_imeta_dir_lookup_component(upd->tp, upd->dp, &xname, &ino);
- switch (error) {
- case -ENOENT:
- break;
- case 0:
- error = -EEXIST;
- fallthrough;
- default:
- return error;
- }
-
- resblks = xfs_link_space_res(mp, xname.len);
- error = xfs_dir_add_child(upd->tp, resblks, &du);
- if (error)
- return error;
-
- trace_xfs_imeta_dir_link(upd);
-
- /* Update the in-core superblock value if there is one. */
- sb_inop = xfs_imeta_path_to_sb_inop(mp, upd->path);
- if (sb_inop)
- *sb_inop = upd->ip->i_ino;
- return 0;
-}
-
-/* General functions for managing metadata inode pointers */
-
-/*
- * Is this metadata inode pointer ok? We allow the fields to be set to
- * NULLFSINO if the metadata structure isn't present, and we don't allow
- * obviously incorrect inode pointers.
- */
-static inline bool
-xfs_imeta_verify(
- struct xfs_mount *mp,
- xfs_ino_t ino)
-{
- if (ino == NULLFSINO)
- return true;
- return xfs_verify_ino(mp, ino);
-}
-
-/* Look up a metadata inode by its path. */
-int
-xfs_imeta_lookup(
- struct xfs_trans *tp,
- const struct xfs_imeta_path *path,
- xfs_ino_t *inop)
-{
- struct xfs_mount *mp = tp->t_mountp;
- xfs_ino_t ino;
- int error;
-
- ASSERT(xfs_imeta_path_check(path));
-
- if (xfs_has_metadir(mp)) {
- error = xfs_imeta_dir_lookup_int(tp, path, &ino);
- if (error == -ENOENT) {
- xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR);
- return -EFSCORRUPTED;
- }
- } else {
- error = xfs_imeta_sb_lookup(mp, path, &ino);
- }
- if (error)
- return error;
-
- if (!xfs_imeta_verify(mp, ino)) {
- xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR);
- return -EFSCORRUPTED;
- }
-
- *inop = ino;
- return 0;
-}
-
-/*
- * Create a metadata inode with the given @mode, and insert it into the
- * metadata directory tree at the given @path. The path (up to the final
- * component) must already exist.
- *
- * The new metadata inode will be attached to the update structure @upd->ip,
- * with the ILOCK held until the caller releases it. @ipp is set to upd->ip
- * as a convenience for callers.
- *
- * Callers must ensure that the root dquots are allocated, if applicable.
- *
- * NOTE: This function may return a new inode to the caller even if it returns
- * a negative error code. If an inode is passed back, the caller must finish
- * setting up the inode before releasing it.
- */
-int
-xfs_imeta_create(
- struct xfs_imeta_update *upd,
- umode_t mode,
- struct xfs_inode **ipp)
-{
- struct xfs_mount *mp = upd->mp;
- int error;
-
- ASSERT(xfs_imeta_path_check(upd->path));
-
- *ipp = NULL;
-
- if (xfs_has_metadir(mp))
- error = xfs_imeta_dir_create(upd, mode);
- else
- error = xfs_imeta_sb_create(upd, mode);
- *ipp = upd->ip;
- return error;
-}
-
-/* Free a file from the metadata directory tree. */
-STATIC int
-xfs_imeta_ifree(
- struct xfs_trans *tp,
- struct xfs_inode *ip)
-{
- struct xfs_mount *mp = ip->i_mount;
- struct xfs_perag *pag;
- struct xfs_icluster xic = { 0 };
- int error;
-
- ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
- ASSERT(VFS_I(ip)->i_nlink == 0);
- ASSERT(ip->i_df.if_nextents == 0);
- ASSERT(ip->i_disk_size == 0 || !S_ISREG(VFS_I(ip)->i_mode));
- ASSERT(ip->i_nblocks == 0);
-
- pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));
-
- error = xfs_dir_ifree(tp, pag, ip, &xic);
- if (error)
- goto out;
-
- /* Metadata files do not support ownership changes or DMAPI. */
-
- if (xic.deleted)
- error = xfs_ifree_cluster(tp, pag, ip, &xic);
-out:
- xfs_perag_put(pag);
- return error;
-}
-
-/*
- * Unlink a metadata inode @upd->ip from the metadata directory given by @path.
- * The path must already exist.
- */
-int
-xfs_imeta_unlink(
- struct xfs_imeta_update *upd)
-{
- int error;
-
- ASSERT(xfs_imeta_path_check(upd->path));
- ASSERT(xfs_imeta_verify(upd->mp, upd->ip->i_ino));
-
- if (xfs_has_metadir(upd->mp))
- error = xfs_imeta_dir_unlink(upd);
- else
- error = xfs_imeta_sb_unlink(upd);
- if (error)
- return error;
-
- /*
- * Metadata files require explicit resource cleanup. In other words,
- * the inactivation system will not touch these files, so we must free
- * the ondisk inode by ourselves if warranted.
- */
- if (VFS_I(upd->ip)->i_nlink > 0)
- return 0;
-
- return xfs_imeta_ifree(upd->tp, upd->ip);
-}
-
-/*
- * Link the metadata directory given by @path to the inode @upd->ip.
- * The path (up to the final component) must already exist, but the final
- * component must not already exist.
- */
-int
-xfs_imeta_link(
- struct xfs_imeta_update *upd)
-{
- ASSERT(xfs_imeta_path_check(upd->path));
-
- if (xfs_has_metadir(upd->mp))
- return xfs_imeta_dir_link(upd);
- return xfs_imeta_sb_link(upd);
-}
-
-/* Does this inode number refer to a static metadata inode? */
-bool
-xfs_is_static_meta_ino(
- struct xfs_mount *mp,
- xfs_ino_t ino)
-{
- const struct xfs_imeta_sbmap *p;
-
- if (ino == NULLFSINO)
- return false;
-
- for (p = xfs_imeta_sbmaps; p->path; p++)
- if (ino == *xfs_imeta_sbmap_to_inop(mp, p))
- return true;
-
- return false;
-}
-
-/*
- * Ensure that the in-core superblock has all the values that it should.
- * Caller should pass in an empty transaction to avoid livelocking on btree
- * cycles.
- */
-int
-xfs_imeta_mount(
- struct xfs_trans *tp)
-{
- if (xfs_has_metadir(tp->t_mountp))
- return xfs_imeta_dir_mount(tp);
-
- return 0;
-}
-
-/* Create a path to a file within the metadata directory tree. */
-int
-xfs_imeta_create_file_path(
- struct xfs_mount *mp,
- unsigned int nr_components,
- struct xfs_imeta_path **pathp)
-{
- struct xfs_imeta_path *p;
- unsigned char **components;
-
- p = kzalloc(sizeof(struct xfs_imeta_path), GFP_KERNEL);
- if (!p)
- return -ENOMEM;
-
- components = kvcalloc(nr_components, sizeof(unsigned char *),
- GFP_KERNEL);
- if (!components) {
- kfree(p);
- return -ENOMEM;
- }
-
- p->im_depth = nr_components;
- p->im_path = (const unsigned char **)components;
- p->im_ftype = XFS_DIR3_FT_REG_FILE;
- *pathp = p;
- return 0;
-}
-
-/* Free a metadata directory tree path. */
-void
-xfs_imeta_free_path(
- const struct xfs_imeta_path *path)
-{
- unsigned int i;
-
- if (path->im_flags & XFS_IMETA_PATH_STATIC)
- return;
-
- for (i = 0; i < path->im_depth; i++) {
- if ((path->im_dynamicmask & (1ULL << i)) && path->im_path[i])
- kfree(path->im_path[i]);
- }
- kfree(path->im_path);
- kfree(path);
-}
-
/*
* Is the amount of space that could be allocated towards a given metadata
* file at or beneath a certain threshold?