ocfs2: Optionally return filldir errors

Modify ocfs2_dir_foreach_blk() to optionally return any error from the
filldir callback. This way ocfs2_dirforeach() can terminate early, as
opposed to always passing through the entire directory. This fixes a bug
introduced during a previous code refactor where ocfs2_empty_dir() would
loop infinitely.

Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index e153513..7453b70 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -588,7 +588,7 @@
 static int ocfs2_dir_foreach_blk_id(struct inode *inode,
 				    unsigned long *f_version,
 				    loff_t *f_pos, void *priv,
-				    filldir_t filldir)
+				    filldir_t filldir, int *filldir_err)
 {
 	int ret, i, filldir_ret;
 	unsigned long offset = *f_pos;
@@ -659,8 +659,11 @@
 					      *f_pos,
 					      le64_to_cpu(de->inode),
 					      d_type);
-			if (filldir_ret)
+			if (filldir_ret) {
+				if (filldir_err)
+					*filldir_err = filldir_ret;
 				break;
+			}
 			if (version != *f_version)
 				goto revalidate;
 		}
@@ -676,7 +679,7 @@
 static int ocfs2_dir_foreach_blk_el(struct inode *inode,
 				    unsigned long *f_version,
 				    loff_t *f_pos, void *priv,
-				    filldir_t filldir)
+				    filldir_t filldir, int *filldir_err)
 {
 	int error = 0;
 	unsigned long offset, blk, last_ra_blk = 0;
@@ -775,8 +778,11 @@
 						*f_pos,
 						le64_to_cpu(de->inode),
 						d_type);
-				if (error)
+				if (error) {
+					if (filldir_err)
+						*filldir_err = error;
 					break;
+				}
 				if (version != *f_version)
 					goto revalidate;
 				stored ++;
@@ -793,13 +799,15 @@
 }
 
 static int ocfs2_dir_foreach_blk(struct inode *inode, unsigned long *f_version,
-				 loff_t *f_pos, void *priv, filldir_t filldir)
+				 loff_t *f_pos, void *priv, filldir_t filldir,
+				 int *filldir_err)
 {
 	if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
 		return ocfs2_dir_foreach_blk_id(inode, f_version, f_pos, priv,
-						filldir);
+						filldir, filldir_err);
 
-	return ocfs2_dir_foreach_blk_el(inode, f_version, f_pos, priv, filldir);
+	return ocfs2_dir_foreach_blk_el(inode, f_version, f_pos, priv, filldir,
+					filldir_err);
 }
 
 /*
@@ -809,16 +817,19 @@
 int ocfs2_dir_foreach(struct inode *inode, loff_t *f_pos, void *priv,
 		      filldir_t filldir)
 {
-	int ret = 0;
+	int ret = 0, filldir_err = 0;
 	unsigned long version = inode->i_version;
 
 	while (*f_pos < i_size_read(inode)) {
 		ret = ocfs2_dir_foreach_blk(inode, &version, f_pos, priv,
-					    filldir);
-		if (ret)
+					    filldir, &filldir_err);
+		if (ret || filldir_err)
 			break;
 	}
 
+	if (ret > 0)
+		ret = -EIO;
+
 	return 0;
 }
 
@@ -852,7 +863,7 @@
 	}
 
 	error = ocfs2_dir_foreach_blk(inode, &filp->f_version, &filp->f_pos,
-				      dirent, filldir);
+				      dirent, filldir, NULL);
 
 	ocfs2_meta_unlock(inode, lock_level);