diff mbox

jfs: fix readdir cookie incompatibility with NFSv4

Message ID 520D3EA7.1010109@oracle.com (mailing list archive)
State New, archived
Headers show

Commit Message

Dave Kleikamp Aug. 15, 2013, 8:48 p.m. UTC
This patch replaces the one I posted yesterday. I like this better since
it doesn't require fixing existing on-disk cookies or skipping a
position in the in-inode index table.

NFSv4 reserves readdir cookie values 0-2 for special entries (. and ..),
but jfs allows a value of 2 for a non-special entry. This incompatibility
can result in the nfs client reporting a readdir loop.

This patch doesn't change the value stored internally, but adds one to
the value exposed to the iterate method.

Signed-off-by: Dave Kleikamp <dave.kleikamp@oracle.com>
---
 fs/jfs/jfs_dtree.c | 31 +++++++++++++++++++++++--------
 1 file changed, 23 insertions(+), 8 deletions(-)

Comments

Christian Kujau Aug. 15, 2013, 9:26 p.m. UTC | #1
On Thu, 15 Aug 2013 at 15:48, Dave Kleikamp wrote:
> This patch replaces the one I posted yesterday. I like this better since
> it doesn't require fixing existing on-disk cookies or skipping a
> position in the in-inode index table.

Thanks. Applied to 3.11-rc5 and tested, no more "readdir loop" messages 
and with unique inode numbers, great!

  Tested-by: Christian Kujau <lists@nerdbynature.de>

Thanks for the fix!
Christian.
Dave Kleikamp Aug. 15, 2013, 10:09 p.m. UTC | #2
On 08/15/2013 04:26 PM, Christian Kujau wrote:
> On Thu, 15 Aug 2013 at 15:48, Dave Kleikamp wrote:
>> This patch replaces the one I posted yesterday. I like this better since
>> it doesn't require fixing existing on-disk cookies or skipping a
>> position in the in-inode index table.
> 
> Thanks. Applied to 3.11-rc5 and tested, no more "readdir loop" messages 
> and with unique inode numbers, great!
> 
>   Tested-by: Christian Kujau <lists@nerdbynature.de>
> 
> Thanks for the fix!
> Christian.

Thanks for reporting, investigating and testing!

Dave

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Christian Kujau Aug. 24, 2013, 10:21 p.m. UTC | #3
On Thu, 15 Aug 2013 at 15:48, Dave Kleikamp wrote:
> This patch replaces the one I posted yesterday. I like this better since
> it doesn't require fixing existing on-disk cookies or skipping a
> position in the in-inode index table.
> 
> NFSv4 reserves readdir cookie values 0-2 for special entries (. and ..),
> but jfs allows a value of 2 for a non-special entry. This incompatibility
> can result in the nfs client reporting a readdir loop.
> 
> This patch doesn't change the value stored internally, but adds one to
> the value exposed to the iterate method.

Out of curiosity, will this land on 3.11?

Christian.
Dave Kleikamp Aug. 26, 2013, 10:27 p.m. UTC | #4
On 08/24/2013 05:21 PM, Christian Kujau wrote:
> On Thu, 15 Aug 2013 at 15:48, Dave Kleikamp wrote:
>> This patch replaces the one I posted yesterday. I like this better since
>> it doesn't require fixing existing on-disk cookies or skipping a
>> position in the in-inode index table.
>>
>> NFSv4 reserves readdir cookie values 0-2 for special entries (. and ..),
>> but jfs allows a value of 2 for a non-special entry. This incompatibility
>> can result in the nfs client reporting a readdir loop.
>>
>> This patch doesn't change the value stored internally, but adds one to
>> the value exposed to the iterate method.
> 
> Out of curiosity, will this land on 3.11?

Just sent a pull request to Linus. Once it's picked up, I'll submit a
patch to the stable trees.
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
index 8743ba9..0ec767e 100644
--- a/fs/jfs/jfs_dtree.c
+++ b/fs/jfs/jfs_dtree.c
@@ -3047,6 +3047,14 @@  int jfs_readdir(struct file *file, struct dir_context *ctx)
 
 		dir_index = (u32) ctx->pos;
 
+		/*
+		 * NFSv4 reserves cookies 1 and 2 for . and .. so we add
+		 * the value we return to the vfs is one greater than the
+		 * one we use internally.
+		 */
+		if (dir_index)
+			dir_index--;
+
 		if (dir_index > 1) {
 			struct dir_table_slot dirtab_slot;
 
@@ -3086,7 +3094,7 @@  int jfs_readdir(struct file *file, struct dir_context *ctx)
 			if (p->header.flag & BT_INTERNAL) {
 				jfs_err("jfs_readdir: bad index table");
 				DT_PUTPAGE(mp);
-				ctx->pos = -1;
+				ctx->pos = DIREND;
 				return 0;
 			}
 		} else {
@@ -3094,14 +3102,14 @@  int jfs_readdir(struct file *file, struct dir_context *ctx)
 				/*
 				 * self "."
 				 */
-				ctx->pos = 0;
+				ctx->pos = 1;
 				if (!dir_emit(ctx, ".", 1, ip->i_ino, DT_DIR))
 					return 0;
 			}
 			/*
 			 * parent ".."
 			 */
-			ctx->pos = 1;
+			ctx->pos = 2;
 			if (!dir_emit(ctx, "..", 2, PARENT(ip), DT_DIR))
 				return 0;
 
@@ -3122,22 +3130,23 @@  int jfs_readdir(struct file *file, struct dir_context *ctx)
 		/*
 		 * Legacy filesystem - OS/2 & Linux JFS < 0.3.6
 		 *
-		 * pn = index = 0:	First entry "."
-		 * pn = 0; index = 1:	Second entry ".."
+		 * pn = 0; index = 1:	First entry "."
+		 * pn = 0; index = 2:	Second entry ".."
 		 * pn > 0:		Real entries, pn=1 -> leftmost page
 		 * pn = index = -1:	No more entries
 		 */
 		dtpos = ctx->pos;
-		if (dtpos == 0) {
+		if (dtpos < 2) {
 			/* build "." entry */
+			ctx->pos = 1;
 			if (!dir_emit(ctx, ".", 1, ip->i_ino, DT_DIR))
 				return 0;
-			dtoffset->index = 1;
+			dtoffset->index = 2;
 			ctx->pos = dtpos;
 		}
 
 		if (dtoffset->pn == 0) {
-			if (dtoffset->index == 1) {
+			if (dtoffset->index == 2) {
 				/* build ".." entry */
 				if (!dir_emit(ctx, "..", 2, PARENT(ip), DT_DIR))
 					return 0;
@@ -3228,6 +3237,12 @@  int jfs_readdir(struct file *file, struct dir_context *ctx)
 					}
 					jfs_dirent->position = unique_pos++;
 				}
+				/*
+				 * We add 1 to the index because we may
+				 * use a value of 2 internally, and NFSv4
+				 * doesn't like that.
+				 */
+				jfs_dirent->position++;
 			} else {
 				jfs_dirent->position = dtpos;
 				len = min(d_namleft, DTLHDRDATALEN_LEGACY);