Date: Tue, 23 Jul 2002 14:06:14 +1000 (EST) From: Bruce Evans <bde@zeta.org.au> To: Alfred Perlstein <bright@mu.org> Cc: fs@FreeBSD.ORG Subject: Re: rename hardlinks "works" on FreeBSD, but no-op on others Message-ID: <20020723133856.L28400-100000@gamplex.bde.org> In-Reply-To: <20020722191522.GA77219@elvis.mu.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On Mon, 22 Jul 2002, Alfred Perlstein wrote: > A coworker recently asked me (slightly modified): > > ...it says that if you rename file A to file B where A and B are > hard links to each other, it does nothing. I thought this was > kind of odd so I tried the experiment on Linux and sure enough > it does the same there: no error and both A and B still exist > after the rename. > > I tried the same experiment on Solaris 8 and got the same effect. > > I tried the same experiment on FreeBSD and it did the obviously > correct thing and removed the old name. > > What gives? > > It seems that we do the right thing, however: > > 1) are we standards compliant? No. > 2) just for curiousity, why would others silently fail? Because they are standards compliant (even though the standard may be wrong here). I fixed this in Linux back in 1992 or 1993, and in my version of FreeBSD a few months later, but never got around to committing the fix. I know too much about this because Minix has or had test programs for it, and I ran these tests to find bugs in early versions of Linux, FreeBSD and in the tests themselves. This patch has been tested for 9-10 years :-). It is a bit incomplete -- it doesn't remove the broken code, and filesystems still do extra work to handle the fvp == tvp case. %%% Index: vfs_syscalls.c =================================================================== RCS file: /home/ncvs/src/sys/kern/vfs_syscalls.c,v retrieving revision 1.268 diff -u -2 -r1.268 vfs_syscalls.c --- vfs_syscalls.c 13 Jul 2002 04:07:12 -0000 1.268 +++ vfs_syscalls.c 13 Jul 2002 20:22:32 -0000 @@ -2519,4 +2516,5 @@ if (fvp == tdvp) error = EINVAL; +#if 0 /* * If source is the same as the destination (that is the @@ -2529,4 +2527,13 @@ fromnd.ni_cnd.cn_namelen)) error = -1; +#else + /* + * If the source is the same as the destination (that is, if they + * are links to the same vnode), then there is nothing to do. + * POSIX standard. + */ + if (fvp == tvp) + error = -1; +#endif out: if (!error) { %%% Here is the ufs code for the fvp == tvp case: % /* % * Check if just deleting a link name or if we've lost a race. % * If another process completes the same rename after we've looked % * up the source and have blocked looking up the target, then the % * source and target inodes may be identical now although the % * names were never linked. % */ % if (fvp == tvp) { % if (fvp->v_type == VDIR) { % /* % * Linked directories are impossible, so we must % * have lost the race. Pretend that the rename % * completed before the lookup. % */ % #ifdef UFS_RENAME_DEBUG % printf("ufs_rename: fvp == tvp for directories\n"); % #endif % error = ENOENT; % goto abortit; % } % % /* Release destination completely. */ % vput(tdvp); % vput(tvp); % % /* % * Delete source. There is another race now that everything % * is unlocked, but this doesn't cause any new complications. % * Relookup() may find a file that is unrelated to the % * original one, or it may fail. Too bad. % */ % vrele(fdvp); % vrele(fvp); % fcnp->cn_flags &= ~MODMASK; % fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; % if ((fcnp->cn_flags & SAVESTART) == 0) % panic("ufs_rename: lost from startdir"); % fcnp->cn_nameiop = DELETE; % VREF(fdvp); % error = relookup(fdvp, &fvp, fcnp); % if (error == 0) % vrele(fdvp); % if (fvp == NULL) { % #ifdef UFS_RENAME_DEBUG % printf("ufs_rename: from name disappeared\n"); % #endif % return (ENOENT); % } % error = VOP_REMOVE(fdvp, fvp, fcnp); % if (fdvp == fvp) % vrele(fdvp); % else % vput(fdvp); % vput(fvp); % return (error); % } I don't understand the race case now, although ISTR fixing it. Races from using relookup() may also need to be considered. Bruce To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-fs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020723133856.L28400-100000>