diff options
author | Dave Kleikamp <dave.kleikamp@oracle.com> | 2013-08-15 16:36:49 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-09-08 01:09:57 -0400 |
commit | 192caed2bfb7072b7f364dc909b43fd7604b991d (patch) | |
tree | 0b646c2a1e2bdcc32717909b7a73188c0a6dc0ce | |
parent | 3508b9b01638a5e73fcf913213e4692680a86507 (diff) |
jfs: fix readdir cookie incompatibility with NFSv4
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>
-rw-r--r-- | fs/jfs/jfs_dtree.c | 31 |
1 files changed, 23 insertions, 8 deletions
diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c index 0ddbeceafc62..c450fdb3d78d 100644 --- a/fs/jfs/jfs_dtree.c +++ b/fs/jfs/jfs_dtree.c | |||
@@ -3047,6 +3047,14 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
3047 | 3047 | ||
3048 | dir_index = (u32) filp->f_pos; | 3048 | dir_index = (u32) filp->f_pos; |
3049 | 3049 | ||
3050 | /* | ||
3051 | * NFSv4 reserves cookies 1 and 2 for . and .. so we add | ||
3052 | * the value we return to the vfs is one greater than the | ||
3053 | * one we use internally. | ||
3054 | */ | ||
3055 | if (dir_index) | ||
3056 | dir_index--; | ||
3057 | |||
3050 | if (dir_index > 1) { | 3058 | if (dir_index > 1) { |
3051 | struct dir_table_slot dirtab_slot; | 3059 | struct dir_table_slot dirtab_slot; |
3052 | 3060 | ||
@@ -3086,7 +3094,7 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
3086 | if (p->header.flag & BT_INTERNAL) { | 3094 | if (p->header.flag & BT_INTERNAL) { |
3087 | jfs_err("jfs_readdir: bad index table"); | 3095 | jfs_err("jfs_readdir: bad index table"); |
3088 | DT_PUTPAGE(mp); | 3096 | DT_PUTPAGE(mp); |
3089 | filp->f_pos = -1; | 3097 | filp->f_pos = DIREND; |
3090 | return 0; | 3098 | return 0; |
3091 | } | 3099 | } |
3092 | } else { | 3100 | } else { |
@@ -3094,7 +3102,7 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
3094 | /* | 3102 | /* |
3095 | * self "." | 3103 | * self "." |
3096 | */ | 3104 | */ |
3097 | filp->f_pos = 0; | 3105 | filp->f_pos = 1; |
3098 | if (filldir(dirent, ".", 1, 0, ip->i_ino, | 3106 | if (filldir(dirent, ".", 1, 0, ip->i_ino, |
3099 | DT_DIR)) | 3107 | DT_DIR)) |
3100 | return 0; | 3108 | return 0; |
@@ -3102,7 +3110,7 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
3102 | /* | 3110 | /* |
3103 | * parent ".." | 3111 | * parent ".." |
3104 | */ | 3112 | */ |
3105 | filp->f_pos = 1; | 3113 | filp->f_pos = 2; |
3106 | if (filldir(dirent, "..", 2, 1, PARENT(ip), DT_DIR)) | 3114 | if (filldir(dirent, "..", 2, 1, PARENT(ip), DT_DIR)) |
3107 | return 0; | 3115 | return 0; |
3108 | 3116 | ||
@@ -3123,24 +3131,25 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
3123 | /* | 3131 | /* |
3124 | * Legacy filesystem - OS/2 & Linux JFS < 0.3.6 | 3132 | * Legacy filesystem - OS/2 & Linux JFS < 0.3.6 |
3125 | * | 3133 | * |
3126 | * pn = index = 0: First entry "." | 3134 | * pn = 0; index = 1: First entry "." |
3127 | * pn = 0; index = 1: Second entry ".." | 3135 | * pn = 0; index = 2: Second entry ".." |
3128 | * pn > 0: Real entries, pn=1 -> leftmost page | 3136 | * pn > 0: Real entries, pn=1 -> leftmost page |
3129 | * pn = index = -1: No more entries | 3137 | * pn = index = -1: No more entries |
3130 | */ | 3138 | */ |
3131 | dtpos = filp->f_pos; | 3139 | dtpos = filp->f_pos; |
3132 | if (dtpos == 0) { | 3140 | if (dtpos < 2) { |
3133 | /* build "." entry */ | 3141 | /* build "." entry */ |
3134 | 3142 | ||
3143 | filp->f_pos = 1; | ||
3135 | if (filldir(dirent, ".", 1, filp->f_pos, ip->i_ino, | 3144 | if (filldir(dirent, ".", 1, filp->f_pos, ip->i_ino, |
3136 | DT_DIR)) | 3145 | DT_DIR)) |
3137 | return 0; | 3146 | return 0; |
3138 | dtoffset->index = 1; | 3147 | dtoffset->index = 2; |
3139 | filp->f_pos = dtpos; | 3148 | filp->f_pos = dtpos; |
3140 | } | 3149 | } |
3141 | 3150 | ||
3142 | if (dtoffset->pn == 0) { | 3151 | if (dtoffset->pn == 0) { |
3143 | if (dtoffset->index == 1) { | 3152 | if (dtoffset->index == 2) { |
3144 | /* build ".." entry */ | 3153 | /* build ".." entry */ |
3145 | 3154 | ||
3146 | if (filldir(dirent, "..", 2, filp->f_pos, | 3155 | if (filldir(dirent, "..", 2, filp->f_pos, |
@@ -3233,6 +3242,12 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
3233 | } | 3242 | } |
3234 | jfs_dirent->position = unique_pos++; | 3243 | jfs_dirent->position = unique_pos++; |
3235 | } | 3244 | } |
3245 | /* | ||
3246 | * We add 1 to the index because we may | ||
3247 | * use a value of 2 internally, and NFSv4 | ||
3248 | * doesn't like that. | ||
3249 | */ | ||
3250 | jfs_dirent->position++; | ||
3236 | } else { | 3251 | } else { |
3237 | jfs_dirent->position = dtpos; | 3252 | jfs_dirent->position = dtpos; |
3238 | len = min(d_namleft, DTLHDRDATALEN_LEGACY); | 3253 | len = min(d_namleft, DTLHDRDATALEN_LEGACY); |