Changeset View
Changeset View
Standalone View
Standalone View
sys/ufs/ufs/ufs_lookup.c
Show First 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | |||||
#include <ufs/ufs/quota.h> | #include <ufs/ufs/quota.h> | ||||
#include <ufs/ufs/inode.h> | #include <ufs/ufs/inode.h> | ||||
#include <ufs/ufs/dir.h> | #include <ufs/ufs/dir.h> | ||||
#ifdef UFS_DIRHASH | #ifdef UFS_DIRHASH | ||||
#include <ufs/ufs/dirhash.h> | #include <ufs/ufs/dirhash.h> | ||||
#endif | #endif | ||||
#include <ufs/ufs/ufsmount.h> | #include <ufs/ufs/ufsmount.h> | ||||
#include <ufs/ufs/ufs_extern.h> | #include <ufs/ufs/ufs_extern.h> | ||||
#include <ufs/ffs/ffs_extern.h> | |||||
#ifdef DIAGNOSTIC | #ifdef DIAGNOSTIC | ||||
static int dirchk = 1; | static int dirchk = 1; | ||||
#else | #else | ||||
static int dirchk = 0; | static int dirchk = 0; | ||||
#endif | #endif | ||||
SYSCTL_INT(_debug, OID_AUTO, dircheck, CTLFLAG_RW, &dirchk, 0, ""); | SYSCTL_INT(_debug, OID_AUTO, dircheck, CTLFLAG_RW, &dirchk, 0, ""); | ||||
▲ Show 20 Lines • Show All 422 Lines • ▼ Show 20 Lines | if ((nameiop == CREATE || nameiop == RENAME || | ||||
* entry should be put. If we didn't find a slot, | * entry should be put. If we didn't find a slot, | ||||
* then set dp->i_count to 0 indicating | * then set dp->i_count to 0 indicating | ||||
* that the new slot belongs at the end of the | * that the new slot belongs at the end of the | ||||
* directory. If we found a slot, then the new entry | * directory. If we found a slot, then the new entry | ||||
* can be put in the range from dp->i_offset to | * can be put in the range from dp->i_offset to | ||||
* dp->i_offset + dp->i_count. | * dp->i_offset + dp->i_count. | ||||
*/ | */ | ||||
if (slotstatus == NONE) { | if (slotstatus == NONE) { | ||||
dp->i_offset = roundup2(dp->i_size, DIRBLKSIZ); | SET_I_OFFSET(dp, roundup2(dp->i_size, DIRBLKSIZ)); | ||||
dp->i_count = 0; | SET_I_COUNT(dp, 0); | ||||
enduseful = dp->i_offset; | enduseful = I_OFFSET(dp); | ||||
} else if (nameiop == DELETE) { | } else if (nameiop == DELETE) { | ||||
dp->i_offset = slotoffset; | SET_I_OFFSET(dp, slotoffset); | ||||
if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0) | if ((I_OFFSET(dp) & (DIRBLKSIZ - 1)) == 0) | ||||
dp->i_count = 0; | SET_I_COUNT(dp, 0); | ||||
else | else | ||||
dp->i_count = dp->i_offset - prevoff; | SET_I_COUNT(dp, I_OFFSET(dp) - prevoff); | ||||
} else { | } else { | ||||
dp->i_offset = slotoffset; | SET_I_OFFSET(dp, slotoffset); | ||||
dp->i_count = slotsize; | SET_I_COUNT(dp, slotsize); | ||||
if (enduseful < slotoffset + slotsize) | if (enduseful < slotoffset + slotsize) | ||||
enduseful = slotoffset + slotsize; | enduseful = slotoffset + slotsize; | ||||
} | } | ||||
dp->i_endoff = roundup2(enduseful, DIRBLKSIZ); | SET_I_ENDOFF(dp, roundup2(enduseful, DIRBLKSIZ)); | ||||
/* | /* | ||||
* We return with the directory locked, so that | * We return with the directory locked, so that | ||||
* the parameters we set up above will still be | * the parameters we set up above will still be | ||||
* valid if we actually decide to do a direnter(). | * valid if we actually decide to do a direnter(). | ||||
* We return ni_vp == NULL to indicate that the entry | * We return ni_vp == NULL to indicate that the entry | ||||
* does not currently exist; we leave a pointer to | * does not currently exist; we leave a pointer to | ||||
* the (locked) directory inode in ndp->ni_dvp. | * the (locked) directory inode in ndp->ni_dvp. | ||||
* The pathname buffer is saved so that the name | * The pathname buffer is saved so that the name | ||||
Show All 39 Lines | found: | ||||
/* | /* | ||||
* If deleting, and at end of pathname, return | * If deleting, and at end of pathname, return | ||||
* parameters which can be used to remove file. | * parameters which can be used to remove file. | ||||
*/ | */ | ||||
if (nameiop == DELETE && (flags & ISLASTCN)) { | if (nameiop == DELETE && (flags & ISLASTCN)) { | ||||
if (flags & LOCKPARENT) | if (flags & LOCKPARENT) | ||||
ASSERT_VOP_ELOCKED(vdp, __FUNCTION__); | ASSERT_VOP_ELOCKED(vdp, __FUNCTION__); | ||||
if (VOP_ISLOCKED(vdp) == LK_EXCLUSIVE) { | |||||
/* | /* | ||||
* Return pointer to current entry in dp->i_offset, | * Return pointer to current entry in | ||||
* and distance past previous entry (if there | * dp->i_offset, and distance past previous | ||||
* is a previous entry in this block) in dp->i_count. | * entry (if there is a previous entry in this | ||||
* Save directory inode pointer in ndp->ni_dvp for dirremove(). | * block) in dp->i_count. | ||||
* | * | ||||
* Technically we shouldn't be setting these in the | * We shouldn't be setting these in the | ||||
* WANTPARENT case (first lookup in rename()), but any | * WANTPARENT case (first lookup in rename()), but any | ||||
* lookups that will result in directory changes will | * lookups that will result in directory changes will | ||||
* overwrite these. | * overwrite these. | ||||
*/ | */ | ||||
dp->i_offset = i_offset; | SET_I_OFFSET(dp, i_offset); | ||||
if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0) | if ((I_OFFSET(dp) & (DIRBLKSIZ - 1)) == 0) | ||||
dp->i_count = 0; | SET_I_COUNT(dp, 0); | ||||
else | else | ||||
dp->i_count = dp->i_offset - prevoff; | SET_I_COUNT(dp, I_OFFSET(dp) - prevoff); | ||||
} | |||||
if (dd_ino != NULL) | if (dd_ino != NULL) | ||||
return (0); | return (0); | ||||
/* | |||||
* Save directory inode pointer in ndp->ni_dvp for | |||||
* dirremove(). | |||||
*/ | |||||
if ((error = VFS_VGET(vdp->v_mount, ino, | if ((error = VFS_VGET(vdp->v_mount, ino, | ||||
LK_EXCLUSIVE, &tdp)) != 0) | LK_EXCLUSIVE, &tdp)) != 0) | ||||
return (error); | return (error); | ||||
error = ufs_delete_denied(vdp, tdp, cred, cnp->cn_thread); | error = ufs_delete_denied(vdp, tdp, cred, cnp->cn_thread); | ||||
if (error) { | if (error) { | ||||
vput(tdp); | vput(tdp); | ||||
return (error); | return (error); | ||||
} | } | ||||
Show All 20 Lines | if (nameiop == RENAME && (flags & ISLASTCN)) { | ||||
else | else | ||||
error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_thread); | error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_thread); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
/* | /* | ||||
* Careful about locking second inode. | * Careful about locking second inode. | ||||
* This can only occur if the target is ".". | * This can only occur if the target is ".". | ||||
*/ | */ | ||||
dp->i_offset = i_offset; | SET_I_OFFSET(dp, i_offset); | ||||
if (dp->i_number == ino) | if (dp->i_number == ino) | ||||
return (EISDIR); | return (EISDIR); | ||||
if (dd_ino != NULL) | if (dd_ino != NULL) | ||||
return (0); | return (0); | ||||
if ((error = VFS_VGET(vdp->v_mount, ino, | if ((error = VFS_VGET(vdp->v_mount, ino, | ||||
LK_EXCLUSIVE, &tdp)) != 0) | LK_EXCLUSIVE, &tdp)) != 0) | ||||
return (error); | return (error); | ||||
▲ Show 20 Lines • Show All 241 Lines • ▼ Show 20 Lines | ufs_direnter(dvp, tvp, dirp, cnp, newdirbp, isrename) | ||||
char *dirbuf; | char *dirbuf; | ||||
td = curthread; /* XXX */ | td = curthread; /* XXX */ | ||||
cr = td->td_ucred; | cr = td->td_ucred; | ||||
dp = VTOI(dvp); | dp = VTOI(dvp); | ||||
newentrysize = DIRSIZ(OFSFMT(dvp), dirp); | newentrysize = DIRSIZ(OFSFMT(dvp), dirp); | ||||
if (dp->i_count == 0) { | if (I_COUNT(dp) == 0) { | ||||
/* | /* | ||||
* If dp->i_count is 0, then namei could find no | * If dp->i_count is 0, then namei could find no | ||||
* space in the directory. Here, dp->i_offset will | * space in the directory. Here, dp->i_offset will | ||||
* be on a directory block boundary and we will write the | * be on a directory block boundary and we will write the | ||||
* new entry into a fresh block. | * new entry into a fresh block. | ||||
*/ | */ | ||||
if (dp->i_offset & (DIRBLKSIZ - 1)) | if (I_OFFSET(dp) & (DIRBLKSIZ - 1)) | ||||
panic("ufs_direnter: newblk"); | panic("ufs_direnter: newblk"); | ||||
flags = BA_CLRBUF; | flags = BA_CLRBUF; | ||||
if (!DOINGSOFTDEP(dvp) && !DOINGASYNC(dvp)) | if (!DOINGSOFTDEP(dvp) && !DOINGASYNC(dvp)) | ||||
flags |= IO_SYNC; | flags |= IO_SYNC; | ||||
#ifdef QUOTA | #ifdef QUOTA | ||||
if ((error = getinoquota(dp)) != 0) { | if ((error = getinoquota(dp)) != 0) { | ||||
if (DOINGSOFTDEP(dvp) && newdirbp != NULL) | if (DOINGSOFTDEP(dvp) && newdirbp != NULL) | ||||
bdwrite(newdirbp); | bdwrite(newdirbp); | ||||
return (error); | return (error); | ||||
} | } | ||||
#endif | #endif | ||||
old_isize = dp->i_size; | old_isize = dp->i_size; | ||||
vnode_pager_setsize(dvp, (u_long)dp->i_offset + DIRBLKSIZ); | vnode_pager_setsize(dvp, (u_long)I_OFFSET(dp) + DIRBLKSIZ); | ||||
if ((error = UFS_BALLOC(dvp, (off_t)dp->i_offset, DIRBLKSIZ, | if ((error = UFS_BALLOC(dvp, (off_t)I_OFFSET(dp), DIRBLKSIZ, | ||||
cr, flags, &bp)) != 0) { | cr, flags, &bp)) != 0) { | ||||
if (DOINGSOFTDEP(dvp) && newdirbp != NULL) | if (DOINGSOFTDEP(dvp) && newdirbp != NULL) | ||||
bdwrite(newdirbp); | bdwrite(newdirbp); | ||||
vnode_pager_setsize(dvp, (u_long)old_isize); | vnode_pager_setsize(dvp, (u_long)old_isize); | ||||
return (error); | return (error); | ||||
} | } | ||||
dp->i_size = dp->i_offset + DIRBLKSIZ; | dp->i_size = I_OFFSET(dp) + DIRBLKSIZ; | ||||
DIP_SET(dp, i_size, dp->i_size); | DIP_SET(dp, i_size, dp->i_size); | ||||
dp->i_endoff = dp->i_size; | SET_I_ENDOFF(dp, dp->i_size); | ||||
UFS_INODE_SET_FLAG(dp, IN_SIZEMOD | IN_CHANGE | IN_UPDATE); | UFS_INODE_SET_FLAG(dp, IN_SIZEMOD | IN_CHANGE | IN_UPDATE); | ||||
dirp->d_reclen = DIRBLKSIZ; | dirp->d_reclen = DIRBLKSIZ; | ||||
blkoff = dp->i_offset & | blkoff = I_OFFSET(dp) & | ||||
(VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_iosize - 1); | (VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_iosize - 1); | ||||
bcopy((caddr_t)dirp, (caddr_t)bp->b_data + blkoff,newentrysize); | bcopy((caddr_t)dirp, (caddr_t)bp->b_data + blkoff,newentrysize); | ||||
#ifdef UFS_DIRHASH | #ifdef UFS_DIRHASH | ||||
if (dp->i_dirhash != NULL) { | if (dp->i_dirhash != NULL) { | ||||
ufsdirhash_newblk(dp, dp->i_offset); | ufsdirhash_newblk(dp, I_OFFSET(dp)); | ||||
ufsdirhash_add(dp, dirp, dp->i_offset); | ufsdirhash_add(dp, dirp, I_OFFSET(dp)); | ||||
ufsdirhash_checkblock(dp, (char *)bp->b_data + blkoff, | ufsdirhash_checkblock(dp, (char *)bp->b_data + blkoff, | ||||
dp->i_offset); | I_OFFSET(dp)); | ||||
} | } | ||||
#endif | #endif | ||||
if (DOINGSOFTDEP(dvp)) { | if (DOINGSOFTDEP(dvp)) { | ||||
/* | /* | ||||
* Ensure that the entire newly allocated block is a | * Ensure that the entire newly allocated block is a | ||||
* valid directory so that future growth within the | * valid directory so that future growth within the | ||||
* block does not have to ensure that the block is | * block does not have to ensure that the block is | ||||
* written before the inode. | * written before the inode. | ||||
*/ | */ | ||||
blkoff += DIRBLKSIZ; | blkoff += DIRBLKSIZ; | ||||
while (blkoff < bp->b_bcount) { | while (blkoff < bp->b_bcount) { | ||||
((struct direct *) | ((struct direct *) | ||||
(bp->b_data + blkoff))->d_reclen = DIRBLKSIZ; | (bp->b_data + blkoff))->d_reclen = DIRBLKSIZ; | ||||
blkoff += DIRBLKSIZ; | blkoff += DIRBLKSIZ; | ||||
} | } | ||||
if (softdep_setup_directory_add(bp, dp, dp->i_offset, | if (softdep_setup_directory_add(bp, dp, I_OFFSET(dp), | ||||
dirp->d_ino, newdirbp, 1)) | dirp->d_ino, newdirbp, 1)) | ||||
UFS_INODE_SET_FLAG(dp, IN_NEEDSYNC); | UFS_INODE_SET_FLAG(dp, IN_NEEDSYNC); | ||||
if (newdirbp) | if (newdirbp) | ||||
bdwrite(newdirbp); | bdwrite(newdirbp); | ||||
bdwrite(bp); | bdwrite(bp); | ||||
if ((dp->i_flag & IN_NEEDSYNC) == 0) | if ((dp->i_flag & IN_NEEDSYNC) == 0) | ||||
return (UFS_UPDATE(dvp, 0)); | return (UFS_UPDATE(dvp, 0)); | ||||
/* | |||||
* We have just allocated a directory block in an | |||||
* indirect block. We must prevent holes in the | |||||
* directory created if directory entries are | |||||
* written out of order. To accomplish this we | |||||
* fsync when we extend a directory into indirects. | |||||
* During rename it's not safe to drop the tvp lock | |||||
* so sync must be delayed until it is. | |||||
* | |||||
* This synchronous step could be removed if fsck and | |||||
* the kernel were taught to fill in sparse | |||||
* directories rather than panic. | |||||
*/ | |||||
if (isrename) | |||||
return (0); | return (0); | ||||
if (tvp != NULL) | |||||
VOP_UNLOCK(tvp); | |||||
(void) VOP_FSYNC(dvp, MNT_WAIT, td); | |||||
if (tvp != NULL) | |||||
vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY); | |||||
return (error); | |||||
} | } | ||||
if (DOINGASYNC(dvp)) { | if (DOINGASYNC(dvp)) { | ||||
bdwrite(bp); | bdwrite(bp); | ||||
return (UFS_UPDATE(dvp, 0)); | return (UFS_UPDATE(dvp, 0)); | ||||
} | } | ||||
error = bwrite(bp); | error = bwrite(bp); | ||||
ret = UFS_UPDATE(dvp, 1); | ret = UFS_UPDATE(dvp, 1); | ||||
if (error == 0) | if (error == 0) | ||||
Show All 12 Lines | #endif | ||||
/* | /* | ||||
* Increase size of directory if entry eats into new space. | * Increase size of directory if entry eats into new space. | ||||
* This should never push the size past a new multiple of | * This should never push the size past a new multiple of | ||||
* DIRBLKSIZE. | * DIRBLKSIZE. | ||||
* | * | ||||
* N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN. | * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN. | ||||
*/ | */ | ||||
if (dp->i_offset + dp->i_count > dp->i_size) { | if (I_OFFSET(dp) + I_COUNT(dp) > dp->i_size) { | ||||
dp->i_size = dp->i_offset + dp->i_count; | dp->i_size = I_OFFSET(dp) + I_COUNT(dp); | ||||
DIP_SET(dp, i_size, dp->i_size); | DIP_SET(dp, i_size, dp->i_size); | ||||
UFS_INODE_SET_FLAG(dp, IN_SIZEMOD | IN_MODIFIED); | UFS_INODE_SET_FLAG(dp, IN_SIZEMOD | IN_MODIFIED); | ||||
} | } | ||||
/* | /* | ||||
* Get the block containing the space for the new directory entry. | * Get the block containing the space for the new directory entry. | ||||
*/ | */ | ||||
error = UFS_BLKATOFF(dvp, (off_t)dp->i_offset, &dirbuf, &bp); | error = UFS_BLKATOFF(dvp, (off_t)I_OFFSET(dp), &dirbuf, &bp); | ||||
if (error) { | if (error) { | ||||
if (DOINGSOFTDEP(dvp) && newdirbp != NULL) | if (DOINGSOFTDEP(dvp) && newdirbp != NULL) | ||||
bdwrite(newdirbp); | bdwrite(newdirbp); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Find space for the new entry. In the simple case, the entry at | * Find space for the new entry. In the simple case, the entry at | ||||
* offset base will have the space. If it does not, then namei | * offset base will have the space. If it does not, then namei | ||||
* arranged that compacting the region dp->i_offset to | * arranged that compacting the region dp->i_offset to | ||||
* dp->i_offset + dp->i_count would yield the space. | * dp->i_offset + dp->i_count would yield the space. | ||||
*/ | */ | ||||
ep = (struct direct *)dirbuf; | ep = (struct direct *)dirbuf; | ||||
dsize = ep->d_ino ? DIRSIZ(OFSFMT(dvp), ep) : 0; | dsize = ep->d_ino ? DIRSIZ(OFSFMT(dvp), ep) : 0; | ||||
spacefree = ep->d_reclen - dsize; | spacefree = ep->d_reclen - dsize; | ||||
for (loc = ep->d_reclen; loc < dp->i_count; ) { | for (loc = ep->d_reclen; loc < I_COUNT(dp); ) { | ||||
nep = (struct direct *)(dirbuf + loc); | nep = (struct direct *)(dirbuf + loc); | ||||
/* Trim the existing slot (NB: dsize may be zero). */ | /* Trim the existing slot (NB: dsize may be zero). */ | ||||
ep->d_reclen = dsize; | ep->d_reclen = dsize; | ||||
ep = (struct direct *)((char *)ep + dsize); | ep = (struct direct *)((char *)ep + dsize); | ||||
/* Read nep->d_reclen now as the bcopy() may clobber it. */ | /* Read nep->d_reclen now as the bcopy() may clobber it. */ | ||||
loc += nep->d_reclen; | loc += nep->d_reclen; | ||||
Show All 11 Lines | if (nep->d_ino == 0) { | ||||
dsize = 0; | dsize = 0; | ||||
continue; | continue; | ||||
} | } | ||||
dsize = DIRSIZ(OFSFMT(dvp), nep); | dsize = DIRSIZ(OFSFMT(dvp), nep); | ||||
spacefree += nep->d_reclen - dsize; | spacefree += nep->d_reclen - dsize; | ||||
#ifdef UFS_DIRHASH | #ifdef UFS_DIRHASH | ||||
if (dp->i_dirhash != NULL) | if (dp->i_dirhash != NULL) | ||||
ufsdirhash_move(dp, nep, | ufsdirhash_move(dp, nep, | ||||
dp->i_offset + ((char *)nep - dirbuf), | I_OFFSET(dp) + ((char *)nep - dirbuf), | ||||
dp->i_offset + ((char *)ep - dirbuf)); | I_OFFSET(dp) + ((char *)ep - dirbuf)); | ||||
#endif | #endif | ||||
if (DOINGSOFTDEP(dvp)) | if (DOINGSOFTDEP(dvp)) | ||||
softdep_change_directoryentry_offset(bp, dp, dirbuf, | softdep_change_directoryentry_offset(bp, dp, dirbuf, | ||||
(caddr_t)nep, (caddr_t)ep, dsize); | (caddr_t)nep, (caddr_t)ep, dsize); | ||||
else | else | ||||
bcopy((caddr_t)nep, (caddr_t)ep, dsize); | bcopy((caddr_t)nep, (caddr_t)ep, dsize); | ||||
} | } | ||||
/* | /* | ||||
Show All 24 Lines | if (spacefree < newentrysize) | ||||
panic("ufs_direnter: compact2"); | panic("ufs_direnter: compact2"); | ||||
dirp->d_reclen = spacefree; | dirp->d_reclen = spacefree; | ||||
ep->d_reclen = dsize; | ep->d_reclen = dsize; | ||||
ep = (struct direct *)((char *)ep + dsize); | ep = (struct direct *)((char *)ep + dsize); | ||||
} | } | ||||
#ifdef UFS_DIRHASH | #ifdef UFS_DIRHASH | ||||
if (dp->i_dirhash != NULL && (ep->d_ino == 0 || | if (dp->i_dirhash != NULL && (ep->d_ino == 0 || | ||||
dirp->d_reclen == spacefree)) | dirp->d_reclen == spacefree)) | ||||
ufsdirhash_add(dp, dirp, dp->i_offset + ((char *)ep - dirbuf)); | ufsdirhash_add(dp, dirp, I_OFFSET(dp) + ((char *)ep - dirbuf)); | ||||
#endif | #endif | ||||
bcopy((caddr_t)dirp, (caddr_t)ep, (u_int)newentrysize); | bcopy((caddr_t)dirp, (caddr_t)ep, (u_int)newentrysize); | ||||
#ifdef UFS_DIRHASH | #ifdef UFS_DIRHASH | ||||
if (dp->i_dirhash != NULL) | if (dp->i_dirhash != NULL) | ||||
ufsdirhash_checkblock(dp, dirbuf - | ufsdirhash_checkblock(dp, dirbuf - | ||||
(dp->i_offset & (DIRBLKSIZ - 1)), | (I_OFFSET(dp) & (DIRBLKSIZ - 1)), | ||||
rounddown2(dp->i_offset, DIRBLKSIZ)); | rounddown2(I_OFFSET(dp), DIRBLKSIZ)); | ||||
#endif | #endif | ||||
if (DOINGSOFTDEP(dvp)) { | if (DOINGSOFTDEP(dvp)) { | ||||
(void) softdep_setup_directory_add(bp, dp, | (void) softdep_setup_directory_add(bp, dp, | ||||
dp->i_offset + (caddr_t)ep - dirbuf, | I_OFFSET(dp) + (caddr_t)ep - dirbuf, | ||||
dirp->d_ino, newdirbp, 0); | dirp->d_ino, newdirbp, 0); | ||||
if (newdirbp != NULL) | if (newdirbp != NULL) | ||||
bdwrite(newdirbp); | bdwrite(newdirbp); | ||||
bdwrite(bp); | bdwrite(bp); | ||||
} else { | } else { | ||||
if (DOINGASYNC(dvp)) { | if (DOINGASYNC(dvp)) { | ||||
bdwrite(bp); | bdwrite(bp); | ||||
error = 0; | error = 0; | ||||
} else { | } else { | ||||
error = bwrite(bp); | error = bwrite(bp); | ||||
} | } | ||||
} | } | ||||
UFS_INODE_SET_FLAG(dp, IN_CHANGE | IN_UPDATE); | UFS_INODE_SET_FLAG(dp, IN_CHANGE | IN_UPDATE); | ||||
/* | /* | ||||
* If all went well, and the directory can be shortened, proceed | * If all went well, and the directory can be shortened, proceed | ||||
* with the truncation. Note that we have to unlock the inode for | * with the truncation. Note that we have to unlock the inode for | ||||
* the entry that we just entered, as the truncation may need to | * the entry that we just entered, as the truncation may need to | ||||
* lock other inodes which can lead to deadlock if we also hold a | * lock other inodes which can lead to deadlock if we also hold a | ||||
* lock on the newly entered node. | * lock on the newly entered node. | ||||
*/ | */ | ||||
if (isrename == 0 && error == 0 && | if (isrename == 0 && error == 0 && | ||||
dp->i_endoff && dp->i_endoff < dp->i_size) { | I_ENDOFF(dp) != 0 && I_ENDOFF(dp) < dp->i_size) { | ||||
if (tvp != NULL) | if (tvp != NULL) | ||||
VOP_UNLOCK(tvp); | VOP_UNLOCK(tvp); | ||||
error = UFS_TRUNCATE(dvp, (off_t)dp->i_endoff, | error = UFS_TRUNCATE(dvp, (off_t)I_ENDOFF(dp), | ||||
IO_NORMAL | (DOINGASYNC(dvp) ? 0 : IO_SYNC), cr); | IO_NORMAL | (DOINGASYNC(dvp) ? 0 : IO_SYNC), cr); | ||||
if (error != 0) | if (error != 0) | ||||
vn_printf(dvp, | vn_printf(dvp, | ||||
"ufs_direnter: failed to truncate, error %d\n", | "ufs_direnter: failed to truncate, error %d\n", | ||||
error); | error); | ||||
#ifdef UFS_DIRHASH | #ifdef UFS_DIRHASH | ||||
if (error == 0 && dp->i_dirhash != NULL) | if (error == 0 && dp->i_dirhash != NULL) | ||||
ufsdirhash_dirtrunc(dp, dp->i_endoff); | ufsdirhash_dirtrunc(dp, I_ENDOFF(dp)); | ||||
#endif | #endif | ||||
error = 0; | error = 0; | ||||
if (tvp != NULL) | if (tvp != NULL) | ||||
vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY); | vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY); | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
Show All 34 Lines | if (DOINGSOFTDEP(dvp)) { | ||||
softdep_setup_unlink(dp, ip); | softdep_setup_unlink(dp, ip); | ||||
} else { | } else { | ||||
ip->i_nlink--; | ip->i_nlink--; | ||||
DIP_SET(ip, i_nlink, ip->i_nlink); | DIP_SET(ip, i_nlink, ip->i_nlink); | ||||
UFS_INODE_SET_FLAG(ip, IN_CHANGE); | UFS_INODE_SET_FLAG(ip, IN_CHANGE); | ||||
} | } | ||||
} | } | ||||
if (flags & DOWHITEOUT) | if (flags & DOWHITEOUT) | ||||
offset = dp->i_offset; | offset = I_OFFSET(dp); | ||||
else | else | ||||
offset = dp->i_offset - dp->i_count; | offset = I_OFFSET(dp) - I_COUNT(dp); | ||||
if ((error = UFS_BLKATOFF(dvp, offset, (char **)&ep, &bp)) != 0) { | if ((error = UFS_BLKATOFF(dvp, offset, (char **)&ep, &bp)) != 0) { | ||||
if (ip) { | if (ip) { | ||||
ip->i_effnlink++; | ip->i_effnlink++; | ||||
UFS_INODE_SET_FLAG(ip, IN_CHANGE); | UFS_INODE_SET_FLAG(ip, IN_CHANGE); | ||||
if (DOINGSOFTDEP(dvp)) { | if (DOINGSOFTDEP(dvp)) { | ||||
softdep_change_linkcnt(ip); | softdep_change_linkcnt(ip); | ||||
} else { | } else { | ||||
ip->i_nlink++; | ip->i_nlink++; | ||||
DIP_SET(ip, i_nlink, ip->i_nlink); | DIP_SET(ip, i_nlink, ip->i_nlink); | ||||
UFS_INODE_SET_FLAG(ip, IN_CHANGE); | UFS_INODE_SET_FLAG(ip, IN_CHANGE); | ||||
} | } | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
if (flags & DOWHITEOUT) { | if (flags & DOWHITEOUT) { | ||||
/* | /* | ||||
* Whiteout entry: set d_ino to UFS_WINO. | * Whiteout entry: set d_ino to UFS_WINO. | ||||
*/ | */ | ||||
ep->d_ino = UFS_WINO; | ep->d_ino = UFS_WINO; | ||||
ep->d_type = DT_WHT; | ep->d_type = DT_WHT; | ||||
goto out; | goto out; | ||||
} | } | ||||
/* Set 'rep' to the entry being removed. */ | /* Set 'rep' to the entry being removed. */ | ||||
if (dp->i_count == 0) | if (I_COUNT(dp) == 0) | ||||
rep = ep; | rep = ep; | ||||
else | else | ||||
rep = (struct direct *)((char *)ep + ep->d_reclen); | rep = (struct direct *)((char *)ep + ep->d_reclen); | ||||
#ifdef UFS_DIRHASH | #ifdef UFS_DIRHASH | ||||
/* | /* | ||||
* Remove the dirhash entry. This is complicated by the fact | * Remove the dirhash entry. This is complicated by the fact | ||||
* that `ep' is the previous entry when dp->i_count != 0. | * that `ep' is the previous entry when dp->i_count != 0. | ||||
*/ | */ | ||||
if (dp->i_dirhash != NULL) | if (dp->i_dirhash != NULL) | ||||
ufsdirhash_remove(dp, rep, dp->i_offset); | ufsdirhash_remove(dp, rep, I_OFFSET(dp)); | ||||
#endif | #endif | ||||
if (ip && rep->d_ino != ip->i_number) | if (ip && rep->d_ino != ip->i_number) | ||||
panic("ufs_dirremove: ip %ju does not match dirent ino %ju\n", | panic("ufs_dirremove: ip %ju does not match dirent ino %ju\n", | ||||
(uintmax_t)ip->i_number, (uintmax_t)rep->d_ino); | (uintmax_t)ip->i_number, (uintmax_t)rep->d_ino); | ||||
/* | /* | ||||
* Zero out the file directory entry metadata to reduce disk | * Zero out the file directory entry metadata to reduce disk | ||||
* scavenging disclosure. | * scavenging disclosure. | ||||
*/ | */ | ||||
bzero(&rep->d_name[0], rep->d_namlen); | bzero(&rep->d_name[0], rep->d_namlen); | ||||
rep->d_namlen = 0; | rep->d_namlen = 0; | ||||
rep->d_type = 0; | rep->d_type = 0; | ||||
rep->d_ino = 0; | rep->d_ino = 0; | ||||
if (dp->i_count != 0) { | if (I_COUNT(dp) != 0) { | ||||
/* | /* | ||||
* Collapse new free space into previous entry. | * Collapse new free space into previous entry. | ||||
*/ | */ | ||||
ep->d_reclen += rep->d_reclen; | ep->d_reclen += rep->d_reclen; | ||||
rep->d_reclen = 0; | rep->d_reclen = 0; | ||||
} | } | ||||
#ifdef UFS_DIRHASH | #ifdef UFS_DIRHASH | ||||
if (dp->i_dirhash != NULL) | if (dp->i_dirhash != NULL) | ||||
ufsdirhash_checkblock(dp, (char *)ep - | ufsdirhash_checkblock(dp, (char *)ep - | ||||
((dp->i_offset - dp->i_count) & (DIRBLKSIZ - 1)), | ((I_OFFSET(dp) - I_COUNT(dp)) & (DIRBLKSIZ - 1)), | ||||
rounddown2(dp->i_offset, DIRBLKSIZ)); | rounddown2(I_OFFSET(dp), DIRBLKSIZ)); | ||||
#endif | #endif | ||||
out: | out: | ||||
error = 0; | error = 0; | ||||
if (DOINGSOFTDEP(dvp)) { | if (DOINGSOFTDEP(dvp)) { | ||||
if (ip) | if (ip) | ||||
softdep_setup_remove(bp, dp, ip, isrmdir); | softdep_setup_remove(bp, dp, ip, isrmdir); | ||||
if (softdep_slowdown(dvp)) | if (softdep_slowdown(dvp)) | ||||
error = bwrite(bp); | error = bwrite(bp); | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | ufs_dirrewrite(dp, oip, newinum, newtype, isrmdir) | ||||
if (DOINGSOFTDEP(vdp)) { | if (DOINGSOFTDEP(vdp)) { | ||||
softdep_setup_unlink(dp, oip); | softdep_setup_unlink(dp, oip); | ||||
} else { | } else { | ||||
oip->i_nlink--; | oip->i_nlink--; | ||||
DIP_SET(oip, i_nlink, oip->i_nlink); | DIP_SET(oip, i_nlink, oip->i_nlink); | ||||
UFS_INODE_SET_FLAG(oip, IN_CHANGE); | UFS_INODE_SET_FLAG(oip, IN_CHANGE); | ||||
} | } | ||||
error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp); | error = UFS_BLKATOFF(vdp, (off_t)I_OFFSET(dp), (char **)&ep, &bp); | ||||
if (error == 0 && ep->d_namlen == 2 && ep->d_name[1] == '.' && | if (error == 0 && ep->d_namlen == 2 && ep->d_name[1] == '.' && | ||||
ep->d_name[0] == '.' && ep->d_ino != oip->i_number) { | ep->d_name[0] == '.' && ep->d_ino != oip->i_number) { | ||||
brelse(bp); | brelse(bp); | ||||
error = EIDRM; | error = EIDRM; | ||||
} | } | ||||
if (error) { | if (error) { | ||||
oip->i_effnlink++; | oip->i_effnlink++; | ||||
UFS_INODE_SET_FLAG(oip, IN_CHANGE); | UFS_INODE_SET_FLAG(oip, IN_CHANGE); | ||||
▲ Show 20 Lines • Show All 192 Lines • ▼ Show 20 Lines | ufs_checkpath(ino_t source_ino, ino_t parent_ino, struct inode *target, struct ucred *cred, ino_t *wait_ino) | ||||
if (error == ENOTDIR) | if (error == ENOTDIR) | ||||
panic("checkpath: .. not a directory\n"); | panic("checkpath: .. not a directory\n"); | ||||
if (vp1 != NULL) | if (vp1 != NULL) | ||||
vput(vp1); | vput(vp1); | ||||
if (vp != tvp) | if (vp != tvp) | ||||
vput(vp); | vput(vp); | ||||
return (error); | return (error); | ||||
} | } | ||||
#ifdef DIAGNOSTIC | |||||
static void | |||||
ufs_assert_inode_offset_owner(struct inode *ip, struct iown_tracker *tr, | |||||
const char *name, const char *file, int line) | |||||
{ | |||||
char msg[128]; | |||||
snprintf(msg, sizeof(msg), "at %s@%d", file, line); | |||||
ASSERT_VOP_ELOCKED(ITOV(ip), msg); | |||||
MPASS((ip->i_mode & IFMT) == IFDIR); | |||||
if (curthread == tr->tr_owner && ip->i_lock_gen == tr->tr_gen) | |||||
return; | |||||
printf("locked at\n"); | |||||
stack_print(&tr->tr_st); | |||||
printf("unlocked at\n"); | |||||
stack_print(&tr->tr_unlock); | |||||
panic("%s ip %p %jd offset owner %p %d gen %d " | |||||
"curthread %p %d gen %d at %s@%d\n", | |||||
name, ip, (uintmax_t)ip->i_number, tr->tr_owner, | |||||
tr->tr_owner->td_tid, tr->tr_gen, | |||||
curthread, curthread->td_tid, ip->i_lock_gen, | |||||
file, line); | |||||
} | |||||
static void | |||||
ufs_set_inode_offset_owner(struct inode *ip, struct iown_tracker *tr, | |||||
const char *file, int line) | |||||
{ | |||||
char msg[128]; | |||||
snprintf(msg, sizeof(msg), "at %s@%d", file, line); | |||||
ASSERT_VOP_ELOCKED(ITOV(ip), msg); | |||||
MPASS((ip->i_mode & IFMT) == IFDIR); | |||||
tr->tr_owner = curthread; | |||||
tr->tr_gen = ip->i_lock_gen; | |||||
stack_save(&tr->tr_st); | |||||
} | |||||
static void | |||||
ufs_init_one_tracker(struct iown_tracker *tr) | |||||
{ | |||||
tr->tr_owner = NULL; | |||||
stack_zero(&tr->tr_st); | |||||
} | |||||
void | |||||
ufs_init_trackers(struct inode *ip) | |||||
{ | |||||
ufs_init_one_tracker(&ip->i_offset_tracker); | |||||
ufs_init_one_tracker(&ip->i_count_tracker); | |||||
ufs_init_one_tracker(&ip->i_endoff_tracker); | |||||
} | |||||
void | |||||
ufs_unlock_tracker(struct inode *ip) | |||||
{ | |||||
if (ip->i_count_tracker.tr_gen == ip->i_lock_gen) | |||||
stack_save(&ip->i_count_tracker.tr_unlock); | |||||
if (ip->i_offset_tracker.tr_gen == ip->i_lock_gen) | |||||
stack_save(&ip->i_offset_tracker.tr_unlock); | |||||
if (ip->i_endoff_tracker.tr_gen == ip->i_lock_gen) | |||||
stack_save(&ip->i_endoff_tracker.tr_unlock); | |||||
ip->i_lock_gen++; | |||||
} | |||||
doff_t | |||||
ufs_get_i_offset(struct inode *ip, const char *file, int line) | |||||
{ | |||||
ufs_assert_inode_offset_owner(ip, &ip->i_offset_tracker, "i_offset", | |||||
file, line); | |||||
return (ip->i_offset); | |||||
} | |||||
void | |||||
ufs_set_i_offset(struct inode *ip, doff_t off, const char *file, int line) | |||||
{ | |||||
ufs_set_inode_offset_owner(ip, &ip->i_offset_tracker, file, line); | |||||
ip->i_offset = off; | |||||
} | |||||
int32_t | |||||
ufs_get_i_count(struct inode *ip, const char *file, int line) | |||||
{ | |||||
ufs_assert_inode_offset_owner(ip, &ip->i_count_tracker, "i_count", | |||||
file, line); | |||||
return (ip->i_count); | |||||
} | |||||
void | |||||
ufs_set_i_count(struct inode *ip, int32_t cnt, const char *file, int line) | |||||
{ | |||||
ufs_set_inode_offset_owner(ip, &ip->i_count_tracker, file, line); | |||||
ip->i_count = cnt; | |||||
} | |||||
doff_t | |||||
ufs_get_i_endoff(struct inode *ip, const char *file, int line) | |||||
{ | |||||
ufs_assert_inode_offset_owner(ip, &ip->i_endoff_tracker, "i_endoff", | |||||
file, line); | |||||
return (ip->i_endoff); | |||||
} | |||||
void | |||||
ufs_set_i_endoff(struct inode *ip, doff_t off, const char *file, int line) | |||||
{ | |||||
ufs_set_inode_offset_owner(ip, &ip->i_endoff_tracker, file, line); | |||||
ip->i_endoff = off; | |||||
} | |||||
#endif |