diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c --- a/sys/ufs/ffs/ffs_alloc.c +++ b/sys/ufs/ffs/ffs_alloc.c @@ -3330,7 +3330,7 @@ break; ip = VTOI(vp); ip->i_nlink += cmd.size; - DIP_SET(ip, i_nlink, ip->i_nlink); + DIP_SET_NLINK(ip, ip->i_nlink); ip->i_effnlink += cmd.size; UFS_INODE_SET_FLAG(ip, IN_CHANGE | IN_MODIFIED); error = ffs_update(vp, 1); diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -10046,7 +10046,7 @@ KASSERT(ip->i_nlink >= 0, ("handle_workitem_remove: file ino " "%ju negative i_nlink %d", (intmax_t)ip->i_number, ip->i_nlink)); - DIP_SET(ip, i_nlink, ip->i_nlink); + DIP_SET_NLINK(ip, ip->i_nlink); UFS_INODE_SET_FLAG(ip, IN_CHANGE); if (ip->i_nlink < ip->i_effnlink) panic("handle_workitem_remove: bad file delta"); @@ -10069,7 +10069,7 @@ ip->i_nlink -= 2; KASSERT(ip->i_nlink >= 0, ("handle_workitem_remove: directory ino " "%ju negative i_nlink %d", (intmax_t)ip->i_number, ip->i_nlink)); - DIP_SET(ip, i_nlink, ip->i_nlink); + DIP_SET_NLINK(ip, ip->i_nlink); UFS_INODE_SET_FLAG(ip, IN_CHANGE); if (ip->i_nlink < ip->i_effnlink) panic("handle_workitem_remove: bad dir delta"); diff --git a/sys/ufs/ufs/dinode.h b/sys/ufs/ufs/dinode.h --- a/sys/ufs/ufs/dinode.h +++ b/sys/ufs/ufs/dinode.h @@ -123,7 +123,7 @@ struct ufs2_dinode { uint16_t di_mode; /* 0: IFMT, permissions; see below. */ - int16_t di_nlink; /* 2: File link count. */ + uint16_t di_nlink; /* 2: File link count. */ uint32_t di_uid; /* 4: File owner. */ uint32_t di_gid; /* 8: File group. */ uint32_t di_blksize; /* 12: Inode blocksize. */ @@ -178,7 +178,7 @@ */ struct ufs1_dinode { uint16_t di_mode; /* 0: IFMT, permissions; see below. */ - int16_t di_nlink; /* 2: File link count. */ + uint16_t di_nlink; /* 2: File link count. */ union { uint32_t di_freelink; /* 4: SUJ: Next unlinked inode. */ uint32_t di_dirdepth; /* 4: IFDIR: depth from root dir */ @@ -208,6 +208,6 @@ uint64_t di_modrev; /* 120: i_modrev for NFSv4 */ }; -#define UFS_LINK_MAX 32767 +#define UFS_LINK_MAX 65500 /* leave a few spare for special values */ #endif /* _UFS_UFS_DINODE_H_ */ diff --git a/sys/ufs/ufs/inode.h b/sys/ufs/ufs/inode.h --- a/sys/ufs/ufs/inode.h +++ b/sys/ufs/ufs/inode.h @@ -95,7 +95,7 @@ ino_t i_number; /* The identity of the inode. */ uint32_t i_flag; /* flags, see below */ - int i_effnlink; /* i_nlink when I/O completes */ + int32_t i_effnlink; /* i_nlink when I/O completes */ /* * Side effects; used during directory lookup. @@ -131,7 +131,7 @@ uint32_t i_flags; /* Status flags (chflags). */ uint32_t i_uid; /* File owner. */ uint32_t i_gid; /* File group. */ - int16_t i_nlink; /* File link count. */ + int32_t i_nlink; /* File link count. */ uint16_t i_mode; /* IFMT, permissions; see below. */ }; /* @@ -242,6 +242,12 @@ else \ (ip)->i_din2->d##field = (val); \ } while (0) +#define DIP_SET_NLINK(ip, val) do { \ + KASSERT(ip->i_nlink >= 0, ("%s:%d %s(): setting negative " \ + "nlink value %d for inode %jd\n", __FILE__, __LINE__, \ + __FUNCTION__, (ip)->i_nlink, (ip)->i_number)); \ + DIP_SET(ip, i_nlink, val); \ + } while (0) #define IS_SNAPSHOT(ip) ((ip)->i_flags & SF_SNAPSHOT) #define IS_UFS(vp) ((vp)->v_data != NULL) diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c --- a/sys/ufs/ufs/ufs_lookup.c +++ b/sys/ufs/ufs/ufs_lookup.c @@ -1121,7 +1121,7 @@ softdep_setup_unlink(dp, ip); } else { ip->i_nlink--; - DIP_SET(ip, i_nlink, ip->i_nlink); + DIP_SET_NLINK(ip, ip->i_nlink); UFS_INODE_SET_FLAG(ip, IN_CHANGE); } } @@ -1137,7 +1137,7 @@ softdep_change_linkcnt(ip); } else { ip->i_nlink++; - DIP_SET(ip, i_nlink, ip->i_nlink); + DIP_SET_NLINK(ip, ip->i_nlink); UFS_INODE_SET_FLAG(ip, IN_CHANGE); } } @@ -1241,7 +1241,7 @@ softdep_setup_unlink(dp, oip); } else { oip->i_nlink--; - DIP_SET(oip, i_nlink, oip->i_nlink); + DIP_SET_NLINK(oip, oip->i_nlink); UFS_INODE_SET_FLAG(oip, IN_CHANGE); } @@ -1258,7 +1258,7 @@ softdep_change_linkcnt(oip); } else { oip->i_nlink++; - DIP_SET(oip, i_nlink, oip->i_nlink); + DIP_SET_NLINK(oip, oip->i_nlink); UFS_INODE_SET_FLAG(oip, IN_CHANGE); } return (error); diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c --- a/sys/ufs/ufs/ufs_vnops.c +++ b/sys/ufs/ufs/ufs_vnops.c @@ -1131,7 +1131,7 @@ ip->i_effnlink++; ip->i_nlink++; - DIP_SET(ip, i_nlink, ip->i_nlink); + DIP_SET_NLINK(ip, ip->i_nlink); UFS_INODE_SET_FLAG(ip, IN_CHANGE); if (DOINGSOFTDEP(vp)) softdep_setup_link(VTOI(tdvp), ip); @@ -1144,7 +1144,7 @@ if (error) { ip->i_effnlink--; ip->i_nlink--; - DIP_SET(ip, i_nlink, ip->i_nlink); + DIP_SET_NLINK(ip, ip->i_nlink); UFS_INODE_SET_FLAG(ip, IN_CHANGE); if (DOINGSOFTDEP(vp)) softdep_revert_link(VTOI(tdvp), ip); @@ -1526,7 +1526,7 @@ */ fip->i_effnlink++; fip->i_nlink++; - DIP_SET(fip, i_nlink, fip->i_nlink); + DIP_SET_NLINK(fip, fip->i_nlink); UFS_INODE_SET_FLAG(fip, IN_CHANGE); if (DOINGSOFTDEP(fvp)) softdep_setup_link(tdp, fip); @@ -1555,7 +1555,7 @@ if (tdp->i_nlink >= UFS_LINK_MAX) { fip->i_effnlink--; fip->i_nlink--; - DIP_SET(fip, i_nlink, fip->i_nlink); + DIP_SET_NLINK(fip, fip->i_nlink); UFS_INODE_SET_FLAG(fip, IN_CHANGE); if (DOINGSOFTDEP(fvp)) softdep_revert_link(tdp, fip); @@ -1678,11 +1678,11 @@ */ if (!newparent) { tdp->i_nlink--; - DIP_SET(tdp, i_nlink, tdp->i_nlink); + DIP_SET_NLINK(tdp, tdp->i_nlink); UFS_INODE_SET_FLAG(tdp, IN_CHANGE); } tip->i_nlink--; - DIP_SET(tip, i_nlink, tip->i_nlink); + DIP_SET_NLINK(tip, tip->i_nlink); UFS_INODE_SET_FLAG(tip, IN_CHANGE); } } @@ -1717,7 +1717,7 @@ if (tip == NULL) { tdp->i_effnlink++; tdp->i_nlink++; - DIP_SET(tdp, i_nlink, tdp->i_nlink); + DIP_SET_NLINK(tdp, tdp->i_nlink); UFS_INODE_SET_FLAG(tdp, IN_CHANGE); if (DOINGSOFTDEP(tdvp)) softdep_setup_dotdot_link(tdp, fip); @@ -1780,7 +1780,7 @@ bad: fip->i_effnlink--; fip->i_nlink--; - DIP_SET(fip, i_nlink, fip->i_nlink); + DIP_SET_NLINK(fip, fip->i_nlink); UFS_INODE_SET_FLAG(fip, IN_CHANGE); if (DOINGSOFTDEP(fvp)) softdep_revert_link(tdp, fip); @@ -2120,7 +2120,7 @@ tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */ ip->i_effnlink = 2; ip->i_nlink = 2; - DIP_SET(ip, i_nlink, 2); + DIP_SET_NLINK(ip, 2); DIP_SET(ip, i_dirdepth, DIP(dp,i_dirdepth) + 1); if (cnp->cn_flags & ISWHITEOUT) { @@ -2135,7 +2135,7 @@ */ dp->i_effnlink++; dp->i_nlink++; - DIP_SET(dp, i_nlink, dp->i_nlink); + DIP_SET_NLINK(dp, dp->i_nlink); UFS_INODE_SET_FLAG(dp, IN_CHANGE); if (DOINGSOFTDEP(dvp)) softdep_setup_mkdir(dp, ip); @@ -2226,7 +2226,7 @@ } else { dp->i_effnlink--; dp->i_nlink--; - DIP_SET(dp, i_nlink, dp->i_nlink); + DIP_SET_NLINK(dp, dp->i_nlink); UFS_INODE_SET_FLAG(dp, IN_CHANGE); /* * No need to do an explicit VOP_TRUNCATE here, vrele will @@ -2234,7 +2234,7 @@ */ ip->i_effnlink = 0; ip->i_nlink = 0; - DIP_SET(ip, i_nlink, 0); + DIP_SET_NLINK(ip, 0); UFS_INODE_SET_FLAG(ip, IN_CHANGE); if (DOINGSOFTDEP(tvp)) softdep_revert_mkdir(dp, ip); @@ -2331,11 +2331,11 @@ */ if (!DOINGSOFTDEP(vp)) { dp->i_nlink--; - DIP_SET(dp, i_nlink, dp->i_nlink); + DIP_SET_NLINK(dp, dp->i_nlink); UFS_INODE_SET_FLAG(dp, IN_CHANGE); error = UFS_UPDATE(dvp, 0); ip->i_nlink--; - DIP_SET(ip, i_nlink, ip->i_nlink); + DIP_SET_NLINK(ip, ip->i_nlink); UFS_INODE_SET_FLAG(ip, IN_CHANGE); } cache_vop_rmdir(dvp, vp); @@ -2872,7 +2872,7 @@ tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */ ip->i_effnlink = 1; ip->i_nlink = 1; - DIP_SET(ip, i_nlink, 1); + DIP_SET_NLINK(ip, 1); if (DOINGSOFTDEP(tvp)) softdep_setup_create(VTOI(dvp), ip); if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) && @@ -2928,7 +2928,7 @@ */ ip->i_effnlink = 0; ip->i_nlink = 0; - DIP_SET(ip, i_nlink, 0); + DIP_SET_NLINK(ip, 0); UFS_INODE_SET_FLAG(ip, IN_CHANGE); if (DOINGSOFTDEP(tvp)) softdep_revert_create(VTOI(dvp), ip);