From 22e18a4c0c07a41fcdcde1ce0e90961b347d7a84 Mon Sep 17 00:00:00 2001 From: Emmanuel Dreyfus Date: Tue, 14 Oct 2014 12:11:24 +0200 Subject: Avoid spurious EINVAL in posix_readdir() On non Linux systems, we check that seekdir() succeeds and we return EINVAL if it does not. We need this to avoid infinite loops if some other component in GlusterFS makes an invalid seekdir() usage. This was introduced in this change: http://review.gluster.org/#/c/8760/ But seekdir() also fails when using the offset returned for the last entry, and this is expected behavior. As a result, the seekdir() test produces a spurious EINVAL when reaching end of directory. That error is not propagated to calling process, but it may harm internal GlusterFS processing. At least it produce a spurious error message in brick's log. We fix the problem by remembering the last entry offset in fd private data. When a new posix_readdir() invocation requests that offset, we avoid returning EINVAL. BUG: 1129939 Change-Id: I4e67a2ea46538aae63eea663dd4aa33b16ad24c7 Signed-off-by: Emmanuel Dreyfus Reviewed-on: http://review.gluster.org/8926 Tested-by: Gluster Build System Reviewed-by: Raghavendra Bhat Reviewed-by: Vijay Bellur --- xlators/storage/posix/src/posix.c | 21 ++++++++++++++++++--- xlators/storage/posix/src/posix.h | 1 + 2 files changed, 19 insertions(+), 3 deletions(-) (limited to 'xlators') diff --git a/xlators/storage/posix/src/posix.c b/xlators/storage/posix/src/posix.c index 6b12d39df79..9f7fa0313cd 100644 --- a/xlators/storage/posix/src/posix.c +++ b/xlators/storage/posix/src/posix.c @@ -933,6 +933,7 @@ posix_opendir (call_frame_t *frame, xlator_t *this, } pfd->dir = dir; + pfd->dir_eof = -1; pfd->fd = dirfd (dir); op_ret = fd_ctx_set (fd, this, (uint64_t)(long)pfd); @@ -4845,12 +4846,22 @@ posix_fill_readdir (fd_t *fd, DIR *dir, off_t off, size_t size, struct dirent *entry = NULL; int32_t this_size = -1; gf_dirent_t *this_entry = NULL; + struct posix_fd *pfd = NULL; uuid_t rootgfid = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; struct stat stbuf = {0,}; char *hpath = NULL; int len = 0; int ret = 0; + ret = posix_fd_ctx_get (fd, this, &pfd); + if (ret < 0) { + gf_log (this->name, GF_LOG_WARNING, + "pfd is NULL, fd=%p", fd); + count = -1; + errno = -ret; + goto out; + } + if (skip_dirs) { len = posix_handle_path (this, fd->inode->gfid, NULL, NULL, 0); hpath = alloca (len + 256); /* NAME_MAX */ @@ -4864,7 +4875,7 @@ posix_fill_readdir (fd_t *fd, DIR *dir, off_t off, size_t size, } else { seekdir (dir, off); #ifndef GF_LINUX_HOST_OS - if (telldir(dir) != off) { + if (telldir(dir) != (long)off && off != pfd->dir_eof) { gf_log (THIS->name, GF_LOG_ERROR, "seekdir(%ld) failed on dir=%p: " "Invalid argument (offset reused from " @@ -4937,7 +4948,8 @@ 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) { + if (telldir(dir) != (long)in_case && + in_case != pfd->dir_eof) { gf_log (THIS->name, GF_LOG_ERROR, "seekdir(%ld) failed on dir=%p: " "Invalid argument (offset reused from " @@ -4969,9 +4981,12 @@ posix_fill_readdir (fd_t *fd, DIR *dir, off_t off, size_t size, count ++; } - if ((!readdir (dir) && (errno == 0))) + if ((!readdir (dir) && (errno == 0))) { /* Indicate EOF */ errno = ENOENT; + /* Remember EOF offset for later detection */ + pfd->dir_eof = telldir (dir); + } out: return count; } diff --git a/xlators/storage/posix/src/posix.h b/xlators/storage/posix/src/posix.h index 5bb5e873c82..870315d0ea2 100644 --- a/xlators/storage/posix/src/posix.h +++ b/xlators/storage/posix/src/posix.h @@ -68,6 +68,7 @@ struct posix_fd { int fd; /* fd returned by the kernel */ int32_t flags; /* flags for open/creat */ DIR * dir; /* handle returned by the kernel */ + off_t dir_eof; /* offset at dir EOF */ int odirect; struct list_head list; /* to add to the janitor list */ }; -- cgit