Index: sys/ufs/ffs/ffs_softdep.c =================================================================== --- sys/ufs/ffs/ffs_softdep.c (revision 251100) +++ sys/ufs/ffs/ffs_softdep.c (working copy) @@ -453,6 +453,14 @@ softdep_change_linkcnt(ip) panic("softdep_change_linkcnt called"); } +int +softdep_check_linkcnt(ip) + struct inode *ip; +{ + + panic("softdep_check_linkcnt called"); +} + void softdep_load_inodeblock(ip) struct inode *ip; @@ -1293,6 +1301,7 @@ static int stat_cleanup_blkrequests; /* static int stat_cleanup_inorequests; /* Number of inode cleanup requests */ static int stat_cleanup_retries; /* Number of cleanups that needed to flush */ static int stat_cleanup_failures; /* Number of cleanup requests that failed */ +static int stat_linkcnt_retries; /* Attempts to get i_nlink below LINK_MAX */ SYSCTL_INT(_debug_softdep, OID_AUTO, max_softdeps, CTLFLAG_RW, &max_softdeps, 0, ""); @@ -1350,6 +1359,8 @@ SYSCTL_INT(_debug_softdep, OID_AUTO, cle &stat_cleanup_failures, 0, ""); SYSCTL_INT(_debug_softdep, OID_AUTO, flushcache, CTLFLAG_RW, &softdep_flushcache, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, linkcnt_retries, CTLFLAG_RW, + &stat_linkcnt_retries, 0, ""); SYSCTL_DECL(_vfs_ffs); @@ -9158,6 +9169,35 @@ softdep_change_linkcnt(ip) FREE_LOCK(&lk); } +int +softdep_check_linkcnt(ip) + struct inode *ip; +{ + struct vnode *vp; + int error; + + vp = ITOV(ip); + ASSERT_VOP_LOCKED(vp, "softdep_check_linkcnt"); + + while (ip->i_nlink >= LINK_MAX) { + if (ip->i_effnlink >= LINK_MAX) + return (EMLINK); + + stat_linkcnt_retries++; + ACQUIRE_LOCK(&lk); + process_removes(vp); + softdep_speedup(); + FREE_LOCK(&lk); + error = ffs_syncvnode(vp, MNT_WAIT, 0); + if (error != 0) + return (error); + ACQUIRE_LOCK(&lk); + process_worklist_item(vp->v_mount, 2, LK_NOWAIT); + FREE_LOCK(&lk); + } + return (0); +} + /* * Attach a sbdep dependency to the superblock buf so that we can keep * track of the head of the linked list of referenced but unlinked inodes. Index: sys/ufs/ufs/ufs_extern.h =================================================================== --- sys/ufs/ufs/ufs_extern.h (revision 251100) +++ sys/ufs/ufs/ufs_extern.h (working copy) @@ -98,6 +98,7 @@ void softdep_setup_remove(struct buf *,s void softdep_setup_directory_change(struct buf *, struct inode *, struct inode *, ino_t, int); void softdep_change_linkcnt(struct inode *); +int softdep_check_linkcnt(struct inode *); void softdep_releasefile(struct inode *); int softdep_slowdown(struct vnode *); void softdep_setup_create(struct inode *, struct inode *); Index: sys/ufs/ufs/ufs_vnops.c =================================================================== --- sys/ufs/ufs/ufs_vnops.c (revision 251100) +++ sys/ufs/ufs/ufs_vnops.c (working copy) @@ -1812,10 +1812,13 @@ ufs_mkdir(ap) panic("ufs_mkdir: no name"); #endif dp = VTOI(dvp); - if ((nlink_t)dp->i_nlink >= LINK_MAX) { + error = 0; + if (DOINGSOFTDEP(dvp)) + error = softdep_check_linkcnt(dp); + else if ((nlink_t)dp->i_nlink >= LINK_MAX) error = EMLINK; + if (error != 0) goto out; - } dmode = vap->va_mode & 0777; dmode |= IFDIR; /*