[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Debbugs: The Next Generation



On Sat, Aug 18, 2001 at 01:52:56AM -0400, Matt Zimmerman wrote:
> On Tue, Aug 14, 2001 at 04:24:33PM +1000, Anthony Towns wrote:
> > That's not true: ext2 queries and directory lists are the problem here,
> > in that they're O(N) and O(N^2) rather than O(1)/O(N). Using reiser or
> > subdirectories would reduce those to O(lg(N)) and O(N lg(N)).
> 
> Why on earth are directory lists O(N^2)?  I don't know much about ext2
> internals, but that should be an O(N) operation in any sane filesystem.  

Doing a directory list is indeed O(N) for ext2.  

However, iterating through the directory using readdir() and then
stating or opening each file in readdir order is O(N**2).  There's a
very obvious optimization which makes this O(N), which I thought ext2
was using, but as it turns out, we weren't.

Thanks for bringing this to my attention; here's the very simple
kernel patch which should speed up a du or find of very large
directories significantly.

						- Ted

Patch generated: on Sat Aug 18 08:41:38 EDT 2001 by tytso@think
against Linux version 2.4.8
 
===================================================================
RCS file: fs/ext2/RCS/dir.c,v
retrieving revision 1.1
diff -u -r1.1 fs/ext2/dir.c
--- fs/ext2/dir.c	2001/08/18 11:11:30	1.1
+++ fs/ext2/dir.c	2001/08/18 12:41:10
@@ -303,7 +303,7 @@
 	const char *name = dentry->d_name.name;
 	int namelen = dentry->d_name.len;
 	unsigned reclen = EXT2_DIR_REC_LEN(namelen);
-	unsigned long n;
+	unsigned long start, n;
 	unsigned long npages = dir_pages(dir);
 	struct page *page = NULL;
 	ext2_dirent * de;
@@ -311,7 +311,11 @@
 	/* OFFSET_CACHE */
 	*res_page = NULL;
 
-	for (n = 0; n < npages; n++) {
+	start = dir->u.ext2_i.i_dir_start_lookup;
+	if (start >= npages)
+		start = 0;
+	n = start;
+	do {
 		char *kaddr;
 		page = ext2_get_page(dir, n);
 		if (IS_ERR(page))
@@ -324,11 +328,14 @@
 			if (ext2_match (namelen, name, de))
 				goto found;
 		ext2_put_page(page);
-	}
+		if (++n >= npages)
+			n = 0;
+	} while (n != start);
 	return NULL;
 
 found:
 	*res_page = page;
+	dir->u.ext2_i.i_dir_start_lookup = n;
 	return de;
 }
 
===================================================================
RCS file: include/linux/RCS/ext2_fs_i.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/ext2_fs_i.h
--- include/linux/ext2_fs_i.h	2001/08/18 11:10:48	1.1
+++ include/linux/ext2_fs_i.h	2001/08/18 11:11:18
@@ -34,6 +34,7 @@
 	__u32	i_next_alloc_goal;
 	__u32	i_prealloc_block;
 	__u32	i_prealloc_count;
+	__u32	i_dir_start_lookup;
 	int	i_new_inode:1;	/* Is a freshly allocated inode */
 };
 



Reply to: