Commit 44512449c0ab368889dd13ae0031fba74ee7e1d2

Authored by Dave Kleikamp
1 parent f1d6e17f54

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>

Showing 1 changed file with 23 additions and 8 deletions Side-by-side Diff

... ... @@ -3047,6 +3047,14 @@
3047 3047  
3048 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 3058 if (dir_index > 1) {
3051 3059 struct dir_table_slot dirtab_slot;
3052 3060  
... ... @@ -3086,7 +3094,7 @@
3086 3094 if (p->header.flag & BT_INTERNAL) {
3087 3095 jfs_err("jfs_readdir: bad index table");
3088 3096 DT_PUTPAGE(mp);
3089   - ctx->pos = -1;
  3097 + ctx->pos = DIREND;
3090 3098 return 0;
3091 3099 }
3092 3100 } else {
3093 3101  
... ... @@ -3094,14 +3102,14 @@
3094 3102 /*
3095 3103 * self "."
3096 3104 */
3097   - ctx->pos = 0;
  3105 + ctx->pos = 1;
3098 3106 if (!dir_emit(ctx, ".", 1, ip->i_ino, DT_DIR))
3099 3107 return 0;
3100 3108 }
3101 3109 /*
3102 3110 * parent ".."
3103 3111 */
3104   - ctx->pos = 1;
  3112 + ctx->pos = 2;
3105 3113 if (!dir_emit(ctx, "..", 2, PARENT(ip), DT_DIR))
3106 3114 return 0;
3107 3115  
3108 3116  
3109 3117  
3110 3118  
3111 3119  
... ... @@ -3122,22 +3130,23 @@
3122 3130 /*
3123 3131 * Legacy filesystem - OS/2 & Linux JFS < 0.3.6
3124 3132 *
3125   - * pn = index = 0: First entry "."
3126   - * pn = 0; index = 1: Second entry ".."
  3133 + * pn = 0; index = 1: First entry "."
  3134 + * pn = 0; index = 2: Second entry ".."
3127 3135 * pn > 0: Real entries, pn=1 -> leftmost page
3128 3136 * pn = index = -1: No more entries
3129 3137 */
3130 3138 dtpos = ctx->pos;
3131   - if (dtpos == 0) {
  3139 + if (dtpos < 2) {
3132 3140 /* build "." entry */
  3141 + ctx->pos = 1;
3133 3142 if (!dir_emit(ctx, ".", 1, ip->i_ino, DT_DIR))
3134 3143 return 0;
3135   - dtoffset->index = 1;
  3144 + dtoffset->index = 2;
3136 3145 ctx->pos = dtpos;
3137 3146 }
3138 3147  
3139 3148 if (dtoffset->pn == 0) {
3140   - if (dtoffset->index == 1) {
  3149 + if (dtoffset->index == 2) {
3141 3150 /* build ".." entry */
3142 3151 if (!dir_emit(ctx, "..", 2, PARENT(ip), DT_DIR))
3143 3152 return 0;
... ... @@ -3228,6 +3237,12 @@
3228 3237 }
3229 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 3246 } else {
3232 3247 jfs_dirent->position = dtpos;
3233 3248 len = min(d_namleft, DTLHDRDATALEN_LEGACY);