- (tdp->i_d.di_projid != sip->i_d.di_projid))) {
- error = XFS_ERROR(EXDEV);
- goto error_return;
- }
-
- if (resblks == 0 &&
- (error = XFS_DIR_CANENTER(mp, tp, tdp, target_name,
- target_namelen)))
- goto error_return;
-
- XFS_BMAP_INIT(&free_list, &first_block);
-
- error = XFS_DIR_CREATENAME(mp, 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, first_block, &committed);
- if (error) {
- xfs_bmap_cancel(&free_list);
- goto abort_return;
- }
-
- error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
- if (error) {
- goto std_return;
- }
-
- /* Fall through to std_return with error = 0. */
-std_return:
- if (DM_EVENT_ENABLED(src_vp->v_vfsp, 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;
-}
-/*
- * xfs_mkdir
- *
- */
-STATIC int
-xfs_mkdir(
- bhv_desc_t *dir_bdp,
- vname_t *dentry,
- vattr_t *vap,
- bhv_vnode_t **vpp,
- cred_t *credp)
-{
- char *dir_name = VNAME(dentry);
- xfs_inode_t *dp;
- xfs_inode_t *cdp; /* inode of created dir */
- bhv_vnode_t *cvp; /* vnode of created dir */
- xfs_trans_t *tp;
- xfs_mount_t *mp;
- int cancel_flags;
- int error;
- int committed;
- xfs_bmap_free_t free_list;
- xfs_fsblock_t first_block;
- bhv_vnode_t *dir_vp;
- boolean_t dp_joined_to_trans;
- boolean_t created = B_FALSE;
- int dm_event_sent = 0;
- xfs_prid_t prid;
- struct xfs_dquot *udqp, *gdqp;
- uint resblks;
- int dm_di_mode;
- int dir_namelen;
-
- dir_vp = BHV_TO_VNODE(dir_bdp);
- dp = XFS_BHVTOI(dir_bdp);
- mp = dp->i_mount;
-
- if (XFS_FORCED_SHUTDOWN(mp))
- return XFS_ERROR(EIO);
-
- dir_namelen = VNAMELEN(dentry);
-
- tp = NULL;
- dp_joined_to_trans = B_FALSE;
- dm_di_mode = vap->va_mode;
-
- if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_CREATE)) {
- error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE,
- dir_vp, DM_RIGHT_NULL, NULL,
- DM_RIGHT_NULL, dir_name, NULL,
- dm_di_mode, 0, 0);
- if (error)
- return error;
- dm_event_sent = 1;
- }
-
- /* Return through std_return after this point. */
-
- vn_trace_entry(dir_vp, __FUNCTION__, (inst_t *)__return_address);
-
- mp = dp->i_mount;
- udqp = gdqp = NULL;
- if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
- prid = dp->i_d.di_projid;
- else if (vap->va_mask & XFS_AT_PROJID)
- prid = (xfs_prid_t)vap->va_projid;
- else
- prid = (xfs_prid_t)dfltprid;
-
- /*
- * Make sure that we have allocated dquot(s) on disk.
- */
- error = XFS_QM_DQVOPALLOC(mp, dp,
- current_fsuid(credp), current_fsgid(credp), prid,
- XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
- if (error)
- goto std_return;
-
- tp = xfs_trans_alloc(mp, XFS_TRANS_MKDIR);
- cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
- resblks = XFS_MKDIR_SPACE_RES(mp, dir_namelen);
- error = xfs_trans_reserve(tp, resblks, XFS_MKDIR_LOG_RES(mp), 0,
- XFS_TRANS_PERM_LOG_RES, XFS_MKDIR_LOG_COUNT);
- if (error == ENOSPC) {
- resblks = 0;
- error = xfs_trans_reserve(tp, 0, XFS_MKDIR_LOG_RES(mp), 0,
- XFS_TRANS_PERM_LOG_RES,
- XFS_MKDIR_LOG_COUNT);
- }
- if (error) {
- cancel_flags = 0;
- dp = NULL;
- goto error_return;
- }
-
- xfs_ilock(dp, XFS_ILOCK_EXCL);
-
- /*
- * Check for directory link count overflow.
- */
- if (dp->i_d.di_nlink >= XFS_MAXLINK) {
- error = XFS_ERROR(EMLINK);
- goto error_return;
- }
-
- /*
- * Reserve disk quota and the inode.
- */
- error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0);
- if (error)
- goto error_return;
-
- if (resblks == 0 &&
- (error = XFS_DIR_CANENTER(mp, tp, dp, dir_name, dir_namelen)))
- goto error_return;
- /*
- * create the directory inode.
- */
- error = xfs_dir_ialloc(&tp, dp, vap->va_mode, 2,
- 0, credp, prid, resblks > 0,
- &cdp, NULL);
- if (error) {
- if (error == ENOSPC)
- goto error_return;
- goto abort_return;
- }
- ITRACE(cdp);
-
- /*
- * Now we add the directory inode to the transaction.
- * We waited until now since xfs_dir_ialloc might start
- * a new transaction. Had we joined the transaction
- * earlier, the locks might have gotten released.
- */
- VN_HOLD(dir_vp);
- xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
- dp_joined_to_trans = B_TRUE;
-
- XFS_BMAP_INIT(&free_list, &first_block);
-
- error = XFS_DIR_CREATENAME(mp, tp, dp, dir_name, dir_namelen,
- cdp->i_ino, &first_block, &free_list,
- resblks ? resblks - XFS_IALLOC_SPACE_RES(mp) : 0);
- if (error) {
- ASSERT(error != ENOSPC);
- goto error1;
- }
- xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-
- /*
- * Bump the in memory version number of the parent directory
- * so that other processes accessing it will recognize that
- * the directory has changed.
- */
- dp->i_gen++;
-
- error = XFS_DIR_INIT(mp, tp, cdp, dp);
- if (error) {
- goto error2;
- }
-
- cdp->i_gen = 1;
- error = xfs_bumplink(tp, dp);
- if (error) {
- goto error2;
- }
-
- cvp = XFS_ITOV(cdp);
-
- created = B_TRUE;
-
- *vpp = cvp;
- IHOLD(cdp);
-
- /*
- * Attach the dquots to the new inode and modify the icount incore.
- */
- XFS_QM_DQVOPCREATE(mp, tp, cdp, udqp, gdqp);
-
- /*
- * If this is a synchronous mount, make sure that the
- * mkdir 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, first_block, &committed);
- if (error) {
- IRELE(cdp);
- goto error2;
- }
-
- error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
- XFS_QM_DQRELE(mp, udqp);
- XFS_QM_DQRELE(mp, gdqp);
- if (error) {
- IRELE(cdp);
- }
-
- /* Fall through to std_return with error = 0 or errno from
- * xfs_trans_commit. */
-
-std_return:
- if ( (created || (error != 0 && dm_event_sent != 0)) &&
- DM_EVENT_ENABLED(dir_vp->v_vfsp, XFS_BHVTOI(dir_bdp),
- DM_EVENT_POSTCREATE)) {
- (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTCREATE,
- dir_vp, DM_RIGHT_NULL,
- created ? XFS_ITOV(cdp):NULL,
- DM_RIGHT_NULL,
- dir_name, NULL,
- dm_di_mode, error, 0);
- }
- return error;
-
- error2:
- error1:
- xfs_bmap_cancel(&free_list);
- abort_return:
- cancel_flags |= XFS_TRANS_ABORT;
- error_return:
- xfs_trans_cancel(tp, cancel_flags);
- XFS_QM_DQRELE(mp, udqp);
- XFS_QM_DQRELE(mp, gdqp);
-
- if (!dp_joined_to_trans && (dp != NULL)) {
- xfs_iunlock(dp, XFS_ILOCK_EXCL);
- }
-
- goto std_return;
-}
-
-
-/*
- * xfs_rmdir
- *
- */
-STATIC int
-xfs_rmdir(
- bhv_desc_t *dir_bdp,
- vname_t *dentry,
- cred_t *credp)
-{
- char *name = VNAME(dentry);
- xfs_inode_t *dp;
- xfs_inode_t *cdp; /* child directory */
- xfs_trans_t *tp;
- xfs_mount_t *mp;
- int error;
- xfs_bmap_free_t free_list;
- xfs_fsblock_t first_block;
- int cancel_flags;
- int committed;
- bhv_vnode_t *dir_vp;
- int dm_di_mode = 0;
- int last_cdp_link;
- int namelen;
- uint resblks;
-
- dir_vp = BHV_TO_VNODE(dir_bdp);
- dp = XFS_BHVTOI(dir_bdp);
- mp = dp->i_mount;
-
- vn_trace_entry(dir_vp, __FUNCTION__, (inst_t *)__return_address);
-
- if (XFS_FORCED_SHUTDOWN(XFS_BHVTOI(dir_bdp)->i_mount))
- return XFS_ERROR(EIO);
- namelen = VNAMELEN(dentry);
-
- if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_REMOVE)) {
- error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE,
- dir_vp, DM_RIGHT_NULL,
- NULL, DM_RIGHT_NULL,
- name, NULL, 0, 0, 0);
- if (error)
- return XFS_ERROR(error);
- }
-
- /* Return through std_return after this point. */
-
- cdp = NULL;
-
- /*
- * We need to get a reference to cdp before we get our log
- * reservation. The reason for this is that we cannot call
- * xfs_iget for an inode for which we do not have a reference
- * once we've acquired a log reservation. This is because the
- * inode we are trying to get might be in xfs_inactive going
- * for a log reservation. Since we'll have to wait for the
- * inactive code to complete before returning from xfs_iget,
- * we need to make sure that we don't have log space reserved
- * when we call xfs_iget. Instead we get an unlocked reference
- * to the inode before getting our log reservation.
- */
- error = xfs_get_dir_entry(dentry, &cdp);
- if (error) {
- REMOVE_DEBUG_TRACE(__LINE__);
- goto std_return;
- }
- mp = dp->i_mount;
- dm_di_mode = cdp->i_d.di_mode;
-
- /*
- * Get the dquots for the inodes.
- */
- error = XFS_QM_DQATTACH(mp, dp, 0);
- if (!error && dp != cdp)
- error = XFS_QM_DQATTACH(mp, cdp, 0);
- if (error) {
- IRELE(cdp);
- REMOVE_DEBUG_TRACE(__LINE__);
- goto std_return;
- }
-
- tp = xfs_trans_alloc(mp, XFS_TRANS_RMDIR);
- cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
- /*
- * We try to get the real space reservation first,
- * allowing for directory btree deletion(s) implying
- * possible bmap insert(s). If we can't get the space
- * reservation then we use 0 instead, and avoid the bmap
- * btree insert(s) in the directory code by, if the bmap
- * insert tries to happen, instead trimming the LAST
- * block from the directory.
- */
- resblks = XFS_REMOVE_SPACE_RES(mp);
- error = xfs_trans_reserve(tp, resblks, XFS_REMOVE_LOG_RES(mp), 0,
- XFS_TRANS_PERM_LOG_RES, XFS_DEFAULT_LOG_COUNT);
- if (error == ENOSPC) {
- resblks = 0;
- error = xfs_trans_reserve(tp, 0, XFS_REMOVE_LOG_RES(mp), 0,
- XFS_TRANS_PERM_LOG_RES, XFS_DEFAULT_LOG_COUNT);
- }
- if (error) {
- ASSERT(error != ENOSPC);
- cancel_flags = 0;
- IRELE(cdp);
- goto error_return;
- }
- XFS_BMAP_INIT(&free_list, &first_block);
-
- /*
- * Now lock the child directory inode and the parent directory
- * inode in the proper order. This will take care of validating
- * that the directory entry for the child directory inode has
- * not changed while we were obtaining a log reservation.
- */
- error = xfs_lock_dir_and_entry(dp, dentry, cdp);
- if (error) {
- xfs_trans_cancel(tp, cancel_flags);
- IRELE(cdp);
- goto std_return;
- }
-
- xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
- if (dp != cdp) {
- /*
- * Only increment the parent directory vnode count if
- * we didn't bump it in looking up cdp. The only time
- * we don't bump it is when we're looking up ".".
- */
- VN_HOLD(dir_vp);
- }
-
- ITRACE(cdp);
- xfs_trans_ijoin(tp, cdp, XFS_ILOCK_EXCL);
-
- ASSERT(cdp->i_d.di_nlink >= 2);
- if (cdp->i_d.di_nlink != 2) {
- error = XFS_ERROR(ENOTEMPTY);
- goto error_return;
- }
- if (!XFS_DIR_ISEMPTY(mp, cdp)) {
- error = XFS_ERROR(ENOTEMPTY);
- goto error_return;
- }
-
- error = XFS_DIR_REMOVENAME(mp, tp, dp, name, namelen, cdp->i_ino,
- &first_block, &free_list, resblks);
- if (error) {
- goto error1;
- }
-
- xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-
- /*
- * Bump the in memory generation count on the parent
- * directory so that other can know that it has changed.
- */
- dp->i_gen++;
-
- /*
- * Drop the link from cdp's "..".
- */
- error = xfs_droplink(tp, dp);
- if (error) {
- goto error1;
- }
-
- /*
- * Drop the link from dp to cdp.
- */
- error = xfs_droplink(tp, cdp);
- if (error) {
- goto error1;
- }
-
- /*
- * Drop the "." link from cdp to self.
- */
- error = xfs_droplink(tp, cdp);
- if (error) {
- goto error1;