diff options
author | Emmanuel Dreyfus <manu@netbsd.org> | 2014-09-29 03:06:24 +0200 |
---|---|---|
committer | Vijay Bellur <vbellur@redhat.com> | 2014-09-30 09:40:36 -0700 |
commit | c65d4ea8a10a4004cab145aaea0362e03b209267 (patch) | |
tree | 9ee15019ebaca48c46ffd7af4cbf5efb50a1d242 /xlators/storage | |
parent | 36d2975714ed6ef98c0f86a2fac22fc382ea8a9d (diff) |
Fix invalid seekdir() usage
According to POSIX, seekdir() should only be given offset obtained from
telldir() on the same DIR *
http://pubs.opengroup.org/onlinepubs/9699919799/functions/seekdir.html
Code from afr-self-heald.c and index.c is operating outside of the
specification, by doing using seekdir() with offset from a previously
open/close/re-open directory. This seems to work on Linux (although with
no guarantee it will always in the future). On NetBSD the seekdir()
with a in invalid offset is a nilpotent operation, and causes an infinite
loop, since index_fill_readdir() always restart from the beginning of the
directory.
The situation is fixed by using a non anonymous fd in afr-self-heald.c:
we explicitely open the directory so that it remains open on the brick
side during the timeframe where we want to reuse offsets in seekdir().
This requires adding an opendir fop in index xlator.
If the brick was not updated, the opendir will fail and we fallback
to the standard violating approach for backward compatibility on Linux.
On other systems we fail since it never worked.
While there, add tests to check seekdir() success in index and posix
xlators, so that incorrect usage from calling code produce an explicit
error instead of an infinite loop. We can only do it on non Linux systems,
for the sake of backward compatibility when the brick was updated but
not the client.
BUG: 1129939
Change-Id: I88ca90acfcfee280988124bd6addc1a1893ca7ab
Signed-off-by: Emmanuel Dreyfus <manu@netbsd.org>
Reviewed-on: http://review.gluster.org/8760
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Pranith Kumar Karampuri <pkarampu@redhat.com>
Reviewed-by: Vijay Bellur <vbellur@redhat.com>
Diffstat (limited to 'xlators/storage')
-rw-r--r-- | xlators/storage/posix/src/posix.c | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/xlators/storage/posix/src/posix.c b/xlators/storage/posix/src/posix.c index 43bd3fc1cfd..e830a973b76 100644 --- a/xlators/storage/posix/src/posix.c +++ b/xlators/storage/posix/src/posix.c @@ -4842,6 +4842,17 @@ posix_fill_readdir (fd_t *fd, DIR *dir, off_t off, size_t size, rewinddir (dir); } else { seekdir (dir, off); +#ifndef GF_LINUX_HOST_OS + if (telldir(dir) != off) { + gf_log (THIS->name, GF_LOG_ERROR, + "seekdir(%ld) failed on dir=%p: " + "Invalid argument (offset reused from " + "another DIR * structure?)", (long)off, dir); + errno = EINVAL; + count = -1; + goto out; + } +#endif /* GF_LINUX_HOST_OS */ } while (filled <= size) { @@ -4904,6 +4915,18 @@ posix_fill_readdir (fd_t *fd, DIR *dir, off_t off, size_t size, if (this_size + filled > size) { seekdir (dir, in_case); +#ifndef GF_LINUX_HOST_OS + if (telldir(dir) != in_case) { + gf_log (THIS->name, GF_LOG_ERROR, + "seekdir(%ld) failed on dir=%p: " + "Invalid argument (offset reused from " + "another DIR * structure?)", + (long)in_case, dir); + errno = EINVAL; + count = -1; + goto out; + } +#endif /* GF_LINUX_HOST_OS */ break; } |