Index: sbin/fsck_ffs/dir.c =================================================================== RCS file: /cvs/FreeBSD-CVS/src/sbin/fsck_ffs/dir.c,v retrieving revision 1.30 diff -u -r1.30 dir.c --- sbin/fsck_ffs/dir.c 8 Oct 2004 20:44:47 -0000 1.30 +++ sbin/fsck_ffs/dir.c 18 Mar 2005 13:13:34 -0000 @@ -474,9 +474,11 @@ parentdir != (ino_t)-1) (void)makeentry(orphan, lfdir, ".."); dp = ginode(lfdir); - DIP_SET(dp, di_nlink, DIP(dp, di_nlink) + 1); - inodirty(); - inoinfo(lfdir)->ino_linkcnt++; + if (dotdotlinkcnt) { + DIP_SET(dp, di_nlink, DIP(dp, di_nlink) + 1); + inodirty(); + inoinfo(lfdir)->ino_linkcnt++; + } pwarn("DIR I=%lu CONNECTED. ", (u_long)orphan); if (parentdir != (ino_t)-1) { printf("PARENT WAS I=%lu\n", (u_long)parentdir); Index: sbin/fsck_ffs/fsck.h =================================================================== RCS file: /cvs/FreeBSD-CVS/src/sbin/fsck_ffs/fsck.h,v retrieving revision 1.36 diff -u -r1.36 fsck.h --- sbin/fsck_ffs/fsck.h 7 Mar 2005 08:42:49 -0000 1.36 +++ sbin/fsck_ffs/fsck.h 18 Mar 2005 13:11:19 -0000 @@ -274,6 +274,7 @@ int bkgrdcheck; /* determine if background check is possible */ int bkgrdsumadj; /* whether the kernel have ability to adjust superblock summary */ char usedsoftdep; /* just fix soft dependency inconsistencies */ +char dotdotlinkcnt; /* Do we expect ".." to contribute to link count */ char preen; /* just fix normal inconsistencies */ char rerun; /* rerun fsck. Only used in non-preen mode */ int returntosingle; /* 1 => return to single user mode on exit */ Index: sbin/fsck_ffs/pass2.c =================================================================== RCS file: /cvs/FreeBSD-CVS/src/sbin/fsck_ffs/pass2.c,v retrieving revision 1.26 diff -u -r1.26 pass2.c --- sbin/fsck_ffs/pass2.c 8 Oct 2004 20:44:47 -0000 1.26 +++ sbin/fsck_ffs/pass2.c 23 Mar 2005 22:13:40 -0000 @@ -209,15 +209,18 @@ if (reply("FIX") == 0) continue; (void)makeentry(inp->i_number, inp->i_parent, ".."); - inoinfo(inp->i_parent)->ino_linkcnt--; + if (dotdotlinkcnt) + inoinfo(inp->i_parent)->ino_linkcnt--; continue; } fileerror(inp->i_parent, inp->i_number, "BAD INODE NUMBER FOR '..'"); if (reply("FIX") == 0) continue; - inoinfo(inp->i_dotdot)->ino_linkcnt++; - inoinfo(inp->i_parent)->ino_linkcnt--; + if (dotdotlinkcnt) { + inoinfo(inp->i_dotdot)->ino_linkcnt++; + inoinfo(inp->i_parent)->ino_linkcnt--; + } inp->i_dotdot = inp->i_parent; (void)changeino(inp->i_number, "..", inp->i_parent); } @@ -339,7 +342,7 @@ ret |= ALTERED; } idesc->id_entryno++; - if (dirp->d_ino != 0) + if (dirp->d_ino != 0 && dotdotlinkcnt) inoinfo(dirp->d_ino)->ino_linkcnt--; return (ret|KEEPON); chk2: @@ -446,7 +449,9 @@ if (reply("FIX") == 1) ret |= ALTERED; } - inoinfo(dirp->d_ino)->ino_linkcnt--; + if (dotdotlinkcnt || idesc->id_number == ROOTINO || + idesc->id_entryno != 2) + inoinfo(dirp->d_ino)->ino_linkcnt--; break; default: Index: sbin/fsck_ffs/pass3.c =================================================================== RCS file: /cvs/FreeBSD-CVS/src/sbin/fsck_ffs/pass3.c,v retrieving revision 1.15 diff -u -r1.15 pass3.c --- sbin/fsck_ffs/pass3.c 8 Oct 2004 20:44:47 -0000 1.15 +++ sbin/fsck_ffs/pass3.c 18 Mar 2005 14:07:10 -0000 @@ -96,7 +96,8 @@ if (loopcnt <= countdirs) { if (linkup(orphan, inp->i_dotdot, NULL)) { inp->i_parent = inp->i_dotdot = lfdir; - inoinfo(lfdir)->ino_linkcnt--; + if (dotdotlinkcnt) + inoinfo(lfdir)->ino_linkcnt--; } inoinfo(orphan)->ino_state = DFOUND; propagate(); @@ -117,9 +118,11 @@ if (linkup(orphan, inp->i_parent, namebuf)) { idesc.id_func = clearentry; if (ckinode(ginode(inp->i_parent), &idesc) & FOUND) - inoinfo(orphan)->ino_linkcnt++; + if (dotdotlinkcnt) + inoinfo(orphan)->ino_linkcnt++; inp->i_parent = inp->i_dotdot = lfdir; - inoinfo(lfdir)->ino_linkcnt--; + if (dotdotlinkcnt) + inoinfo(lfdir)->ino_linkcnt--; } inoinfo(orphan)->ino_state = DFOUND; propagate(); Index: sbin/fsck_ffs/setup.c =================================================================== RCS file: /cvs/FreeBSD-CVS/src/sbin/fsck_ffs/setup.c,v retrieving revision 1.49 diff -u -r1.49 setup.c --- sbin/fsck_ffs/setup.c 7 Mar 2005 08:42:49 -0000 1.49 +++ sbin/fsck_ffs/setup.c 23 Mar 2005 21:48:28 -0000 @@ -295,6 +295,10 @@ usedsoftdep = 1; else usedsoftdep = 0; + if (sblock.fs_flags & FS_NOLINKDIRS) + dotdotlinkcnt = 0; + else + dotdotlinkcnt = 1; return (1); badsb: Index: sbin/newfs/mkfs.c =================================================================== RCS file: /cvs/FreeBSD-CVS/src/sbin/newfs/mkfs.c,v retrieving revision 1.89 diff -u -r1.89 mkfs.c --- sbin/newfs/mkfs.c 20 Feb 2005 11:32:49 -0000 1.89 +++ sbin/newfs/mkfs.c 18 Mar 2005 16:38:50 -0000 @@ -131,6 +131,8 @@ } sblock.fs_old_flags = FS_FLAGS_UPDATED; sblock.fs_flags = 0; + if (Dflag) + sblock.fs_flags |= FS_NOLINKDIRS; if (Uflag) sblock.fs_flags |= FS_DOSOFTDEP; if (Lflag) @@ -765,7 +767,7 @@ * create the root directory */ node.dp1.di_mode = IFDIR | UMASK; - node.dp1.di_nlink = entries; + node.dp1.di_nlink = (Dflag) ? 2 : entries; node.dp1.di_size = makedir(root_dir, entries); node.dp1.di_db[0] = alloc(sblock.fs_fsize, node.dp1.di_mode); node.dp1.di_blocks = @@ -779,7 +781,7 @@ */ node.dp1.di_mode |= 020; node.dp1.di_gid = grp->gr_gid; - node.dp1.di_nlink = SNAPLINKCNT; + node.dp1.di_nlink = (Dflag) ? 2 : SNAPLINKCNT; node.dp1.di_size = makedir(snap_dir, SNAPLINKCNT); node.dp1.di_db[0] = alloc(sblock.fs_fsize, node.dp1.di_mode); @@ -801,7 +803,7 @@ * create the root directory */ node.dp2.di_mode = IFDIR | UMASK; - node.dp2.di_nlink = entries; + node.dp2.di_nlink = (Dflag) ? 2 : entries; node.dp2.di_size = makedir(root_dir, entries); node.dp2.di_db[0] = alloc(sblock.fs_fsize, node.dp2.di_mode); node.dp2.di_blocks = Index: sbin/newfs/newfs.8 =================================================================== RCS file: /cvs/FreeBSD-CVS/src/sbin/newfs/newfs.8,v retrieving revision 1.69 diff -u -r1.69 newfs.8 --- sbin/newfs/newfs.8 22 Jan 2005 14:36:51 -0000 1.69 +++ sbin/newfs/newfs.8 18 Mar 2005 14:13:55 -0000 @@ -36,7 +36,7 @@ .Nd construct a new UFS1/UFS2 file system .Sh SYNOPSIS .Nm -.Op Fl NUln +.Op Fl DNUln .Op Fl L Ar volname .Op Fl O Ar filesystem-type .Op Fl S Ar sector-size @@ -88,6 +88,9 @@ The default format is UFS2. .It Fl T Ar disktype For backward compatibility. +.It Fl D +Don't count link count directories in the traditional way. +This allows directories with large numbers of subdirectories. .It Fl U Enable soft updates on the new file system. .It Fl a Ar maxcontig Index: sbin/newfs/newfs.c =================================================================== RCS file: /cvs/FreeBSD-CVS/src/sbin/newfs/newfs.c,v retrieving revision 1.80 diff -u -r1.80 newfs.c --- sbin/newfs/newfs.c 22 Jan 2005 14:37:57 -0000 1.80 +++ sbin/newfs/newfs.c 18 Mar 2005 14:12:14 -0000 @@ -117,6 +117,7 @@ int Rflag; /* regression test */ int Uflag; /* enable soft updates for file system */ int Eflag = 0; /* exit in middle of newfs for testing */ +int Dflag; /* don't count ".." as an extra link */ int lflag; /* enable multilabel for file system */ int nflag; /* do not create .snap directory */ quad_t fssize; /* file system size */ @@ -156,8 +157,11 @@ off_t mediasize; while ((ch = getopt(argc, argv, - "EL:NO:RS:T:Ua:b:c:d:e:f:g:h:i:lm:no:s:")) != -1) + "DEL:NO:RS:T:Ua:b:c:d:e:f:g:h:i:lm:no:s:")) != -1) switch (ch) { + case 'D': + Dflag++; + break; case 'E': Eflag++; break; Index: sbin/newfs/newfs.h =================================================================== RCS file: /cvs/FreeBSD-CVS/src/sbin/newfs/newfs.h,v retrieving revision 1.17 diff -u -r1.17 newfs.h --- sbin/newfs/newfs.h 21 Jan 2005 22:20:25 -0000 1.17 +++ sbin/newfs/newfs.h 18 Mar 2005 14:12:44 -0000 @@ -49,6 +49,7 @@ extern int Rflag; /* regression test */ extern int Uflag; /* enable soft updates for file system */ extern int Eflag; /* exit as if error, for testing */ +extern int Dflag; /* don't count ".." as an extra link */ extern int lflag; /* enable multilabel MAC for file system */ extern int nflag; /* do not create .snap directory */ extern quad_t fssize; /* file system size */ Index: sbin/tunefs/tunefs.8 =================================================================== RCS file: /cvs/FreeBSD-CVS/src/sbin/tunefs/tunefs.8,v retrieving revision 1.36 diff -u -r1.36 tunefs.8 --- sbin/tunefs/tunefs.8 13 Feb 2005 22:25:17 -0000 1.36 +++ sbin/tunefs/tunefs.8 25 Mar 2005 15:42:20 -0000 @@ -38,6 +38,7 @@ .Nm .Op Fl A .Op Fl a Cm enable | disable +.Op Fl d Cm enable | disable .Op Fl e Ar maxbpg .Op Fl f Ar avgfilesize .Op Fl L Ar volname @@ -70,6 +71,11 @@ This is potentially dangerous - use with caution. .It Fl a Cm enable | disable Turn on/off the administrative ACL enable flag. +.It Fl n Cm enable | disable +This enables or disables unusual directory reference counting. +After enabling or disabling this option, +.Xr 8 fsck_ffs +should be run to recalculate directory reference counts. .It Fl e Ar maxbpg Indicate the maximum number of blocks any single file can allocate out of a cylinder group before it is forced to begin Index: sbin/tunefs/tunefs.c =================================================================== RCS file: /cvs/FreeBSD-CVS/src/sbin/tunefs/tunefs.c,v retrieving revision 1.42 diff -u -r1.42 tunefs.c --- sbin/tunefs/tunefs.c 9 Apr 2004 19:58:40 -0000 1.42 +++ sbin/tunefs/tunefs.c 25 Mar 2005 15:47:34 -0000 @@ -76,12 +76,12 @@ int main(int argc, char *argv[]) { - char *avalue, *Lvalue, *lvalue, *nvalue; + char *avalue, *Lvalue, *lvalue, *nvalue, *dvalue; const char *special, *on; const char *name; int active; int Aflag, aflag, eflag, evalue, fflag, fvalue, Lflag, lflag; - int mflag, mvalue, nflag, oflag, ovalue, pflag, sflag, svalue; + int mflag, mvalue, nflag, oflag, ovalue, pflag, sflag, svalue, dflag; int ch, found_arg, i; const char *chg[2]; struct ufs_args args; @@ -90,12 +90,12 @@ if (argc < 3) usage(); Aflag = aflag = eflag = fflag = Lflag = lflag = mflag = 0; - nflag = oflag = pflag = sflag = 0; - avalue = Lvalue = lvalue = nvalue = NULL; + dflag = nflag = oflag = pflag = sflag = 0; + avalue = Lvalue = lvalue = dvalue = nvalue = NULL; evalue = fvalue = mvalue = ovalue = svalue = 0; active = 0; found_arg = 0; /* At least one arg is required. */ - while ((ch = getopt(argc, argv, "Aa:e:f:L:l:m:n:o:ps:")) != -1) + while ((ch = getopt(argc, argv, "Ad:a:e:f:L:l:m:n:o:ps:")) != -1) switch (ch) { case 'A': @@ -115,6 +115,18 @@ aflag = 1; break; + case 'd': + found_arg = 1; + name = "no directory links"; + dvalue = optarg; + if (strcmp(dvalue, "enable") != 0 && + strcmp(dvalue, "disable") != 0) { + errx(10, "bad %s (options are %s)", + name, "`enable' or `disable'"); + } + dflag = 1; + break; + case 'e': found_arg = 1; name = "maximum blocks per file in a cylinder group"; @@ -337,6 +349,32 @@ } } } + if (dflag) { + name = "no directory links"; + if (strcmp(dvalue, "enable") == 0) { + if (sblock.fs_flags & FS_NOLINKDIRS) + warnx("%s remains unchanged as enabled", name); + else if (sblock.fs_clean == 0) { + warnx("%s cannot be enabled until fsck is run", + name); + } else { + sblock.fs_flags |= FS_NOLINKDIRS; + warnx("%s set: fsck to recalculate counts", + name); + } + } else if (strcmp(dvalue, "disable") == 0) { + if ((~sblock.fs_flags & FS_NOLINKDIRS) == FS_NOLINKDIRS) + warnx("%s remains unchanged as disabled", name); + else if (sblock.fs_clean == 0) { + warnx("%s cannot be disabled until fsck is run", + name); + } else { + sblock.fs_flags &= ~FS_NOLINKDIRS; + warnx("%s cleared: fsck to recalculate count", + name); + } + } + } if (oflag) { name = "optimization preference"; chg[FS_OPTSPACE] = "space"; @@ -404,6 +442,8 @@ (sblock.fs_flags & FS_MULTILABEL)? "enabled" : "disabled"); warnx("soft updates: (-n) %s", (sblock.fs_flags & FS_DOSOFTDEP)? "enabled" : "disabled"); + warnx("no directory links: (-d) %s", + (sblock.fs_flags & FS_NOLINKDIRS)? "enabled" : "disabled"); warnx("maximum blocks per file in a cylinder group: (-e) %d", sblock.fs_maxbpg); warnx("average file size: (-f) %d", Index: sys/ufs/ffs/ffs_alloc.c =================================================================== RCS file: /cvs/FreeBSD-CVS/src/sys/ufs/ffs/ffs_alloc.c,v retrieving revision 1.132 diff -u -r1.132 ffs_alloc.c --- sys/ufs/ffs/ffs_alloc.c 20 Feb 2005 08:02:15 -0000 1.132 +++ sys/ufs/ffs/ffs_alloc.c 25 Mar 2005 16:47:37 -0000 @@ -2349,7 +2349,9 @@ if ((error = getvnode(curproc->p_fd, cmd.handle, &fp)) != 0) return (error); vn_start_write(fp->f_data, &mp, V_WAIT); - if (mp == 0 || strncmp(mp->mnt_stat.f_fstypename, "ufs", MFSNAMELEN)) { + if (mp == 0 || + (strncmp(mp->mnt_stat.f_fstypename, "ufs", MFSNAMELEN) != 0 && + strncmp(mp->mnt_stat.f_fstypename, "wfs", MFSNAMELEN) != 0)) { vn_finished_write(mp); fdrop(fp, curthread); return (EINVAL); Index: sys/ufs/ffs/ffs_softdep.c =================================================================== RCS file: /cvs/FreeBSD-CVS/src/sys/ufs/ffs/ffs_softdep.c,v retrieving revision 1.178 diff -u -r1.178 ffs_softdep.c --- sys/ufs/ffs/ffs_softdep.c 13 Mar 2005 12:01:50 -0000 1.178 +++ sys/ufs/ffs/ffs_softdep.c 25 Mar 2005 23:07:25 -0000 @@ -3426,8 +3426,9 @@ * Rename a directory to a new parent. Since, we are both deleting * and creating a new directory entry, the link count on the new * directory should not change. Thus we skip the followup dirrem. + * We can also skip the dirrem if we are not counting ".." as a link. */ - if (dirrem->dm_state & DIRCHG) { + if ((dirrem->dm_state & DIRCHG) || (ip->i_fs->fs_flags & FS_NOLINKDIRS)) { num_dirrem -= 1; FREE_LOCK(&lk); vput(vp); Index: sys/ufs/ffs/ffs_vfsops.c =================================================================== RCS file: /cvs/FreeBSD-CVS/src/sys/ufs/ffs/ffs_vfsops.c,v retrieving revision 1.285 diff -u -r1.285 ffs_vfsops.c --- sys/ufs/ffs/ffs_vfsops.c 16 Mar 2005 11:20:51 -0000 1.285 +++ sys/ufs/ffs/ffs_vfsops.c 25 Mar 2005 16:45:36 -0000 @@ -1033,6 +1033,8 @@ fs = ump->um_fs; if (fs->fs_magic != FS_UFS1_MAGIC && fs->fs_magic != FS_UFS2_MAGIC) panic("ffs_statfs"); + if (fs->fs_flags & FS_NOLINKDIRS) + snprintf(sbp->f_fstypename, sizeof(sbp->f_fstypename), "wfs"); sbp->f_version = STATFS_VERSION; sbp->f_bsize = fs->fs_fsize; sbp->f_iosize = fs->fs_bsize; Index: sys/ufs/ffs/fs.h =================================================================== RCS file: /cvs/FreeBSD-CVS/src/sys/ufs/ffs/fs.h,v retrieving revision 1.48 diff -u -r1.48 fs.h --- sys/ufs/ffs/fs.h 20 Feb 2005 08:02:15 -0000 1.48 +++ sys/ufs/ffs/fs.h 18 Mar 2005 10:51:48 -0000 @@ -406,6 +406,7 @@ #define FS_INDEXDIRS 0x08 /* kernel supports indexed directories */ #define FS_ACLS 0x10 /* file system has ACLs enabled */ #define FS_MULTILABEL 0x20 /* file system is MAC multi-label */ +#define FS_NOLINKDIRS 0x40 /* filesystem ignores link count on directory */ #define FS_FLAGS_UPDATED 0x80 /* flags have been moved to new location */ /* Index: sys/ufs/ufs/inode.h =================================================================== RCS file: /cvs/FreeBSD-CVS/src/sys/ufs/ufs/inode.h,v retrieving revision 1.49 diff -u -r1.49 inode.h --- sys/ufs/ufs/inode.h 14 Mar 2005 10:21:16 -0000 1.49 +++ sys/ufs/ufs/inode.h 18 Mar 2005 11:47:53 -0000 @@ -168,6 +168,9 @@ #define DOINGSOFTDEP(vp) ((vp)->v_mount->mnt_flag & MNT_SOFTDEP) #define DOINGASYNC(vp) ((vp)->v_mount->mnt_flag & MNT_ASYNC) +/* Determine if we are doing link counting on directories. */ +#define DOINGLINKDIRS(ip) (!((ip)->i_fs->fs_flags & FS_NOLINKDIRS)) + /* This overlays the fid structure (see mount.h). */ struct ufid { u_int16_t ufid_len; /* Length of structure. */ Index: sys/ufs/ufs/ufs_lookup.c =================================================================== RCS file: /cvs/FreeBSD-CVS/src/sys/ufs/ufs/ufs_lookup.c,v retrieving revision 1.73 diff -u -r1.73 ufs_lookup.c --- sys/ufs/ufs/ufs_lookup.c 11 Jan 2005 07:36:22 -0000 1.73 +++ sys/ufs/ufs/ufs_lookup.c 23 Mar 2005 21:22:23 -0000 @@ -64,6 +64,7 @@ #endif #include #include +#include #ifdef DIAGNOSTIC static int dirchk = 1; @@ -1100,8 +1101,13 @@ ep->d_type = newtype; oip->i_effnlink--; if (DOINGSOFTDEP(vdp)) { - softdep_change_linkcnt(oip); - softdep_setup_directory_change(bp, dp, oip, newinum, isrmdir); + if (DOINGLINKDIRS(oip) || ep->d_namlen != 2 || + ep->d_name[0] != '.' || ep->d_name[1] != '.') { + softdep_change_linkcnt(oip); + softdep_setup_directory_change(bp, dp, oip, newinum, + isrmdir); + } else + oip->i_effnlink++; bdwrite(bp); } else { oip->i_nlink--; Index: sys/ufs/ufs/ufs_vnops.c =================================================================== RCS file: /cvs/FreeBSD-CVS/src/sys/ufs/ufs/ufs_vnops.c,v retrieving revision 1.267 diff -u -r1.267 ufs_vnops.c --- sys/ufs/ufs/ufs_vnops.c 13 Mar 2005 11:59:14 -0000 1.267 +++ sys/ufs/ufs/ufs_vnops.c 18 Mar 2005 15:03:31 -0000 @@ -84,6 +84,7 @@ #endif #include +#include static vop_access_t ufs_access; static vop_advlock_t ufs_advlock; @@ -1080,7 +1081,7 @@ * When source and destination have the same * parent we don't fool with the link count. */ - if (doingdirectory && newparent) { + if (doingdirectory && newparent && DOINGLINKDIRS(dp)) { if ((nlink_t)dp->i_nlink >= LINK_MAX) { error = EMLINK; goto bad; @@ -1099,7 +1100,7 @@ ufs_makedirentry(ip, tcnp, &newdir); error = ufs_direnter(tdvp, NULL, &newdir, tcnp, NULL); if (error) { - if (doingdirectory && newparent) { + if (doingdirectory && newparent && DOINGLINKDIRS(dp)) { dp->i_effnlink--; dp->i_nlink--; DIP_SET(dp, i_nlink, dp->i_nlink); @@ -1138,7 +1139,7 @@ * (both directories, or both not directories). */ if ((xp->i_mode&IFMT) == IFDIR) { - if ((xp->i_effnlink > 2) || + if (((DOINGLINKDIRS(xp)) && xp->i_effnlink > 2) || !ufs_dirempty(xp, dp->i_number, tcnp->cn_cred)) { error = ENOTEMPTY; goto bad; @@ -1158,7 +1159,7 @@ if (error) goto bad; if (doingdirectory) { - if (!newparent) { + if (!newparent && DOINGLINKDIRS(dp)) { dp->i_effnlink--; if (DOINGSOFTDEP(tdvp)) softdep_change_linkcnt(dp); @@ -1179,7 +1180,7 @@ * disk, so when running with that code we avoid doing * them now. */ - if (!newparent) { + if (!newparent && DOINGLINKDIRS(dp)) { dp->i_nlink--; DIP_SET(dp, i_nlink, dp->i_nlink); dp->i_flag |= IN_CHANGE; @@ -1326,7 +1327,7 @@ panic("ufs_mkdir: no name"); #endif dp = VTOI(dvp); - if ((nlink_t)dp->i_nlink >= LINK_MAX) { + if ((nlink_t)dp->i_nlink >= LINK_MAX && DOINGLINKDIRS(dp)) { error = EMLINK; goto out; } @@ -1473,15 +1474,17 @@ * Should be done before reference is created so cleanup is * possible if we crash. */ - dp->i_effnlink++; - dp->i_nlink++; - DIP_SET(dp, i_nlink, dp->i_nlink); - dp->i_flag |= IN_CHANGE; - if (DOINGSOFTDEP(dvp)) - softdep_change_linkcnt(dp); - error = UFS_UPDATE(tvp, !(DOINGSOFTDEP(dvp) | DOINGASYNC(dvp))); - if (error) - goto bad; + if (DOINGLINKDIRS(dp)) { + dp->i_effnlink++; + dp->i_nlink++; + DIP_SET(dp, i_nlink, dp->i_nlink); + dp->i_flag |= IN_CHANGE; + if (DOINGSOFTDEP(dvp)) + softdep_change_linkcnt(dp); + error = UFS_UPDATE(tvp, !(DOINGSOFTDEP(dvp) | DOINGASYNC(dvp))); + if (error) + goto bad; + } #ifdef MAC if (dvp->v_mount->mnt_flag & MNT_MULTILABEL) { error = mac_create_vnode_extattr(cnp->cn_cred, dvp->v_mount, @@ -1587,12 +1590,14 @@ VN_KNOTE_UNLOCKED(dvp, NOTE_WRITE | NOTE_LINK); *ap->a_vpp = tvp; } else { - dp->i_effnlink--; - dp->i_nlink--; - DIP_SET(dp, i_nlink, dp->i_nlink); - dp->i_flag |= IN_CHANGE; - if (DOINGSOFTDEP(dvp)) - softdep_change_linkcnt(dp); + if (DOINGLINKDIRS(dp)) { + dp->i_effnlink--; + dp->i_nlink--; + DIP_SET(dp, i_nlink, dp->i_nlink); + dp->i_flag |= IN_CHANGE; + if (DOINGSOFTDEP(dvp)) + softdep_change_linkcnt(dp); + } /* * No need to do an explicit VOP_TRUNCATE here, vrele will * do this for us because we set the link count to 0. @@ -1642,7 +1647,7 @@ error = EINVAL; goto out; } - if (ip->i_effnlink != 2 || + if ((DOINGLINKDIRS(ip) && ip->i_effnlink != 2) || !ufs_dirempty(ip, dp->i_number, cnp->cn_cred)) { error = ENOTEMPTY; goto out; @@ -1661,18 +1666,22 @@ * inode. If we crash in between, the directory * will be reattached to lost+found, */ - dp->i_effnlink--; + if (DOINGLINKDIRS(dp)) + dp->i_effnlink--; ip->i_effnlink--; if (DOINGSOFTDEP(vp)) { - softdep_change_linkcnt(dp); + if (DOINGLINKDIRS(dp)) + softdep_change_linkcnt(dp); softdep_change_linkcnt(ip); } error = ufs_dirremove(dvp, ip, cnp->cn_flags, 1); if (error) { - dp->i_effnlink++; + if (DOINGLINKDIRS(dp)) + dp->i_effnlink++; ip->i_effnlink++; - if (DOINGSOFTDEP(vp)) { - softdep_change_linkcnt(dp); + if (DOINGSOFTDEP(dvp)) { + if (DOINGLINKDIRS(dp)) + softdep_change_linkcnt(dp); softdep_change_linkcnt(ip); } goto out; @@ -1687,9 +1696,11 @@ * when running with that code we avoid doing them now. */ if (!DOINGSOFTDEP(vp)) { - dp->i_nlink--; - DIP_SET(dp, i_nlink, dp->i_nlink); - dp->i_flag |= IN_CHANGE; + if (DOINGLINKDIRS(dp)) { + dp->i_nlink--; + DIP_SET(dp, i_nlink, dp->i_nlink); + dp->i_flag |= IN_CHANGE; + } ip->i_nlink--; DIP_SET(ip, i_nlink, ip->i_nlink); ip->i_flag |= IN_CHANGE;