- return error;
- }
-
- /* Return through std_return after this point. */
-
- error = XFS_QM_DQATTACH(mp, sip, 0);
- if (!error && sip != tdp)
- error = XFS_QM_DQATTACH(mp, tdp, 0);
- if (error)
- goto std_return;
-
- tp = xfs_trans_alloc(mp, XFS_TRANS_LINK);
- cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
- resblks = XFS_LINK_SPACE_RES(mp, target_namelen);
- error = xfs_trans_reserve(tp, resblks, XFS_LINK_LOG_RES(mp), 0,
- XFS_TRANS_PERM_LOG_RES, XFS_LINK_LOG_COUNT);
- if (error == ENOSPC) {
- resblks = 0;
- error = xfs_trans_reserve(tp, 0, XFS_LINK_LOG_RES(mp), 0,
- XFS_TRANS_PERM_LOG_RES, XFS_LINK_LOG_COUNT);
- }
- if (error) {
- cancel_flags = 0;
- goto error_return;
- }
-
- if (sip->i_ino < tdp->i_ino) {
- ips[0] = sip;
- ips[1] = tdp;
- } else {
- ips[0] = tdp;
- ips[1] = sip;
- }
-
- xfs_lock_inodes(ips, 2, 0, XFS_ILOCK_EXCL);
-
- /*
- * Increment vnode ref counts since xfs_trans_commit &
- * xfs_trans_cancel will both unlock the inodes and
- * decrement the associated ref counts.
- */
- VN_HOLD(src_vp);
- VN_HOLD(target_dir_vp);
- xfs_trans_ijoin(tp, sip, XFS_ILOCK_EXCL);
- xfs_trans_ijoin(tp, tdp, XFS_ILOCK_EXCL);
-
- /*
- * If the source has too many links, we can't make any more to it.
- */
- if (sip->i_d.di_nlink >= XFS_MAXLINK) {
- error = XFS_ERROR(EMLINK);
- goto error_return;
- }
-
- /*
- * If we are using project inheritance, we only allow hard link
- * creation in our tree when the project IDs are the same; else
- * the tree quota mechanism could be circumvented.
- */
- if (unlikely((tdp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
- (tdp->i_d.di_projid != sip->i_d.di_projid))) {
- error = XFS_ERROR(EXDEV);
- goto error_return;
- }
-
- if (resblks == 0 &&
- (error = xfs_dir_canenter(tp, tdp, target_name, target_namelen)))
- goto error_return;
-
- XFS_BMAP_INIT(&free_list, &first_block);
-
- error = xfs_dir_createname(tp, tdp, target_name, target_namelen,
- sip->i_ino, &first_block, &free_list,
- resblks);
- if (error)
- goto abort_return;
- xfs_ichgtime(tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
- tdp->i_gen++;
- xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE);
-
- error = xfs_bumplink(tp, sip);
- if (error)
- goto abort_return;
-
- /*
- * If this is a synchronous mount, make sure that the
- * link transaction goes to disk before returning to
- * the user.
- */
- if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
- xfs_trans_set_sync(tp);
- }
-
- error = xfs_bmap_finish (&tp, &free_list, &committed);
- if (error) {
- xfs_bmap_cancel(&free_list);
- goto abort_return;
- }
-
- error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
- if (error)
- goto std_return;
-
- /* Fall through to std_return with error = 0. */
-std_return:
- if (DM_EVENT_ENABLED(sip, DM_EVENT_POSTLINK)) {
- (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTLINK,
- target_dir_vp, DM_RIGHT_NULL,
- src_vp, DM_RIGHT_NULL,
- target_name, NULL, 0, error, 0);
- }
- return error;
-
- abort_return:
- cancel_flags |= XFS_TRANS_ABORT;
- /* FALLTHROUGH */
-
- error_return:
- xfs_trans_cancel(tp, cancel_flags);
- goto std_return;
-}
-
-
-int
-xfs_mkdir(
- xfs_inode_t *dp,
- bhv_vname_t *dentry,
- mode_t mode,
- bhv_vnode_t **vpp,
- cred_t *credp)
-{
- bhv_vnode_t *dir_vp = XFS_ITOV(dp);
- char *dir_name = VNAME(dentry);
- int dir_namelen = VNAMELEN(dentry);
- xfs_mount_t *mp = dp->i_mount;
- xfs_inode_t *cdp; /* inode of created dir */
- bhv_vnode_t *cvp; /* vnode of created dir */
- xfs_trans_t *tp;
- int cancel_flags;
- int error;
- int committed;
- xfs_bmap_free_t free_list;
- xfs_fsblock_t first_block;
- boolean_t unlock_dp_on_error = B_FALSE;
- boolean_t created = B_FALSE;
- int dm_event_sent = 0;
- xfs_prid_t prid;
- struct xfs_dquot *udqp, *gdqp;
- uint resblks;
-
- if (XFS_FORCED_SHUTDOWN(mp))
- return XFS_ERROR(EIO);
-
- tp = NULL;