diff options
| author | Dave Kleikamp <dave.kleikamp@oracle.com> | 2013-08-15 16:36:49 -0400 |
|---|---|---|
| committer | Dave Kleikamp <dave.kleikamp@oracle.com> | 2013-08-15 18:22:29 -0400 |
| commit | 44512449c0ab368889dd13ae0031fba74ee7e1d2 (patch) | |
| tree | 28ac7c89b26e2acacc00c850ac74e825333db72a | |
| parent | f1d6e17f540af37bb1891480143669ba7636c4cf (diff) | |
jfs: fix readdir cookie incompatibility with NFSv4
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>
Tested-by: Christian Kujau <lists@nerdbynature.de>
| -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 8743ba9c6742..984c2bbf4f61 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) | |||
| 3047 | 3047 | ||
| 3048 | dir_index = (u32) ctx->pos; | 3048 | dir_index = (u32) ctx->pos; |
| 3049 | 3049 | ||
| 3050 | /* | ||
| 3051 | * NFSv4 reserves cookies 1 and 2 for . and .. so the value | ||
| 3052 | * we return to the vfs is one greater than the one we use | ||
| 3053 | * 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 *file, struct dir_context *ctx) | |||
| 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 | ctx->pos = -1; | 3097 | ctx->pos = DIREND; |
| 3090 | return 0; | 3098 | return 0; |
| 3091 | } | 3099 | } |
| 3092 | } else { | 3100 | } else { |
| @@ -3094,14 +3102,14 @@ int jfs_readdir(struct file *file, struct dir_context *ctx) | |||
| 3094 | /* | 3102 | /* |
| 3095 | * self "." | 3103 | * self "." |
| 3096 | */ | 3104 | */ |
| 3097 | ctx->pos = 0; | 3105 | ctx->pos = 1; |
| 3098 | if (!dir_emit(ctx, ".", 1, ip->i_ino, DT_DIR)) | 3106 | if (!dir_emit(ctx, ".", 1, ip->i_ino, DT_DIR)) |
| 3099 | return 0; | 3107 | return 0; |
| 3100 | } | 3108 | } |
| 3101 | /* | 3109 | /* |
| 3102 | * parent ".." | 3110 | * parent ".." |
| 3103 | */ | 3111 | */ |
| 3104 | ctx->pos = 1; | 3112 | ctx->pos = 2; |
| 3105 | if (!dir_emit(ctx, "..", 2, PARENT(ip), DT_DIR)) | 3113 | if (!dir_emit(ctx, "..", 2, PARENT(ip), DT_DIR)) |
| 3106 | return 0; | 3114 | return 0; |
| 3107 | 3115 | ||
| @@ -3122,22 +3130,23 @@ int jfs_readdir(struct file *file, struct dir_context *ctx) | |||
| 3122 | /* | 3130 | /* |
| 3123 | * Legacy filesystem - OS/2 & Linux JFS < 0.3.6 | 3131 | * Legacy filesystem - OS/2 & Linux JFS < 0.3.6 |
| 3124 | * | 3132 | * |
| 3125 | * pn = index = 0: First entry "." | 3133 | * pn = 0; index = 1: First entry "." |
| 3126 | * pn = 0; index = 1: Second entry ".." | 3134 | * pn = 0; index = 2: Second entry ".." |
| 3127 | * pn > 0: Real entries, pn=1 -> leftmost page | 3135 | * pn > 0: Real entries, pn=1 -> leftmost page |
| 3128 | * pn = index = -1: No more entries | 3136 | * pn = index = -1: No more entries |
| 3129 | */ | 3137 | */ |
| 3130 | dtpos = ctx->pos; | 3138 | dtpos = ctx->pos; |
| 3131 | if (dtpos == 0) { | 3139 | if (dtpos < 2) { |
| 3132 | /* build "." entry */ | 3140 | /* build "." entry */ |
| 3141 | ctx->pos = 1; | ||
| 3133 | if (!dir_emit(ctx, ".", 1, ip->i_ino, DT_DIR)) | 3142 | if (!dir_emit(ctx, ".", 1, ip->i_ino, DT_DIR)) |
| 3134 | return 0; | 3143 | return 0; |
| 3135 | dtoffset->index = 1; | 3144 | dtoffset->index = 2; |
| 3136 | ctx->pos = dtpos; | 3145 | ctx->pos = dtpos; |
| 3137 | } | 3146 | } |
| 3138 | 3147 | ||
| 3139 | if (dtoffset->pn == 0) { | 3148 | if (dtoffset->pn == 0) { |
| 3140 | if (dtoffset->index == 1) { | 3149 | if (dtoffset->index == 2) { |
| 3141 | /* build ".." entry */ | 3150 | /* build ".." entry */ |
| 3142 | if (!dir_emit(ctx, "..", 2, PARENT(ip), DT_DIR)) | 3151 | if (!dir_emit(ctx, "..", 2, PARENT(ip), DT_DIR)) |
| 3143 | return 0; | 3152 | return 0; |
| @@ -3228,6 +3237,12 @@ int jfs_readdir(struct file *file, struct dir_context *ctx) | |||
| 3228 | } | 3237 | } |
| 3229 | jfs_dirent->position = unique_pos++; | 3238 | jfs_dirent->position = unique_pos++; |
| 3230 | } | 3239 | } |
| 3240 | /* | ||
| 3241 | * We add 1 to the index because we may | ||
| 3242 | * use a value of 2 internally, and NFSv4 | ||
| 3243 | * doesn't like that. | ||
| 3244 | */ | ||
| 3245 | jfs_dirent->position++; | ||
| 3231 | } else { | 3246 | } else { |
| 3232 | jfs_dirent->position = dtpos; | 3247 | jfs_dirent->position = dtpos; |
| 3233 | len = min(d_namleft, DTLHDRDATALEN_LEGACY); | 3248 | len = min(d_namleft, DTLHDRDATALEN_LEGACY); |
