Commit 1fa2e819 authored by Darrick J. Wong's avatar Darrick J. Wong

xfs: create libxfs helper to link a new inode into a directory

Create a new libxfs function to link a newly created inode into a
directory.  The upcoming metadata directory feature will need this to
create a metadata directory tree.
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent b11b11e3
...@@ -19,6 +19,9 @@ ...@@ -19,6 +19,9 @@
#include "xfs_error.h" #include "xfs_error.h"
#include "xfs_trace.h" #include "xfs_trace.h"
#include "xfs_health.h" #include "xfs_health.h"
#include "xfs_bmap_btree.h"
#include "xfs_trans_space.h"
#include "xfs_parent.h"
const struct xfs_name xfs_name_dotdot = { const struct xfs_name xfs_name_dotdot = {
.name = (const unsigned char *)"..", .name = (const unsigned char *)"..",
...@@ -756,3 +759,53 @@ xfs_dir2_compname( ...@@ -756,3 +759,53 @@ xfs_dir2_compname(
return xfs_ascii_ci_compname(args, name, len); return xfs_ascii_ci_compname(args, name, len);
return xfs_da_compname(args, name, len); return xfs_da_compname(args, name, len);
} }
/*
* Given a directory @dp, a newly allocated inode @ip, and a @name, link @ip
* into @dp under the given @name. If @ip is a directory, it will be
* initialized. Both inodes must have the ILOCK held and the transaction must
* have sufficient blocks reserved.
*/
int
xfs_dir_create_child(
struct xfs_trans *tp,
unsigned int resblks,
struct xfs_dir_update *du)
{
struct xfs_inode *dp = du->dp;
const struct xfs_name *name = du->name;
struct xfs_inode *ip = du->ip;
int error;
xfs_assert_ilocked(ip, XFS_ILOCK_EXCL);
xfs_assert_ilocked(dp, XFS_ILOCK_EXCL);
error = xfs_dir_createname(tp, dp, name, ip->i_ino, resblks);
if (error) {
ASSERT(error != -ENOSPC);
return error;
}
xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
if (S_ISDIR(VFS_I(ip)->i_mode)) {
error = xfs_dir_init(tp, ip, dp);
if (error)
return error;
xfs_bumplink(tp, dp);
}
/*
* If we have parent pointers, we need to add the attribute containing
* the parent information now.
*/
if (du->ppargs) {
error = xfs_parent_addname(tp, du->ppargs, dp, name, ip);
if (error)
return error;
}
return 0;
}
...@@ -309,4 +309,16 @@ static inline unsigned char xfs_ascii_ci_xfrm(unsigned char c) ...@@ -309,4 +309,16 @@ static inline unsigned char xfs_ascii_ci_xfrm(unsigned char c)
return c; return c;
} }
struct xfs_parent_args;
struct xfs_dir_update {
struct xfs_inode *dp;
const struct xfs_name *name;
struct xfs_inode *ip;
struct xfs_parent_args *ppargs;
};
int xfs_dir_create_child(struct xfs_trans *tp, unsigned int resblks,
struct xfs_dir_update *du);
#endif /* __XFS_DIR2_H__ */ #endif /* __XFS_DIR2_H__ */
...@@ -714,14 +714,16 @@ xfs_create( ...@@ -714,14 +714,16 @@ xfs_create(
struct xfs_inode **ipp) struct xfs_inode **ipp)
{ {
struct xfs_inode *dp = args->pip; struct xfs_inode *dp = args->pip;
struct xfs_dir_update du = {
.dp = dp,
.name = name,
};
struct xfs_mount *mp = dp->i_mount; struct xfs_mount *mp = dp->i_mount;
struct xfs_inode *ip = NULL;
struct xfs_trans *tp = NULL; struct xfs_trans *tp = NULL;
struct xfs_dquot *udqp; struct xfs_dquot *udqp;
struct xfs_dquot *gdqp; struct xfs_dquot *gdqp;
struct xfs_dquot *pdqp; struct xfs_dquot *pdqp;
struct xfs_trans_res *tres; struct xfs_trans_res *tres;
struct xfs_parent_args *ppargs;
xfs_ino_t ino; xfs_ino_t ino;
bool unlock_dp_on_error = false; bool unlock_dp_on_error = false;
bool is_dir = S_ISDIR(args->mode); bool is_dir = S_ISDIR(args->mode);
...@@ -748,7 +750,7 @@ xfs_create( ...@@ -748,7 +750,7 @@ xfs_create(
tres = &M_RES(mp)->tr_create; tres = &M_RES(mp)->tr_create;
} }
error = xfs_parent_start(mp, &ppargs); error = xfs_parent_start(mp, &du.ppargs);
if (error) if (error)
goto out_release_dquots; goto out_release_dquots;
...@@ -779,7 +781,7 @@ xfs_create( ...@@ -779,7 +781,7 @@ xfs_create(
*/ */
error = xfs_dialloc(&tp, dp->i_ino, args->mode, &ino); error = xfs_dialloc(&tp, dp->i_ino, args->mode, &ino);
if (!error) if (!error)
error = xfs_icreate(tp, ino, args, &ip); error = xfs_icreate(tp, ino, args, &du.ip);
if (error) if (error)
goto out_trans_cancel; goto out_trans_cancel;
...@@ -792,38 +794,15 @@ xfs_create( ...@@ -792,38 +794,15 @@ xfs_create(
*/ */
xfs_trans_ijoin(tp, dp, 0); xfs_trans_ijoin(tp, dp, 0);
error = xfs_dir_createname(tp, dp, name, ip->i_ino, error = xfs_dir_create_child(tp, resblks, &du);
resblks - XFS_IALLOC_SPACE_RES(mp));
if (error) {
ASSERT(error != -ENOSPC);
goto out_trans_cancel;
}
xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
if (is_dir) {
error = xfs_dir_init(tp, ip, dp);
if (error) if (error)
goto out_trans_cancel; goto out_trans_cancel;
xfs_bumplink(tp, dp);
}
/*
* If we have parent pointers, we need to add the attribute containing
* the parent information now.
*/
if (ppargs) {
error = xfs_parent_addname(tp, ppargs, dp, name, ip);
if (error)
goto out_trans_cancel;
}
/* /*
* Create ip with a reference from dp, and add '.' and '..' references * Create ip with a reference from dp, and add '.' and '..' references
* if it's a directory. * if it's a directory.
*/ */
xfs_dir_update_hook(dp, ip, 1, name); xfs_dir_update_hook(dp, du.ip, 1, name);
/* /*
* If this is a synchronous mount, make sure that the * If this is a synchronous mount, make sure that the
...@@ -838,7 +817,7 @@ xfs_create( ...@@ -838,7 +817,7 @@ xfs_create(
* These ids of the inode couldn't have changed since the new * These ids of the inode couldn't have changed since the new
* inode has been locked ever since it was created. * inode has been locked ever since it was created.
*/ */
xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp); xfs_qm_vop_create_dqattach(tp, du.ip, udqp, gdqp, pdqp);
error = xfs_trans_commit(tp); error = xfs_trans_commit(tp);
if (error) if (error)
...@@ -848,10 +827,10 @@ xfs_create( ...@@ -848,10 +827,10 @@ xfs_create(
xfs_qm_dqrele(gdqp); xfs_qm_dqrele(gdqp);
xfs_qm_dqrele(pdqp); xfs_qm_dqrele(pdqp);
*ipp = ip; *ipp = du.ip;
xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(du.ip, XFS_ILOCK_EXCL);
xfs_iunlock(dp, XFS_ILOCK_EXCL); xfs_iunlock(dp, XFS_ILOCK_EXCL);
xfs_parent_finish(mp, ppargs); xfs_parent_finish(mp, du.ppargs);
return 0; return 0;
out_trans_cancel: out_trans_cancel:
...@@ -862,13 +841,13 @@ xfs_create( ...@@ -862,13 +841,13 @@ xfs_create(
* setup of the inode and release the inode. This prevents recursive * setup of the inode and release the inode. This prevents recursive
* transactions and deadlocks from xfs_inactive. * transactions and deadlocks from xfs_inactive.
*/ */
if (ip) { if (du.ip) {
xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(du.ip, XFS_ILOCK_EXCL);
xfs_finish_inode_setup(ip); xfs_finish_inode_setup(du.ip);
xfs_irele(ip); xfs_irele(du.ip);
} }
out_parent: out_parent:
xfs_parent_finish(mp, ppargs); xfs_parent_finish(mp, du.ppargs);
out_release_dquots: out_release_dquots:
xfs_qm_dqrele(udqp); xfs_qm_dqrele(udqp);
xfs_qm_dqrele(gdqp); xfs_qm_dqrele(gdqp);
......
...@@ -95,8 +95,11 @@ xfs_symlink( ...@@ -95,8 +95,11 @@ xfs_symlink(
.pip = dp, .pip = dp,
.mode = S_IFLNK | (mode & ~S_IFMT), .mode = S_IFLNK | (mode & ~S_IFMT),
}; };
struct xfs_dir_update du = {
.dp = dp,
.name = link_name,
};
struct xfs_trans *tp = NULL; struct xfs_trans *tp = NULL;
struct xfs_inode *ip = NULL;
int error = 0; int error = 0;
int pathlen; int pathlen;
bool unlock_dp_on_error = false; bool unlock_dp_on_error = false;
...@@ -106,7 +109,6 @@ xfs_symlink( ...@@ -106,7 +109,6 @@ xfs_symlink(
struct xfs_dquot *pdqp; struct xfs_dquot *pdqp;
uint resblks; uint resblks;
xfs_ino_t ino; xfs_ino_t ino;
struct xfs_parent_args *ppargs;
*ipp = NULL; *ipp = NULL;
...@@ -140,7 +142,7 @@ xfs_symlink( ...@@ -140,7 +142,7 @@ xfs_symlink(
fs_blocks = xfs_symlink_blocks(mp, pathlen); fs_blocks = xfs_symlink_blocks(mp, pathlen);
resblks = xfs_symlink_space_res(mp, link_name->len, fs_blocks); resblks = xfs_symlink_space_res(mp, link_name->len, fs_blocks);
error = xfs_parent_start(mp, &ppargs); error = xfs_parent_start(mp, &du.ppargs);
if (error) if (error)
goto out_release_dquots; goto out_release_dquots;
...@@ -165,7 +167,7 @@ xfs_symlink( ...@@ -165,7 +167,7 @@ xfs_symlink(
*/ */
error = xfs_dialloc(&tp, dp->i_ino, S_IFLNK, &ino); error = xfs_dialloc(&tp, dp->i_ino, S_IFLNK, &ino);
if (!error) if (!error)
error = xfs_icreate(tp, ino, &args, &ip); error = xfs_icreate(tp, ino, &args, &du.ip);
if (error) if (error)
goto out_trans_cancel; goto out_trans_cancel;
...@@ -181,33 +183,24 @@ xfs_symlink( ...@@ -181,33 +183,24 @@ xfs_symlink(
/* /*
* Also attach the dquot(s) to it, if applicable. * Also attach the dquot(s) to it, if applicable.
*/ */
xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp); xfs_qm_vop_create_dqattach(tp, du.ip, udqp, gdqp, pdqp);
resblks -= XFS_IALLOC_SPACE_RES(mp); resblks -= XFS_IALLOC_SPACE_RES(mp);
error = xfs_symlink_write_target(tp, ip, ip->i_ino, target_path, error = xfs_symlink_write_target(tp, du.ip, du.ip->i_ino, target_path,
pathlen, fs_blocks, resblks); pathlen, fs_blocks, resblks);
if (error) if (error)
goto out_trans_cancel; goto out_trans_cancel;
resblks -= fs_blocks; resblks -= fs_blocks;
i_size_write(VFS_I(ip), ip->i_disk_size); i_size_write(VFS_I(du.ip), du.ip->i_disk_size);
/* /*
* Create the directory entry for the symlink. * Create the directory entry for the symlink.
*/ */
error = xfs_dir_createname(tp, dp, link_name, ip->i_ino, resblks); error = xfs_dir_create_child(tp, resblks, &du);
if (error) if (error)
goto out_trans_cancel; goto out_trans_cancel;
xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
/* Add parent pointer for the new symlink. */ xfs_dir_update_hook(dp, du.ip, 1, link_name);
if (ppargs) {
error = xfs_parent_addname(tp, ppargs, dp, link_name, ip);
if (error)
goto out_trans_cancel;
}
xfs_dir_update_hook(dp, ip, 1, link_name);
/* /*
* If this is a synchronous mount, make sure that the * If this is a synchronous mount, make sure that the
...@@ -225,10 +218,10 @@ xfs_symlink( ...@@ -225,10 +218,10 @@ xfs_symlink(
xfs_qm_dqrele(gdqp); xfs_qm_dqrele(gdqp);
xfs_qm_dqrele(pdqp); xfs_qm_dqrele(pdqp);
*ipp = ip; *ipp = du.ip;
xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(du.ip, XFS_ILOCK_EXCL);
xfs_iunlock(dp, XFS_ILOCK_EXCL); xfs_iunlock(dp, XFS_ILOCK_EXCL);
xfs_parent_finish(mp, ppargs); xfs_parent_finish(mp, du.ppargs);
return 0; return 0;
out_trans_cancel: out_trans_cancel:
...@@ -239,13 +232,13 @@ xfs_symlink( ...@@ -239,13 +232,13 @@ xfs_symlink(
* setup of the inode and release the inode. This prevents recursive * setup of the inode and release the inode. This prevents recursive
* transactions and deadlocks from xfs_inactive. * transactions and deadlocks from xfs_inactive.
*/ */
if (ip) { if (du.ip) {
xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(du.ip, XFS_ILOCK_EXCL);
xfs_finish_inode_setup(ip); xfs_finish_inode_setup(du.ip);
xfs_irele(ip); xfs_irele(du.ip);
} }
out_parent: out_parent:
xfs_parent_finish(mp, ppargs); xfs_parent_finish(mp, du.ppargs);
out_release_dquots: out_release_dquots:
xfs_qm_dqrele(udqp); xfs_qm_dqrele(udqp);
xfs_qm_dqrele(gdqp); xfs_qm_dqrele(gdqp);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment