When a read error occurs while fetching a directory block to delete

or rename an entry in it, properly reset the link count of the inode
associated with the entry that was to have been changed.

Tested by: Peter Holm
MFC after: 7 days
This commit is contained in:
Kirk McKusick 2020-01-11 03:18:47 +00:00
parent 7e4c9d4893
commit 27a6257130
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=356627

View file

@ -1169,6 +1169,7 @@ ufs_dirremove(dvp, ip, flags, isrmdir)
struct inode *dp;
struct direct *ep, *rep;
struct buf *bp;
off_t offset;
int error;
dp = VTOI(dvp);
@ -1187,22 +1188,32 @@ ufs_dirremove(dvp, ip, flags, isrmdir)
ip->i_flag |= IN_CHANGE;
}
}
if (flags & DOWHITEOUT)
offset = dp->i_offset;
else
offset = dp->i_offset - dp->i_count;
if ((error = UFS_BLKATOFF(dvp, offset, (char **)&ep, &bp)) != 0) {
if (ip) {
ip->i_effnlink++;
ip->i_flag |= IN_CHANGE;
if (DOINGSOFTDEP(dvp)) {
softdep_change_linkcnt(ip);
} else {
ip->i_nlink++;
DIP_SET(ip, i_nlink, ip->i_nlink);
ip->i_flag |= IN_CHANGE;
}
}
return (error);
}
if (flags & DOWHITEOUT) {
/*
* Whiteout entry: set d_ino to UFS_WINO.
*/
if ((error =
UFS_BLKATOFF(dvp, (off_t)dp->i_offset, (char **)&ep, &bp)) != 0)
return (error);
ep->d_ino = UFS_WINO;
ep->d_type = DT_WHT;
goto out;
}
if ((error = UFS_BLKATOFF(dvp,
(off_t)(dp->i_offset - dp->i_count), (char **)&ep, &bp)) != 0)
return (error);
/* Set 'rep' to the entry being removed. */
if (dp->i_count == 0)
rep = ep;
@ -1302,12 +1313,22 @@ ufs_dirrewrite(dp, oip, newinum, newtype, isrmdir)
}
error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp);
if (error)
return (error);
if (ep->d_namlen == 2 && ep->d_name[1] == '.' && ep->d_name[0] == '.' &&
ep->d_ino != oip->i_number) {
if (error == 0 && ep->d_namlen == 2 && ep->d_name[1] == '.' &&
ep->d_name[0] == '.' && ep->d_ino != oip->i_number) {
brelse(bp);
return (EIDRM);
error = EIDRM;
}
if (error) {
oip->i_effnlink++;
oip->i_flag |= IN_CHANGE;
if (DOINGSOFTDEP(vdp)) {
softdep_change_linkcnt(oip);
} else {
oip->i_nlink++;
DIP_SET(oip, i_nlink, oip->i_nlink);
oip->i_flag |= IN_CHANGE;
}
return (error);
}
ep->d_ino = newinum;
if (!OFSFMT(vdp))