* or the MMAPLOCK since metadata inodes should never be exposed to user space.
*/
-/* 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;
-}
-
static inline void
xfs_imeta_set_xname(
struct xfs_name *xname,
- const struct xfs_imeta_path *path,
- unsigned int path_idx,
+ const char *path,
unsigned char ftype)
{
- xname->name = (const unsigned char *)path->im_path[path_idx];
- xname->len = strlen(path->im_path[path_idx]);
+ xname->name = (const unsigned char *)path;
+ xname->len = strlen(path);
xname->type = ftype;
}
}
/*
- * 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.
+ * Look up a metadata inode from the metadata directory. If the path
+ * component doesn't exist, return -ENOENT.
*/
int
-xfs_imeta_iget_parent(
+xfs_imeta_lookup(
struct xfs_trans *tp,
- const struct xfs_imeta_path *path,
- struct xfs_inode **dpp)
+ struct xfs_inode *dp,
+ const char *path,
+ xfs_ino_t *inop)
{
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, S_IFDIR, &dp);
- if (error)
- return error;
-
- for (i = 0; i < path->im_depth - 1; i++) {
- struct xfs_inode *ip = NULL;
+ xfs_imeta_set_xname(&xname, path, XFS_DIR3_FT_UNKNOWN);
- 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_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, S_IFDIR, &ip);
- if (error)
- goto out_rele;
-
- xfs_iunlock(dp, XFS_ILOCK_EXCL);
- xfs_irele(dp);
- dp = ip;
- }
-
-out:
- *dpp = dp;
- return 0;
-
-out_rele:
+ xfs_ilock(dp, XFS_ILOCK_EXCL);
+ error = xfs_imeta_lookup_component(tp, dp, &xname, inop);
xfs_iunlock(dp, XFS_ILOCK_EXCL);
- xfs_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.
- */
int
-xfs_imeta_lookup(
- struct xfs_trans *tp,
- const struct xfs_imeta_path *path,
- xfs_ino_t *inop)
+xfs_imeta_load(
+ struct xfs_trans *tp,
+ struct xfs_inode *dp,
+ const char *path,
+ umode_t mode,
+ struct xfs_inode **ipp)
{
- struct xfs_name xname;
- struct xfs_inode *dp = NULL;
- int error;
-
- ASSERT(xfs_imeta_path_check(path));
-
- /* Metadata directory root cannot be used with this function. */
- if (path->im_depth == 0) {
- ASSERT(0);
- return -EFSCORRUPTED;
- }
+ int error;
+ xfs_ino_t ino;
- /* Find the parent of the last path component. */
- error = xfs_imeta_iget_parent(tp, path, &dp);
+ error = xfs_imeta_lookup(tp, dp, path, &ino);
if (error)
return error;
-
- 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_lookup_component(tp, dp, &xname, inop);
- if (error == -ENOENT) {
- *inop = NULLFSINO;
- error = 0;
- }
-
- xfs_iunlock(dp, XFS_ILOCK_EXCL);
- xfs_irele(dp);
-
- return error;
+ return xfs_imeta_iget(tp, ino, mode, ipp);
}
/* Set up an inode to be recognized as a metadata directory inode. */
/* Initialize a metadata update structure. */
static inline int
xfs_imeta_init_update(
- struct xfs_mount *mp,
- const struct xfs_imeta_path *path,
+ struct xfs_inode *dp,
+ const char *path,
struct xfs_imeta_update *upd)
{
- struct xfs_trans *tp;
- int error;
-
- ASSERT(xfs_has_metadir(mp));
+ ASSERT(xfs_has_metadir(dp->i_mount));
memset(upd, 0, sizeof(struct xfs_imeta_update));
- upd->mp = mp;
+ upd->mp = dp->i_mount;
+ upd->dp = dp;
upd->path = path;
- /*
- * Find the parent of the last path component. If the parent path does
- * not exist, we consider this corruption because paths are supposed
- * to exist. For example, if the path is /quota/user, we require that
- * /quota already exists.
- */
- error = xfs_trans_alloc_empty(mp, &tp);
- if (error)
- return error;
- error = xfs_imeta_iget_parent(tp, upd->path, &upd->dp);
- xfs_trans_cancel(tp);
- if (error == -ENOENT) {
- xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR);
- return -EFSCORRUPTED;
- }
- if (xfs_metadata_is_sick(error))
- xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR);
- if (error)
- return error;
-
- return xfs_parent_start(mp, &upd->ppargs);
+ return xfs_parent_start(upd->mp, &upd->ppargs);
}
/*
if (upd->dp_locked)
xfs_iunlock(upd->dp, XFS_ILOCK_EXCL);
upd->dp_locked = false;
-
- xfs_irele(upd->dp);
- upd->dp = NULL;
}
}
*/
int
xfs_imeta_start_create(
- struct xfs_mount *mp,
- const struct xfs_imeta_path *path,
+ struct xfs_inode *dp,
+ const char *path,
struct xfs_imeta_update *upd)
{
+ struct xfs_mount *mp = dp->i_mount;
int error;
- error = xfs_imeta_init_update(mp, path, upd);
+ error = xfs_imeta_init_update(dp, path, upd);
if (error)
return error;
unsigned int resblks;
int error;
- ASSERT(xfs_imeta_path_check(upd->path));
xfs_assert_ilocked(upd->dp, XFS_ILOCK_EXCL);
- /* Metadata directory root cannot be created with this function. */
- if (upd->path->im_depth == 0) {
- ASSERT(0);
- xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR);
- return -EFSCORRUPTED;
- }
-
/* 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);
+ xfs_imeta_set_xname(&xname, upd->path, XFS_DIR3_FT_UNKNOWN);
error = xfs_imeta_lookup_component(upd->tp, upd->dp, &xname, &ino);
switch (error) {
case -ENOENT:
*/
int
xfs_imeta_start_link(
- struct xfs_mount *mp,
- const struct xfs_imeta_path *path,
+ struct xfs_inode *dp,
+ const char *path,
struct xfs_inode *ip,
struct xfs_imeta_update *upd)
{
+ struct xfs_mount *mp = dp->i_mount;
unsigned int resblks;
int nospace_error = 0;
int error;
- error = xfs_imeta_init_update(mp, path, upd);
+ error = xfs_imeta_init_update(dp, path, upd);
if (error)
return error;
- ASSERT(upd->dp != NULL);
-
upd->ip = ip;
resblks = xfs_link_space_res(mp, MAXNAMELEN);
unsigned int resblks;
int error;
- ASSERT(xfs_imeta_path_check(upd->path));
-
xfs_assert_ilocked(upd->dp, XFS_ILOCK_EXCL);
xfs_assert_ilocked(upd->ip, XFS_ILOCK_EXCL);
- /* Metadata directory root cannot be linked. */
- if (upd->path->im_depth == 0) {
- ASSERT(0);
- xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR);
- return -EFSCORRUPTED;
- }
-
/* Look up the name in the current directory. */
- xfs_imeta_set_xname(&xname, upd->path, upd->path->im_depth - 1,
+ xfs_imeta_set_xname(&xname, upd->path,
xfs_mode_to_ftype(VFS_I(upd->ip)->i_mode));
error = xfs_imeta_lookup_component(upd->tp, upd->dp, &xname, &ino);
switch (error) {
}
/* Create a metadata for the last component of the path. */
-STATIC int
+int
xfs_imeta_mkdir(
- struct xfs_mount *mp,
- const struct xfs_imeta_path *path)
+ struct xfs_inode *dp,
+ const char *path,
+ struct xfs_inode **ipp)
{
struct xfs_imeta_update upd = { };
int error;
- if (xfs_is_shutdown(mp))
+ if (xfs_is_shutdown(dp->i_mount))
return -EIO;
/* Allocate a transaction to create the last directory. */
- error = xfs_imeta_start_create(mp, path, &upd);
+ error = xfs_imeta_start_create(dp, path, &upd);
if (error)
return error;
goto out_cancel;
error = xfs_imeta_commit(&upd);
+ if (error)
+ goto out_irele;
- /*
- * We don't pass the directory we just created to the caller, so finish
- * setting up the inode, then release the dir and the dquots.
- */
- goto out_irele;
+ xfs_finish_inode_setup(upd.ip);
+ *ipp = upd.ip;
+ return 0;
out_cancel:
xfs_imeta_cancel(&upd, error);
return error;
}
-/*
- * Make sure that every metadata directory path component exists and is a
- * directory.
- */
-int
-xfs_imeta_ensure_dirpath(
- struct xfs_mount *mp,
- const struct xfs_imeta_path *path)
-{
- struct xfs_imeta_path temp_path = {
- .im_path = path->im_path,
- .im_ftype = XFS_DIR3_FT_DIR,
- };
- int error = 0;
-
- if (!xfs_has_metadir(mp))
- return 0;
-
- for (temp_path.im_depth = 1;
- temp_path.im_depth < path->im_depth;
- temp_path.im_depth++) {
- error = xfs_imeta_mkdir(mp, &temp_path);
- if (error && error != -EEXIST)
- return error;
- }
-
- 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;
- const char **components;
-
- p = kzalloc(sizeof(struct xfs_imeta_path), GFP_KERNEL);
- if (!p)
- return -ENOMEM;
-
- components = kvcalloc(nr_components, sizeof(char *), GFP_KERNEL);
- if (!components) {
- kfree(p);
- return -ENOMEM;
- }
-
- p->im_depth = nr_components;
- p->im_path = 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;
-
- 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?
#ifndef __XFS_IMETA_H__
#define __XFS_IMETA_H__
-/* How deep can we nest metadata dirs? */
-#define XFS_IMETA_MAX_DEPTH 64
-
-/* Key for looking up metadata inodes. */
-struct xfs_imeta_path {
- /* Array of string pointers. */
- const char **im_path;
-
- /* Set bits correspond to components of im_path needing to be freed */
- unsigned long long im_dynamicmask;
-
- /* Number of strings in path. 0 here means the metadir root. */
- uint8_t im_depth;
-
- /* Expected file type. */
- uint8_t im_ftype;
-};
-
/* Cleanup widget for metadata inode creation and deletion. */
struct xfs_imeta_update {
struct xfs_mount *mp;
struct xfs_trans *tp;
/* Path to metadata file */
- const struct xfs_imeta_path *path;
+ const char *path;
/* Parent pointer update context */
struct xfs_parent_args *ppargs;
unsigned int ip_locked:1;
};
-/* Grab the last path component, mostly for tracing. */
-static inline const char *
-xfs_imeta_lastpath(
- const struct xfs_imeta_update *upd)
-{
- if (upd->path && upd->path->im_path && upd->path->im_depth > 0)
- return upd->path->im_path[upd->path->im_depth - 1];
- return "?";
-}
-
-int xfs_imeta_lookup(struct xfs_trans *tp, const struct xfs_imeta_path *path,
- xfs_ino_t *ino);
-int xfs_imeta_iget_parent(struct xfs_trans *tp,
- const struct xfs_imeta_path *path, struct xfs_inode **dpp);
-
-int xfs_imeta_create_file_path(struct xfs_mount *mp,
- unsigned int nr_components, struct xfs_imeta_path **pathp);
-void xfs_imeta_free_path(const struct xfs_imeta_path *path);
+int xfs_imeta_lookup(struct xfs_trans *tp, struct xfs_inode *dp,
+ const char *path, xfs_ino_t *ino);
+int xfs_imeta_load(struct xfs_trans *tp, struct xfs_inode *dp,
+ const char *path, umode_t mode, struct xfs_inode **ipp);
void xfs_imeta_set_iflag(struct xfs_trans *tp, struct xfs_inode *ip);
void xfs_imeta_clear_iflag(struct xfs_trans *tp, struct xfs_inode *ip);
-int xfs_imeta_ensure_dirpath(struct xfs_mount *mp,
- const struct xfs_imeta_path *path);
-
-int xfs_imeta_start_create(struct xfs_mount *mp,
- const struct xfs_imeta_path *path,
+int xfs_imeta_start_create(struct xfs_inode *dp, const char *path,
struct xfs_imeta_update *upd);
int xfs_imeta_create(struct xfs_imeta_update *upd, umode_t mode);
-int xfs_imeta_start_link(struct xfs_mount *mp,
- const struct xfs_imeta_path *path,
+int xfs_imeta_start_link(struct xfs_inode *dp, const char *path,
struct xfs_inode *ip, struct xfs_imeta_update *upd);
int xfs_imeta_link(struct xfs_imeta_update *upd);
+int xfs_imeta_mkdir(struct xfs_inode *dp, const char *path,
+ struct xfs_inode **ipp);
+
int xfs_imeta_commit(struct xfs_imeta_update *upd);
void xfs_imeta_cancel(struct xfs_imeta_update *upd, int error);