patch-2.4.4 linux/fs/affs/dir.c

Next file: linux/fs/affs/file.c
Previous file: linux/fs/affs/bitmap.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.3/linux/fs/affs/dir.c linux/fs/affs/dir.c
@@ -13,7 +13,6 @@
  *
  */
 
-#define DEBUG 0
 #include <asm/uaccess.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -50,109 +49,115 @@
 static int
 affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
-	int			 j, namelen;
-	s32			 i;
+	struct inode		*inode = filp->f_dentry->d_inode;
+	struct super_block	*sb = inode->i_sb;
+	struct buffer_head	*dir_bh;
+	struct buffer_head	*fh_bh;
+	unsigned char		*name;
+	int			 namelen;
+	u32			 i;
 	int			 hash_pos;
 	int			 chain_pos;
-	unsigned long		 ino;
+	u32			 f_pos;
+	u32			 ino;
 	int			 stored;
-	unsigned char		*name;
-	struct buffer_head	*dir_bh;
-	struct buffer_head	*fh_bh;
-	struct inode		*dir;
-	struct inode		*inode = filp->f_dentry->d_inode;
+	int			 res;
 
-	pr_debug("AFFS: readdir(ino=%lu,f_pos=%lu)\n",inode->i_ino,(unsigned long)filp->f_pos);
+	pr_debug("AFFS: readdir(ino=%lu,f_pos=%lx)\n",inode->i_ino,(unsigned long)filp->f_pos);
 
 	stored = 0;
+	res    = -EIO;
 	dir_bh = NULL;
 	fh_bh  = NULL;
-	dir    = NULL;
-	ino    = inode->i_ino;
+	f_pos  = filp->f_pos;
 
-	if (filp->f_pos == 0) {
+	if (f_pos == 0) {
 		filp->private_data = (void *)0;
-		if (filldir(dirent,".",1,filp->f_pos,inode->i_ino,DT_DIR) < 0) {
+		if (filldir(dirent, ".", 1, f_pos, inode->i_ino, DT_DIR) < 0)
 			return 0;
-		}
-		++filp->f_pos;
+		filp->f_pos = f_pos = 1;
 		stored++;
 	}
-	if (filp->f_pos == 1) {
-		if (filldir(dirent,"..",2,filp->f_pos,affs_parent_ino(inode),DT_DIR) < 0) {
+	if (f_pos == 1) {
+		if (filldir(dirent, "..", 2, f_pos, filp->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
 			return stored;
-		}
-		filp->f_pos = 2;
+		filp->f_pos = f_pos = 2;
 		stored++;
 	}
-	chain_pos = (filp->f_pos - 2) & 0xffff;
-	hash_pos  = (filp->f_pos - 2) >> 16;
+
+	down(&AFFS_INODE->i_hash_lock);
+	chain_pos = (f_pos - 2) & 0xffff;
+	hash_pos  = (f_pos - 2) >> 16;
 	if (chain_pos == 0xffff) {
-		affs_warning(inode->i_sb,"readdir","More than 65535 entries in chain");
+		affs_warning(sb, "readdir", "More than 65535 entries in chain");
 		chain_pos = 0;
 		hash_pos++;
 		filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
 	}
-	if (!(dir_bh = affs_bread(inode->i_dev,inode->i_ino,
-				  AFFS_I2BSIZE(inode))))
-		goto readdir_done;
-
-	while (1) {
-		while (hash_pos < AFFS_I2HSIZE(inode) &&
-		     !((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos])
-			hash_pos++;
-		if (hash_pos >= AFFS_I2HSIZE(inode))
-			break;
-		
-		i = be32_to_cpu(((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos]);
-		j = chain_pos;
-
-		/* If the directory hasn't changed since the last call to readdir(),
-		 * we can jump directly to where we left off.
-		 */
-		if (filp->private_data && filp->f_version == inode->i_version) {
-			i = (s32)(unsigned long)filp->private_data;
-			j = 0;
-			pr_debug("AFFS: readdir() left off=%d\n",i);
+	dir_bh = affs_bread(sb, inode->i_ino);
+	if (!dir_bh)
+		goto readdir_out;
+
+	/* If the directory hasn't changed since the last call to readdir(),
+	 * we can jump directly to where we left off.
+	 */
+	ino = (u32)(long)filp->private_data;
+	if (ino && filp->f_version == inode->i_version) {
+		pr_debug("AFFS: readdir() left off=%d\n", ino);
+		goto inside;
+	}
+
+	ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]);
+	for (i = 0; ino && i < chain_pos; i++) {
+		fh_bh = affs_bread(sb, ino);
+		if (!fh_bh) {
+			affs_error(sb, "readdir","Cannot read block %d", i);
+			goto readdir_out;
 		}
-		filp->f_version = inode->i_version;
-		pr_debug("AFFS: hash_pos=%d chain_pos=%d\n",hash_pos,chain_pos);
-		while (i) {
-			if (!(fh_bh = affs_bread(inode->i_dev,i,AFFS_I2BSIZE(inode)))) {
-				affs_error(inode->i_sb,"readdir","Cannot read block %d",i);
+		ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
+		affs_brelse(fh_bh);
+		fh_bh = NULL;
+	}
+	if (ino)
+		goto inside;
+	hash_pos++;
+
+	for (; hash_pos < AFFS_SB->s_hashsize; hash_pos++) {
+		ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]);
+		if (!ino)
+			continue;
+		f_pos = (hash_pos << 16) + 2;
+inside:
+		do {
+			fh_bh = affs_bread(sb, ino);
+			if (!fh_bh) {
+				affs_error(sb, "readdir","Cannot read block %d", ino);
 				goto readdir_done;
 			}
-			ino = i;
-			i   = be32_to_cpu(FILE_END(fh_bh->b_data,inode)->hash_chain);
-			if (j == 0)
-				break;
-			affs_brelse(fh_bh);
-			fh_bh = NULL;
-			j--;
-		}
-		if (fh_bh) {
-			namelen = affs_get_file_name(AFFS_I2BSIZE(inode),fh_bh->b_data,&name);
-			pr_debug("AFFS: readdir(): filldir(\"%.*s\",ino=%lu), i=%d\n",
-				 namelen,name,ino,i);
-			filp->private_data = (void *)ino;
-			if (filldir(dirent,name,namelen,filp->f_pos,ino,DT_UNKNOWN) < 0)
+
+			namelen = MIN(AFFS_TAIL(sb, fh_bh)->name[0], 30);
+			name = AFFS_TAIL(sb, fh_bh)->name + 1;
+			pr_debug("AFFS: readdir(): filldir(\"%.*s\", ino=%u), hash=%d, f_pos=%x\n",
+				 namelen, name, ino, hash_pos, f_pos);
+			if (filldir(dirent, name, namelen, f_pos, ino, DT_UNKNOWN) < 0)
 				goto readdir_done;
-			filp->private_data = (void *)(unsigned long)i;
+			stored++;
+			f_pos++;
+			ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
 			affs_brelse(fh_bh);
 			fh_bh = NULL;
-			stored++;
-		}
-		if (i == 0) {
-			hash_pos++;
-			chain_pos = 0;
-		} else
-			chain_pos++;
-		filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
+		} while (ino);
 	}
-
 readdir_done:
+	filp->f_pos = f_pos;
+	filp->f_version = inode->i_version;
+	filp->private_data = (void *)(long)ino;
+	res = stored;
+
+readdir_out:
 	affs_brelse(dir_bh);
 	affs_brelse(fh_bh);
-	pr_debug("AFFS: readdir()=%d\n",stored);
-	return stored;
+	up(&AFFS_INODE->i_hash_lock);
+	pr_debug("AFFS: readdir()=%d\n", stored);
+	return res;
 }

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