Last night's Tux3 U consisted of a walkthrough of the deferred delete 
patch, during which Hirofumi noticed another race: during deferred 
delete processing, the DCACHE_HIDDEN flag has to be kept until the 
dentry has actually been unlinked, otherwise a lookup may erroneously 
succeed after the HIDDEN flag has ben cleared and before the dentry is 
set negative by removing the inode.  The solution is not to clear the 
HIDDEN flag at all, except when the dentry is about to be reused.  This 
simplifies things a little.

With the current patch, deferred deletion seems to work pretty well, but 
a new ceate of a deferred, deleted name will fail because the Ext2 
create will go to the dirent block and find the name still there.  To 
fix this, I need to complete the patch and handle deferred create as 
well.

The updated patch, and difference between the last two patches are 
attached.

Daniel
diff --git a/Makefile b/Makefile
index 56fb747..985a7ce 100644
--- a/Makefile
+++ b/Makefile
@@ -538,7 +538,7 @@ NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include)
 CHECKFLAGS     += $(NOSTDINC_FLAGS)
 
 # warn about C99 declaration after statement
-KBUILD_CFLAGS += $(call cc-option,-Wdeclaration-after-statement,)
+#KBUILD_CFLAGS += $(call cc-option,-Wdeclaration-after-statement,)
 
 # disable pointer signed / unsigned warnings in gcc 4.0
 KBUILD_CFLAGS += $(call cc-option,-Wno-pointer-sign,)
diff --git a/fs/dcache.c b/fs/dcache.c
index 6068c25..a61d7ab 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -272,7 +272,7 @@ int d_invalidate(struct dentry * dentry)
 	 */
 	spin_lock(&dentry->d_lock);
 	if (atomic_read(&dentry->d_count) > 1) {
-		if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) {
+		if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { // what to do here?
 			spin_unlock(&dentry->d_lock);
 			spin_unlock(&dcache_lock);
 			return -EBUSY;
@@ -973,6 +973,7 @@ void d_instantiate(struct dentry *entry, struct inode * inode)
 	if (inode)
 		list_add(&entry->d_alias, &inode->i_dentry);
 	entry->d_inode = inode;
+	entry->d_flags &= ~DCACHE_HIDDEN;
 	fsnotify_d_instantiate(entry, inode);
 	spin_unlock(&dcache_lock);
 	security_d_instantiate(entry, inode);
@@ -1024,6 +1025,7 @@ static struct dentry *__d_instantiate_unique(struct dentry *entry,
 
 	list_add(&entry->d_alias, &inode->i_dentry);
 	entry->d_inode = inode;
+	entry->d_flags &= ~DCACHE_HIDDEN;
 	fsnotify_d_instantiate(entry, inode);
 	return NULL;
 }
@@ -1387,20 +1389,22 @@ out:
  
 void d_delete(struct dentry * dentry)
 {
-	int isdir = 0;
+	int isdir = 0, hidden;
 	/*
 	 * Are we the only user?
 	 */
 	spin_lock(&dcache_lock);
 	spin_lock(&dentry->d_lock);
 	isdir = S_ISDIR(dentry->d_inode->i_mode);
-	if (atomic_read(&dentry->d_count) == 1) {
+	hidden = dentry->d_op && dentry->d_op->d_hide && dentry->d_op->d_hide(dentry);
+
+	if (atomic_read(&dentry->d_count) == 1 + hidden) {
 		dentry_iput(dentry);
 		fsnotify_nameremove(dentry, isdir);
 		return;
 	}
 
-	if (!d_unhashed(dentry))
+	if (!d_unhashed(dentry) && !hidden)
 		__d_drop(dentry);
 
 	spin_unlock(&dentry->d_lock);
@@ -1514,7 +1518,7 @@ static void d_move_locked(struct dentry * dentry, struct dentry * target)
 {
 	struct hlist_head *list;
 
-	if (!dentry->d_inode)
+	if (d_negative(dentry))
 		printk(KERN_WARNING "VFS: moving negative dcache entry\n");
 
 	write_seqlock(&rename_lock);
@@ -2103,7 +2107,7 @@ ino_t find_inode_number(struct dentry *dir, struct qstr *name)
 
 	dentry = d_hash_and_lookup(dir, name);
 	if (dentry) {
-		if (dentry->d_inode)
+		if (!d_negative(dentry))
 			ino = dentry->d_inode->i_ino;
 		dput(dentry);
 	}
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index a78c6b4..5bb64af 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -270,6 +270,42 @@ static inline void ext2_set_de_type(ext2_dirent *de, struct inode *inode)
 		de->file_type = 0;
 }
 
+int ext2_unlink_deferred(struct inode *dir, struct dentry *dentry);
+void dentry_iput(struct dentry *dentry);
+
+int ext2_flush_dir(struct dentry *dir)
+{
+	printk(">>> ext2_sync_dir %p \"%.*s\"\n", dir, dir->d_name.len, dir->d_name.name);
+	struct list_head *next;
+	spin_lock(&dcache_lock);
+	for (next = dir->d_subdirs.next; next != &dir->d_subdirs;) {
+		struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child);
+		if (d_unhashed(dentry))
+			continue;
+		show_dentry("dentry", dentry);
+		next = next->next;
+		spin_lock(&dentry->d_lock);
+		if (d_negative(dentry)) {
+			show_dentry("drop hidden dentry", dentry);
+			if ((dentry->d_flags & DCACHE_BACKED)) {
+				dentry->d_flags &= ~DCACHE_BACKED;
+				show_dentry("deferred unlink", dentry);
+				spin_unlock(&dentry->d_lock);
+				spin_unlock(&dcache_lock);
+				ext2_unlink_deferred(dir->d_inode, dentry);
+				if (dentry->d_inode)
+					d_delete(dentry);
+				dput(dentry);
+				spin_lock(&dcache_lock);
+				continue;
+			}
+			spin_unlock(&dentry->d_lock);
+		}
+	}
+	spin_unlock(&dcache_lock);
+	return 0; // really??
+}
+
 static int
 ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
 {
@@ -283,6 +319,8 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
 	unsigned char *types = NULL;
 	int need_revalidate = filp->f_version != inode->i_version;
 
+	ext2_flush_dir(filp->f_path.dentry);
+
 	if (pos > inode->i_size - EXT2_DIR_REC_LEN(1))
 		return 0;
 
@@ -699,6 +737,12 @@ not_empty:
 	return 0;
 }
 
+int ext2_sync_dir(struct file *file, struct dentry *dir, int datasync)
+{
+	ext2_flush_dir(dir);
+	return ext2_sync_file(file, dir, datasync);
+}
+
 const struct file_operations ext2_dir_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= generic_read_dir,
@@ -707,5 +751,5 @@ const struct file_operations ext2_dir_operations = {
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= ext2_compat_ioctl,
 #endif
-	.fsync		= ext2_sync_file,
+	.fsync		= ext2_sync_dir,
 };
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 384fc0d..a9ce89b 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -58,6 +58,7 @@ static inline int ext2_inode_is_fast_symlink(struct inode *inode)
  */
 void ext2_delete_inode (struct inode * inode)
 {
+	printk(">>> ext2_delete_inode\n");
 	truncate_inode_pages(&inode->i_data, 0);
 
 	if (is_bad_inode(inode))
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 80c97fd..bdd640c 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -36,10 +36,27 @@
 #include "acl.h"
 #include "xip.h"
 
+static int ext2_hide_dentry(struct dentry *dentry)
+{
+	if (dentry->d_flags & DCACHE_BACKED) {
+		BUG_ON(!dentry->d_inode);
+		show_dentry("hide dentry", dentry);
+		dentry->d_flags |= DCACHE_HIDDEN;
+		dget(dentry);
+		return 1;
+	}
+	return 0;
+}
+
+static struct dentry_operations ext2_dentry_operations = {
+	.d_hide = ext2_hide_dentry,
+};
+
 static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode)
 {
 	int err = ext2_add_link(dentry, inode);
 	if (!err) {
+		dentry->d_op = &ext2_dentry_operations;
 		d_instantiate(dentry, inode);
 		return 0;
 	}
@@ -67,6 +84,8 @@ static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, str
 		if (IS_ERR(inode))
 			return ERR_CAST(inode);
 	}
+	dentry->d_flags |= DCACHE_BACKED;
+	dentry->d_op = &ext2_dentry_operations;
 	return d_splice_alias(inode, dentry);
 }
 
@@ -237,6 +256,7 @@ static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
 	if (err)
 		goto out_fail;
 
+	dentry->d_op = &ext2_dentry_operations;
 	d_instantiate(dentry, inode);
 out:
 	return err;
@@ -250,6 +270,21 @@ out_dir:
 	goto out;
 }
 
+static int defer_unlink(struct inode *dir, struct dentry *dentry)
+{
+	show_dentry("defer unlink", dentry);
+	dentry->d_inode->i_ctime = dir->i_ctime;
+	inode_dec_link_count(dentry->d_inode);
+	return 0;
+}
+
+int ext2_unlink_deferred(struct inode *dir, struct dentry *dentry)
+{
+	struct page *page;
+	struct ext2_dir_entry_2 *de = ext2_find_entry(dir, dentry, &page);
+	return de ? ext2_delete_entry(de, page) : -ENOENT;
+}
+
 static int ext2_unlink(struct inode * dir, struct dentry *dentry)
 {
 	struct inode * inode = dentry->d_inode;
@@ -377,7 +412,7 @@ const struct inode_operations ext2_dir_inode_operations = {
 	.create		= ext2_create,
 	.lookup		= ext2_lookup,
 	.link		= ext2_link,
-	.unlink		= ext2_unlink,
+	.unlink		= defer_unlink,
 	.symlink	= ext2_symlink,
 	.mkdir		= ext2_mkdir,
 	.rmdir		= ext2_rmdir,
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index ef50cbc..e8066b3 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -295,17 +295,52 @@ static ssize_t ext2_quota_read(struct super_block *sb, int type, char *data, siz
 static ssize_t ext2_quota_write(struct super_block *sb, int type, const char *data, size_t len, loff_t off);
 #endif
 
+extern spinlock_t inode_lock;
+
+static inline void show_inode(char *tag, struct inode *inode)
+{
+	printk(">>> %s: %p/%i %x\n", tag, inode,
+		atomic_read(&inode->i_count), inode->i_flags);
+}
+
+static void defer_drop_inode(struct inode *inode)
+{
+	if (inode->i_nlink) {
+		generic_drop_inode(inode);
+		return;
+	}
+	show_inode("defer inode delete", inode);
+	inode->i_state |= I_DIRTY;
+	list_move(&inode->i_list, &EXT2_SB(inode->i_sb)->delete);
+	spin_unlock(&inode_lock);
+}
+
+extern struct list_head inode_unused;
+
+static int ext2_sync_fs(struct super_block *sb, int wait)
+{
+	while (!list_empty(&EXT2_SB(sb)->delete)) {
+		struct inode *inode = list_entry(EXT2_SB(sb)->delete.next, struct inode, i_list);
+		show_inode("delete deferred inode", inode);
+		spin_lock(&inode_lock);
+		generic_delete_inode(inode); /* removes from list and drops lock */
+	}
+	return 0;
+}
+
 static const struct super_operations ext2_sops = {
 	.alloc_inode	= ext2_alloc_inode,
 	.destroy_inode	= ext2_destroy_inode,
 	.write_inode	= ext2_write_inode,
 	.delete_inode	= ext2_delete_inode,
+	.drop_inode	= defer_drop_inode,
 	.put_super	= ext2_put_super,
 	.write_super	= ext2_write_super,
 	.statfs		= ext2_statfs,
 	.remount_fs	= ext2_remount,
 	.clear_inode	= ext2_clear_inode,
 	.show_options	= ext2_show_options,
+	.sync_fs	= ext2_sync_fs,
 #ifdef CONFIG_QUOTA
 	.quota_read	= ext2_quota_read,
 	.quota_write	= ext2_quota_write,
@@ -614,6 +649,7 @@ static int ext2_setup_super (struct super_block * sb,
 			EXT2_BLOCKS_PER_GROUP(sb),
 			EXT2_INODES_PER_GROUP(sb),
 			sbi->s_mount_opt);
+	INIT_LIST_HEAD(&sbi->delete);
 	return res;
 }
 
diff --git a/fs/namei.c b/fs/namei.c
index 3b26a24..a9d103b 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -955,9 +955,9 @@ static int __link_path_walk(const char *name, struct nameidata *nd)
 			break;
 
 		err = -ENOENT;
-		inode = next.dentry->d_inode;
-		if (!inode)
+		if (d_negative(next.dentry))
 			goto out_dput;
+		inode = next.dentry->d_inode;
 		err = -ENOTDIR; 
 		if (!inode->i_op)
 			goto out_dput;
@@ -967,9 +967,9 @@ static int __link_path_walk(const char *name, struct nameidata *nd)
 			if (err)
 				goto return_err;
 			err = -ENOENT;
-			inode = nd->path.dentry->d_inode;
-			if (!inode)
+			if (d_negative(nd->path.dentry))
 				break;
+			inode = nd->path.dentry->d_inode;
 			err = -ENOTDIR; 
 			if (!inode->i_op)
 				break;
@@ -1077,7 +1077,7 @@ static int __emul_lookup_dentry(const char *name, struct nameidata *nd)
 	if (path_walk(name, nd))
 		return 0;		/* something went wrong... */
 
-	if (!nd->path.dentry->d_inode ||
+	if (d_negative(nd->path.dentry) ||
 	    S_ISDIR(nd->path.dentry->d_inode->i_mode)) {
 		struct path old_path = nd->path;
 		struct qstr last = nd->last;
@@ -1094,7 +1094,7 @@ static int __emul_lookup_dentry(const char *name, struct nameidata *nd)
 		path_get(&fs->root);
 		read_unlock(&fs->lock);
 		if (path_walk(name, nd) == 0) {
-			if (nd->path.dentry->d_inode) {
+			if (d_negative(nd->path.dentry)) {
 				path_put(&old_path);
 				return 1;
 			}
@@ -1487,7 +1487,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
 {
 	int error;
 
-	if (!victim->d_inode)
+	if (d_negative(victim))
 		return -ENOENT;
 
 	BUG_ON(victim->d_parent->d_inode != dir);
@@ -1526,7 +1526,8 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
 static inline int may_create(struct inode *dir, struct dentry *child,
 			     struct nameidata *nd)
 {
-	if (child->d_inode)
+printk("--- dentry %p negative %i\n", child, d_negative(child));
+	if (!d_negative(child))
 		return -EEXIST;
 	if (IS_DEADDIR(dir))
 		return -ENOENT;
@@ -1618,12 +1619,14 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode,
 int may_open(struct nameidata *nd, int acc_mode, int flag)
 {
 	struct dentry *dentry = nd->path.dentry;
-	struct inode *inode = dentry->d_inode;
+	struct inode *inode;
 	int error;
 
-	if (!inode)
+	if (d_negative(dentry))
 		return -ENOENT;
 
+	inode = dentry->d_inode;
+
 	if (S_ISLNK(inode->i_mode))
 		return -ELOOP;
 	
@@ -1828,7 +1831,7 @@ do_last:
 	}
 
 	/* Negative dentry, just create the file */
-	if (!path.dentry->d_inode) {
+	if (d_negative(path.dentry)) {
 		/*
 		 * This write is needed to ensure that a
 		 * ro->rw transition does not occur between
@@ -1866,14 +1869,14 @@ do_last:
 	}
 
 	error = -ENOENT;
-	if (!path.dentry->d_inode)
+	if (d_negative(path.dentry))
 		goto exit_dput;
 	if (path.dentry->d_inode->i_op && path.dentry->d_inode->i_op->follow_link)
 		goto do_link;
 
 	path_to_nameidata(&path, &nd);
 	error = -EISDIR;
-	if (path.dentry->d_inode && S_ISDIR(path.dentry->d_inode->i_mode))
+	if (!d_negative(path.dentry) && S_ISDIR(path.dentry->d_inode->i_mode))
 		goto exit;
 ok:
 	/*
@@ -2017,7 +2020,7 @@ struct dentry *lookup_create(struct nameidata *nd, int is_dir)
 	if (IS_ERR(dentry))
 		goto fail;
 
-	if (dentry->d_inode)
+	if (!d_negative(dentry))
 		goto eexist;
 	/*
 	 * Special case - lookup gave negative, but... we had foo/bar/
@@ -2381,7 +2384,7 @@ static long do_unlinkat(int dfd, const char __user *pathname)
 		/* Why not before? Because we want correct error value */
 		if (nd.last.name[nd.last.len])
 			goto slashes;
-		inode = dentry->d_inode;
+		inode = dentry->d_inode; // what to do here?
 		if (inode)
 			atomic_inc(&inode->i_count);
 		error = mnt_want_write(nd.path.mnt);
@@ -2402,7 +2405,7 @@ exit:
 	return error;
 
 slashes:
-	error = !dentry->d_inode ? -ENOENT :
+	error = d_negative(dentry) ? -ENOENT :
 		S_ISDIR(dentry->d_inode->i_mode) ? -EISDIR : -ENOTDIR;
 	goto exit2;
 }
@@ -2680,7 +2683,7 @@ static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
 
 	dget(new_dentry);
 	target = new_dentry->d_inode;
-	if (target)
+	if (target) // what to do here?
 		mutex_lock(&target->i_mutex);
 	if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry))
 		error = -EBUSY;
@@ -2710,7 +2713,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 	if (error)
 		return error;
 
-	if (!new_dentry->d_inode)
+	if (d_negative(new_dentry))
 		error = may_create(new_dir, new_dentry, NULL);
 	else
 		error = may_delete(new_dir, new_dentry, is_dir);
@@ -2777,7 +2780,7 @@ static int do_rename(int olddfd, const char *oldname,
 		goto exit3;
 	/* source must exist */
 	error = -ENOENT;
-	if (!old_dentry->d_inode)
+	if (d_negative(old_dentry))
 		goto exit4;
 	/* unless the source is a directory trailing slashes give -ENOTDIR */
 	if (!S_ISDIR(old_dentry->d_inode->i_mode)) {
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index d982eb8..e05eaca 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -133,6 +133,7 @@ struct dentry_operations {
 	void (*d_release)(struct dentry *);
 	void (*d_iput)(struct dentry *, struct inode *);
 	char *(*d_dname)(struct dentry *, char *, int);
+	int (*d_hide)(struct dentry *);
 };
 
 /* the dentry parameter passed to d_hash and d_compare is the parent
@@ -176,6 +177,10 @@ d_iput:		no		no		no       yes
 
 #define DCACHE_INOTIFY_PARENT_WATCHED	0x0020 /* Parent inode is watched */
 
+#define DCACHE_HIDDEN		0x0020 /* Unlinked but referenced by an open file */
+#define DCACHE_BACKED		0x0040 /* FS has dirent */
+#define DCACHE_STALE		0x0080 /* FS has wrong dirent */
+
 extern spinlock_t dcache_lock;
 extern seqlock_t rename_lock;
 
@@ -341,6 +346,11 @@ static inline int d_unhashed(struct dentry *dentry)
 	return (dentry->d_flags & DCACHE_UNHASHED);
 }
 
+static inline int d_negative(struct dentry *dentry)
+{
+	return !dentry->d_inode || (dentry->d_flags & DCACHE_HIDDEN);
+}
+
 static inline struct dentry *dget_parent(struct dentry *dentry)
 {
 	struct dentry *ret;
@@ -363,4 +373,11 @@ extern struct dentry *lookup_create(struct nameidata *nd, int is_dir);
 
 extern int sysctl_vfs_cache_pressure;
 
+static inline void show_dentry(char *tag, struct dentry *dentry)
+{
+	printk(">>> %s: %p/%i %x \"%.*s\"\n", tag, dentry,
+		atomic_read(&dentry->d_count), dentry->d_flags,
+		dentry->d_name.len, dentry->d_name.name);
+}
+
 #endif	/* __LINUX_DCACHE_H */
diff --git a/include/linux/ext2_fs_sb.h b/include/linux/ext2_fs_sb.h
index f273415..54ef185 100644
--- a/include/linux/ext2_fs_sb.h
+++ b/include/linux/ext2_fs_sb.h
@@ -106,6 +106,7 @@ struct ext2_sb_info {
 	spinlock_t s_rsv_window_lock;
 	struct rb_root s_rsv_window_root;
 	struct ext2_reserve_window_node s_rsv_window_head;
+	struct list_head delete;
 };
 
 #endif	/* _LINUX_EXT2_FS_SB */
diff --git a/fs/dcache.c b/fs/dcache.c
index 94b3656..a61d7ab 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -973,6 +973,7 @@ void d_instantiate(struct dentry *entry, struct inode * inode)
 	if (inode)
 		list_add(&entry->d_alias, &inode->i_dentry);
 	entry->d_inode = inode;
+	entry->d_flags &= ~DCACHE_HIDDEN;
 	fsnotify_d_instantiate(entry, inode);
 	spin_unlock(&dcache_lock);
 	security_d_instantiate(entry, inode);
@@ -1024,6 +1025,7 @@ static struct dentry *__d_instantiate_unique(struct dentry *entry,
 
 	list_add(&entry->d_alias, &inode->i_dentry);
 	entry->d_inode = inode;
+	entry->d_flags &= ~DCACHE_HIDDEN;
 	fsnotify_d_instantiate(entry, inode);
 	return NULL;
 }
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 06b5d05..5bb64af 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -286,23 +286,20 @@ int ext2_flush_dir(struct dentry *dir)
 		next = next->next;
 		spin_lock(&dentry->d_lock);
 		if (d_negative(dentry)) {
-			if ((dentry->d_flags & DCACHE_HIDDEN)) {
-				dentry->d_flags &= ~DCACHE_HIDDEN;
-				show_dentry("drop hidden dentry", dentry);
-				if ((dentry->d_flags & DCACHE_BACKED)) {
-					dentry->d_flags &= ~DCACHE_BACKED;
-					show_dentry("deferred unlink", dentry);
-					spin_unlock(&dentry->d_lock);
-					spin_unlock(&dcache_lock);
-					ext2_unlink_deferred(dir->d_inode, dentry);
-				} else {
-					spin_unlock(&dentry->d_lock);
-					spin_unlock(&dcache_lock);
-				}
-				d_delete(dentry);
+			show_dentry("drop hidden dentry", dentry);
+			if ((dentry->d_flags & DCACHE_BACKED)) {
+				dentry->d_flags &= ~DCACHE_BACKED;
+				show_dentry("deferred unlink", dentry);
+				spin_unlock(&dentry->d_lock);
+				spin_unlock(&dcache_lock);
+				ext2_unlink_deferred(dir->d_inode, dentry);
+				if (dentry->d_inode)
+					d_delete(dentry);
 				dput(dentry);
 				spin_lock(&dcache_lock);
+				continue;
 			}
+			spin_unlock(&dentry->d_lock);
 		}
 	}
 	spin_unlock(&dcache_lock);
diff --git a/fs/namei.c b/fs/namei.c
index f4eae06..a9d103b 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1526,6 +1526,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
 static inline int may_create(struct inode *dir, struct dentry *child,
 			     struct nameidata *nd)
 {
+printk("--- dentry %p negative %i\n", child, d_negative(child));
 	if (!d_negative(child))
 		return -EEXIST;
 	if (IS_DEADDIR(dir))
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index c434d8d..e05eaca 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -176,9 +176,10 @@ d_iput:		no		no		no       yes
 #define DCACHE_UNHASHED		0x0010	
 
 #define DCACHE_INOTIFY_PARENT_WATCHED	0x0020 /* Parent inode is watched */
+
 #define DCACHE_HIDDEN		0x0020 /* Unlinked but referenced by an open file */
 #define DCACHE_BACKED		0x0040 /* FS has dirent */
-#define DCACHE_WRONG		0x0080 /* FS has wrong dirent */
+#define DCACHE_STALE		0x0080 /* FS has wrong dirent */
 
 extern spinlock_t dcache_lock;
 extern seqlock_t rename_lock;
_______________________________________________
Tux3 mailing list
[email protected]
http://mailman.tux3.org/cgi-bin/mailman/listinfo/tux3

Reply via email to