@@ -22,6 +22,9 @@
#include "xfs_errortag.h"
#include "xfs_error.h"
#include "xfs_trace.h"
+#include "xfs_shared.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_trans_space.h"
struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2, XFS_DIR3_FT_DIR };
@@ -703,3 +706,45 @@ xfs_dir2_shrink_inode(
xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
return 0;
}
+
+/*
+ * 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_new_child(
+ struct xfs_trans *tp,
+ uint resblks,
+ struct xfs_inode *dp,
+ struct xfs_name *name,
+ struct xfs_inode *ip)
+{
+ struct xfs_mount *mp = tp->t_mountp;
+ int error;
+
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
+ ASSERT(xfs_isilocked(dp, XFS_ILOCK_EXCL));
+ ASSERT(resblks == 0 || resblks > XFS_IALLOC_SPACE_RES(mp));
+
+ error = xfs_dir_createname(tp, dp, name, ip->i_ino,
+ resblks ?
+ resblks - XFS_IALLOC_SPACE_RES(mp) : 0);
+ 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))
+ return 0;
+
+ error = xfs_dir_init(tp, ip, dp);
+ if (error)
+ return error;
+
+ return xfs_bumplink(tp, dp);
+}
@@ -327,4 +327,8 @@ unsigned char xfs_dir3_get_dtype(struct xfs_mount *mp, uint8_t filetype);
void *xfs_dir3_data_endp(struct xfs_da_geometry *geo,
struct xfs_dir2_data_hdr *hdr);
+int xfs_dir_create_new_child(struct xfs_trans *tp, uint resblks,
+ struct xfs_inode *dp, struct xfs_name *name,
+ struct xfs_inode *ip);
+
#endif /* __XFS_DIR2_H__ */
@@ -778,25 +778,9 @@ xfs_create(
xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
unlock_dp_on_error = false;
- error = xfs_dir_createname(tp, dp, name, ip->i_ino,
- resblks ?
- resblks - XFS_IALLOC_SPACE_RES(mp) : 0);
- if (error) {
- ASSERT(error != -ENOSPC);
+ error = xfs_dir_create_new_child(tp, resblks, dp, name, ip);
+ if (error)
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)
- goto out_trans_cancel;
-
- error = xfs_bumplink(tp, dp);
- if (error)
- goto out_trans_cancel;
- }
/*
* If this is a synchronous mount, make sure that the