| From 44512449c0ab368889dd13ae0031fba74ee7e1d2 Mon Sep 17 00:00:00 2001 |
| From: Dave Kleikamp <dave.kleikamp@oracle.com> |
| Date: Thu, 15 Aug 2013 15:36:49 -0500 |
| Subject: jfs: fix readdir cookie incompatibility with NFSv4 |
| |
| From: Dave Kleikamp <dave.kleikamp@oracle.com> |
| |
| commit 44512449c0ab368889dd13ae0031fba74ee7e1d2 upstream. |
| |
| 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> |
| [bwh: Backported to 3.2: |
| - Adjust context |
| - s/ctx->pos/filp->f_pos/] |
| Tested-by: Christian Kujau <lists@nerdbynature.de> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| fs/jfs/jfs_dtree.c | 31 +++++++++++++++++++++++-------- |
| 1 file changed, 23 insertions(+), 8 deletions(-) |
| |
| --- a/fs/jfs/jfs_dtree.c |
| +++ b/fs/jfs/jfs_dtree.c |
| @@ -3047,6 +3047,14 @@ int jfs_readdir(struct file *filp, void |
| |
| dir_index = (u32) filp->f_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 *filp, void |
| if (p->header.flag & BT_INTERNAL) { |
| jfs_err("jfs_readdir: bad index table"); |
| DT_PUTPAGE(mp); |
| - filp->f_pos = -1; |
| + filp->f_pos = DIREND; |
| return 0; |
| } |
| } else { |
| @@ -3094,7 +3102,7 @@ int jfs_readdir(struct file *filp, void |
| /* |
| * self "." |
| */ |
| - filp->f_pos = 0; |
| + filp->f_pos = 1; |
| if (filldir(dirent, ".", 1, 0, ip->i_ino, |
| DT_DIR)) |
| return 0; |
| @@ -3102,7 +3110,7 @@ int jfs_readdir(struct file *filp, void |
| /* |
| * parent ".." |
| */ |
| - filp->f_pos = 1; |
| + filp->f_pos = 2; |
| if (filldir(dirent, "..", 2, 1, PARENT(ip), DT_DIR)) |
| return 0; |
| |
| @@ -3123,24 +3131,25 @@ int jfs_readdir(struct file *filp, void |
| /* |
| * 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 = filp->f_pos; |
| - if (dtpos == 0) { |
| + if (dtpos < 2) { |
| /* build "." entry */ |
| |
| + filp->f_pos = 1; |
| if (filldir(dirent, ".", 1, filp->f_pos, ip->i_ino, |
| DT_DIR)) |
| return 0; |
| - dtoffset->index = 1; |
| + dtoffset->index = 2; |
| filp->f_pos = dtpos; |
| } |
| |
| if (dtoffset->pn == 0) { |
| - if (dtoffset->index == 1) { |
| + if (dtoffset->index == 2) { |
| /* build ".." entry */ |
| |
| if (filldir(dirent, "..", 2, filp->f_pos, |
| @@ -3233,6 +3242,12 @@ int jfs_readdir(struct file *filp, void |
| } |
| 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); |