The reconnect algorithm was historically O(n^4).

Some years ago I made it O(n^2).
Someone helpfully made it O(n^4) again.
Today I'm making it O(n).
If that's not good enough, I don't know what else to do.  B-)

Technical details:
* The graph traversal in propagate() is modified to be able to start from any
  point in the tree.  To handle certain exceptional cases, it is also modified
  to work in two passes, marking the tree with a special tag and then changing
  it to DFOUND.
* The reconnect case now modifies the child/sibling pointers and calls
  propagate() to propagate the connection state starting with the reconnected
  directory.

Pray that you never encounter a file system trashed enough for this to matter.
This commit is contained in:
mycroft 2001-01-09 05:51:14 +00:00
parent 3f2ff10f4c
commit 66418680d4
5 changed files with 58 additions and 39 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: dir.c,v 1.28 2000/12/14 00:32:22 simonb Exp $ */
/* $NetBSD: dir.c,v 1.29 2001/01/09 05:51:14 mycroft Exp $ */
/*
* Copyright (c) 1980, 1986, 1993
@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "@(#)dir.c 8.8 (Berkeley) 4/28/95";
#else
__RCSID("$NetBSD: dir.c,v 1.28 2000/12/14 00:32:22 simonb Exp $");
__RCSID("$NetBSD: dir.c,v 1.29 2001/01/09 05:51:14 mycroft Exp $");
#endif
#endif /* not lint */
@ -84,38 +84,33 @@ static int mkentry __P((struct inodesc *));
* Propagate connected state through the tree.
*/
void
propagate()
propagate(inumber)
ino_t inumber;
{
struct inoinfo **inpp, *inp, *pinp;
struct inoinfo **inpend;
struct inoinfo *inp;
/*
* Create a list of children for each directory.
*/
inpend = &inpsort[inplast];
for (inpp = inpsort; inpp < inpend; inpp++) {
inp = *inpp;
inp->i_child = inp->i_sibling = inp->i_parentp = 0;
if (statemap[inp->i_number] == DFOUND)
statemap[inp->i_number] = DSTATE;
inp = getinoinfo(inumber);
for (;;) {
statemap[inp->i_number] = DMARK;
if (inp->i_child &&
statemap[inp->i_child->i_number] != DMARK)
inp = inp->i_child;
else if (inp->i_number == inumber)
break;
else if (inp->i_sibling)
inp = inp->i_sibling;
else
inp = inp->i_parentp;
}
for (inpp = inpsort; inpp < inpend; inpp++) {
inp = *inpp;
if (inp->i_parent == 0 ||
inp->i_number == ROOTINO)
continue;
pinp = getinoinfo(inp->i_parent);
inp->i_parentp = pinp;
inp->i_sibling = pinp->i_child;
pinp->i_child = inp;
}
inp = getinoinfo(ROOTINO);
while (inp) {
for (;;) {
statemap[inp->i_number] = DFOUND;
if (inp->i_child &&
statemap[inp->i_child->i_number] == DSTATE)
statemap[inp->i_child->i_number] != DFOUND)
inp = inp->i_child;
else if (inp->i_number == inumber)
break;
else if (inp->i_sibling)
inp = inp->i_sibling;
else

View File

@ -1,4 +1,4 @@
/* $NetBSD: extern.h,v 1.10 1998/07/26 20:32:42 mycroft Exp $ */
/* $NetBSD: extern.h,v 1.11 2001/01/09 05:51:14 mycroft Exp $ */
/*
* Copyright (c) 1994 James A. Jegers
@ -74,7 +74,7 @@ int pass4check __P((struct inodesc *));
void pass5 __P((void));
void pfatal __P((const char *fmt, ...));
void pinode __P((ino_t));
void propagate __P((void));
void propagate __P((ino_t));
void pwarn __P((const char *fmt, ...));
int reply __P((char *));
void resetinodebuf __P((void));

View File

@ -1,4 +1,4 @@
/* $NetBSD: fsck.h,v 1.21 2000/12/13 22:38:15 scw Exp $ */
/* $NetBSD: fsck.h,v 1.22 2001/01/09 05:51:14 mycroft Exp $ */
/*
* Copyright (c) 1980, 1986, 1993
@ -53,6 +53,7 @@
#define DFOUND 04 /* directory found during descent */
#define DCLEAR 05 /* directory is to be cleared */
#define FCLEAR 06 /* file is to be cleared */
#define DMARK 07 /* used in propagate()'s traversal algorithm */
/*
* buffer cache structure.

View File

@ -1,4 +1,4 @@
/* $NetBSD: pass2.c,v 1.28 2001/01/05 02:02:57 lukem Exp $ */
/* $NetBSD: pass2.c,v 1.29 2001/01/09 05:51:14 mycroft Exp $ */
/*
* Copyright (c) 1980, 1986, 1993
@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "@(#)pass2.c 8.9 (Berkeley) 4/28/95";
#else
__RCSID("$NetBSD: pass2.c,v 1.28 2001/01/05 02:02:57 lukem Exp $");
__RCSID("$NetBSD: pass2.c,v 1.29 2001/01/09 05:51:14 mycroft Exp $");
#endif
#endif /* not lint */
@ -67,7 +67,7 @@ void
pass2()
{
struct dinode *dp;
struct inoinfo **inpp, *inp;
struct inoinfo **inpp, *inp, *pinp;
struct inoinfo **inpend;
struct inodesc curino;
struct dinode dino;
@ -235,10 +235,30 @@ pass2()
inp->i_dotdot = inp->i_parent;
(void)changeino(inp->i_number, "..", inp->i_parent);
}
/*
* Create a list of children for each directory.
*/
inpend = &inpsort[inplast];
for (inpp = inpsort; inpp < inpend; inpp++) {
inp = *inpp;
inp->i_child = inp->i_sibling = inp->i_parentp = 0;
if (statemap[inp->i_number] == DFOUND)
statemap[inp->i_number] = DSTATE;
}
for (inpp = inpsort; inpp < inpend; inpp++) {
inp = *inpp;
if (inp->i_parent == 0 ||
inp->i_number == ROOTINO)
continue;
pinp = getinoinfo(inp->i_parent);
inp->i_parentp = pinp;
inp->i_sibling = pinp->i_child;
pinp->i_child = inp;
}
/*
* Mark all the directories that can be found from the root.
*/
propagate();
propagate(ROOTINO);
}
static int

View File

@ -1,4 +1,4 @@
/* $NetBSD: pass3.c,v 1.10 1997/09/16 16:45:19 lukem Exp $ */
/* $NetBSD: pass3.c,v 1.11 2001/01/09 05:51:14 mycroft Exp $ */
/*
* Copyright (c) 1980, 1986, 1993
@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "@(#)pass3.c 8.2 (Berkeley) 4/27/95";
#else
__RCSID("$NetBSD: pass3.c,v 1.10 1997/09/16 16:45:19 lukem Exp $");
__RCSID("$NetBSD: pass3.c,v 1.11 2001/01/09 05:51:14 mycroft Exp $");
#endif
#endif /* not lint */
@ -54,7 +54,7 @@ __RCSID("$NetBSD: pass3.c,v 1.10 1997/09/16 16:45:19 lukem Exp $");
void
pass3()
{
struct inoinfo **inpp, *inp;
struct inoinfo **inpp, *inp, *pinp;
ino_t orphan;
int loopcnt;
@ -76,7 +76,10 @@ pass3()
(void)linkup(orphan, inp->i_dotdot);
inp->i_parent = inp->i_dotdot = lfdir;
lncntp[lfdir]--;
statemap[orphan] = DFOUND;
propagate();
pinp = getinoinfo(lfdir);
inp->i_parentp = pinp;
inp->i_sibling = pinp->i_child;
pinp->i_child = inp;
propagate(orphan);
}
}