aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorZach Brown <zab@redhat.com>2013-07-11 19:19:42 -0400
committerChris Mason <chris.mason@fusionio.com>2013-08-09 19:34:56 -0400
commitdb62efbbf883c099d44b0fafe18f8ad8f0396892 (patch)
treedacc595d4b9e32b1736c01efea0580ba6a153903 /fs
parentcfad392b22163eba71d882950e17d2c4d43b2bad (diff)
btrfs: don't loop on large offsets in readdir
When btrfs readdir() hits the last entry it sets the readdir offset to a huge value to stop buggy apps from breaking when the same name is returned by readdir() with concurrent rename()s. But unconditionally setting the offset to INT_MAX causes readdir() to loop returning any entries with offsets past INT_MAX. It only takes a few hours of constant file creation and removal to create entries past INT_MAX. So let's set the huge offset to LLONG_MAX if the last entry has already overflowed 32bit loff_t. Without large offsets behaviour is identical. With large offsets 64bit apps will work and 32bit apps will be no more broken than they currently are if they see large offsets. Signed-off-by: Zach Brown <zab@redhat.com> Signed-off-by: Josef Bacik <jbacik@fusionio.com> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/inode.c33
1 files changed, 25 insertions, 8 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index c72033ee6017..021694c08181 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -5170,14 +5170,31 @@ next:
5170 } 5170 }
5171 5171
5172 /* Reached end of directory/root. Bump pos past the last item. */ 5172 /* Reached end of directory/root. Bump pos past the last item. */
5173 if (key_type == BTRFS_DIR_INDEX_KEY) 5173 ctx->pos++;
5174 /* 5174
5175 * 32-bit glibc will use getdents64, but then strtol - 5175 /*
5176 * so the last number we can serve is this. 5176 * Stop new entries from being returned after we return the last
5177 */ 5177 * entry.
5178 ctx->pos = 0x7fffffff; 5178 *
5179 else 5179 * New directory entries are assigned a strictly increasing
5180 ctx->pos++; 5180 * offset. This means that new entries created during readdir
5181 * are *guaranteed* to be seen in the future by that readdir.
5182 * This has broken buggy programs which operate on names as
5183 * they're returned by readdir. Until we re-use freed offsets
5184 * we have this hack to stop new entries from being returned
5185 * under the assumption that they'll never reach this huge
5186 * offset.
5187 *
5188 * This is being careful not to overflow 32bit loff_t unless the
5189 * last entry requires it because doing so has broken 32bit apps
5190 * in the past.
5191 */
5192 if (key_type == BTRFS_DIR_INDEX_KEY) {
5193 if (ctx->pos >= INT_MAX)
5194 ctx->pos = LLONG_MAX;
5195 else
5196 ctx->pos = INT_MAX;
5197 }
5181nopos: 5198nopos:
5182 ret = 0; 5199 ret = 0;
5183err: 5200err: