patch-2.4.0-test3 linux/fs/readdir.c

Next file: linux/fs/smbfs/dir.c
Previous file: linux/fs/ramfs/inode.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test2/linux/fs/readdir.c linux/fs/readdir.c
@@ -24,14 +24,23 @@
 	down(&inode->i_sem);
 	down(&inode->i_zombie);
 	res = -ENOENT;
-	if (!IS_DEADDIR(inode))
+	if (!IS_DEADDIR(inode)) {
+		lock_kernel();
 		res = file->f_op->readdir(file, buf, filler);
+		unlock_kernel();
+	}
 	up(&inode->i_zombie);
 	up(&inode->i_sem);
 out:
 	return res;
 }
 
+/*
+ * Directory is locked and all positive dentries in it are safe, since
+ * for ramfs-type trees they can't go away without unlink() or rmdir(),
+ * both impossible due to the lock on directory.
+ */
+
 int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
 {
 	int i;
@@ -52,28 +61,39 @@
 			filp->f_pos++;
 			/* fallthrough */
 		default: {
-			struct list_head *list = dentry->d_subdirs.next;
-
+			struct list_head *list;
 			int j = i-2;
+
+			spin_lock(&dcache_lock);
+			list = dentry->d_subdirs.next;
+
 			for (;;) {
-				if (list == &dentry->d_subdirs)
+				if (list == &dentry->d_subdirs) {
+					spin_unlock(&dcache_lock);
 					return 0;
+				}
 				if (!j)
 					break;
 				j--;
 				list = list->next;
 			}
 
-			do {
+			while(1) {
 				struct dentry *de = list_entry(list, struct dentry, d_child);
 
-				if (!d_unhashed(de) && de->d_inode) {
+				if (!list_empty(&de->d_hash) && de->d_inode) {
+					spin_unlock(&dcache_lock);
 					if (filldir(dirent, de->d_name.name, de->d_name.len, filp->f_pos, de->d_inode->i_ino) < 0)
 						break;
+					spin_lock(&dcache_lock);
 				}
 				filp->f_pos++;
 				list = list->next;
-			} while (list != &dentry->d_subdirs);
+				if (list != &dentry->d_subdirs)
+					continue;
+				spin_unlock(&dcache_lock);
+				break;
+			}
 		}
 	}
 	return 0;
@@ -135,11 +155,9 @@
 	buf.count = 0;
 	buf.dirent = dirent;
 
-	lock_kernel();
 	error = vfs_readdir(file, fillonedir, &buf);
 	if (error >= 0)
 		error = buf.count;
-	unlock_kernel();
 
 	fput(file);
 out:
@@ -207,7 +225,6 @@
 	buf.count = count;
 	buf.error = 0;
 
-	lock_kernel();
 	error = vfs_readdir(file, filldir, &buf);
 	if (error < 0)
 		goto out_putf;
@@ -219,7 +236,6 @@
 	}
 
 out_putf:
-	unlock_kernel();
 	fput(file);
 out:
 	return error;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)