From ca3e5905ac02fb9c373ac3de10b44f061d04cd6f Mon Sep 17 00:00:00 2001 From: Mohit Agrawal Date: Sun, 20 Oct 2019 22:01:01 +0530 Subject: posix: Avoid diskpace error in case of overwriting the data Problem: Sometime fops like posix_writev, posix_fallocate, posix_zerofile failed and throw error ENOSPC if storage.reserve threshold limit has reached even fops is overwriting the data Solution: Retry the fops in case of overwrite if diskspace check is failed Credits: kinsu Change-Id: I987d73bcf47ed1bb27878df40c39751296e95fe8 Updates: #745 Signed-off-by: Mohit Agrawal --- xlators/storage/posix/src/posix-entry-ops.c | 1 - xlators/storage/posix/src/posix-inode-fd-ops.c | 141 ++++++++++++++++++++++--- 2 files changed, 125 insertions(+), 17 deletions(-) (limited to 'xlators/storage/posix') diff --git a/xlators/storage/posix/src/posix-entry-ops.c b/xlators/storage/posix/src/posix-entry-ops.c index 85bc7bb6a2d..aadc590b376 100644 --- a/xlators/storage/posix/src/posix-entry-ops.c +++ b/xlators/storage/posix/src/posix-entry-ops.c @@ -1632,7 +1632,6 @@ posix_rename(call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc, priv = this->private; VALIDATE_OR_GOTO(priv, out); - DISK_SPACE_CHECK_AND_GOTO(frame, priv, xdata, op_ret, op_errno, out); SET_FS_ID(frame->root->uid, frame->root->gid); MAKE_ENTRY_HANDLE(real_oldpath, par_oldpath, this, oldloc, NULL); diff --git a/xlators/storage/posix/src/posix-inode-fd-ops.c b/xlators/storage/posix/src/posix-inode-fd-ops.c index e5c51eee032..bd1279cabb1 100644 --- a/xlators/storage/posix/src/posix-inode-fd-ops.c +++ b/xlators/storage/posix/src/posix-inode-fd-ops.c @@ -698,6 +698,10 @@ posix_do_fallocate(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t flags, gf_boolean_t locked = _gf_false; posix_inode_ctx_t *ctx = NULL; struct posix_private *priv = NULL; + gf_boolean_t check_space_error = _gf_false; + struct stat statbuf = { + 0, + }; DECLARE_OLD_FS_ID_VAR; @@ -717,7 +721,10 @@ posix_do_fallocate(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t flags, if (priv->disk_reserve) posix_disk_space_check(this); - DISK_SPACE_CHECK_AND_GOTO(frame, priv, xdata, ret, ret, out); + DISK_SPACE_CHECK_AND_GOTO(frame, priv, xdata, ret, ret, unlock); + +overwrite: + check_space_error = _gf_true; ret = posix_fd_ctx_get(fd, this, &pfd, &op_errno); if (ret < 0) { @@ -741,7 +748,7 @@ posix_do_fallocate(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t flags, ret = -errno; gf_msg(this->name, GF_LOG_ERROR, errno, P_MSG_FSTAT_FAILED, "fallocate (fstat) failed on fd=%p", fd); - goto out; + goto unlock; } if (xdata) { @@ -751,7 +758,7 @@ posix_do_fallocate(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t flags, gf_msg(this->name, GF_LOG_ERROR, 0, 0, "file state check failed, fd %p", fd); ret = -EIO; - goto out; + goto unlock; } } @@ -762,7 +769,7 @@ posix_do_fallocate(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t flags, "fallocate failed on %s offset: %jd, " "len:%zu, flags: %d", uuid_utoa(fd->inode->gfid), offset, len, flags); - goto out; + goto unlock; } ret = posix_fdstat(this, fd->inode, pfd->fd, statpost); @@ -770,16 +777,47 @@ posix_do_fallocate(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t flags, ret = -errno; gf_msg(this->name, GF_LOG_ERROR, errno, P_MSG_FSTAT_FAILED, "fallocate (fstat) failed on fd=%p", fd); - goto out; + goto unlock; } posix_set_ctime(frame, this, NULL, pfd->fd, fd->inode, statpost); -out: +unlock: if (locked) { pthread_mutex_unlock(&ctx->write_atomic_lock); locked = _gf_false; } + + if (op_errno == ENOSPC && priv->disk_space_full && !check_space_error) { +#ifdef FALLOC_FL_KEEP_SIZE + if (flags & FALLOC_FL_KEEP_SIZE) { + goto overwrite; + } +#endif + ret = posix_fd_ctx_get(fd, this, &pfd, &op_errno); + if (ret < 0) { + gf_msg(this->name, GF_LOG_WARNING, ret, P_MSG_PFD_NULL, + "pfd is NULL from fd=%p", fd); + goto out; + } + + if (sys_fstat(pfd->fd, &statbuf) < 0) { + gf_msg(this->name, GF_LOG_WARNING, op_errno, P_MSG_FILE_OP_FAILED, + "%d", pfd->fd); + goto out; + } + + if (offset + len <= statbuf.st_size) { + gf_msg_debug(this->name, 0, + "io vector size will not" + " change disk size so allow overwrite for" + " fd %d", + pfd->fd); + goto overwrite; + } + } + +out: SET_TO_OLD_FS_ID(); if (ret == ENOSPC) ret = -ENOSPC; @@ -1089,25 +1127,57 @@ posix_zerofill(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, int op_ret = -1; int op_errno = EINVAL; dict_t *rsp_xdata = NULL; + gf_boolean_t check_space_error = _gf_false; + struct posix_fd *pfd = NULL; + struct stat statbuf = { + 0, + }; - VALIDATE_OR_GOTO(frame, out); - VALIDATE_OR_GOTO(this, out); + VALIDATE_OR_GOTO(frame, unwind); + VALIDATE_OR_GOTO(this, unwind); priv = this->private; DISK_SPACE_CHECK_AND_GOTO(frame, priv, xdata, op_ret, op_errno, out); +overwrite: + check_space_error = _gf_true; ret = posix_do_zerofill(frame, this, fd, offset, len, &statpre, &statpost, xdata, &rsp_xdata); if (ret < 0) { op_ret = -1; op_errno = -ret; - goto out; + goto unwind; } STACK_UNWIND_STRICT(zerofill, frame, 0, 0, &statpre, &statpost, rsp_xdata); return 0; out: + if (op_errno == ENOSPC && priv->disk_space_full && !check_space_error) { + ret = posix_fd_ctx_get(fd, this, &pfd, &op_errno); + if (ret < 0) { + gf_msg(this->name, GF_LOG_WARNING, ret, P_MSG_PFD_NULL, + "pfd is NULL from fd=%p", fd); + goto out; + } + + if (sys_fstat(pfd->fd, &statbuf) < 0) { + gf_msg(this->name, GF_LOG_WARNING, op_errno, P_MSG_FILE_OP_FAILED, + "%d", pfd->fd); + goto out; + } + + if (offset + len <= statbuf.st_size) { + gf_msg_debug(this->name, 0, + "io vector size will not" + " change disk size so allow overwrite for" + " fd %d", + pfd->fd); + goto overwrite; + } + } + +unwind: STACK_UNWIND_STRICT(zerofill, frame, op_ret, op_errno, NULL, NULL, rsp_xdata); return 0; @@ -1872,19 +1942,28 @@ posix_writev(call_frame_t *frame, xlator_t *this, fd_t *fd, gf_boolean_t write_append = _gf_false; gf_boolean_t update_atomic = _gf_false; posix_inode_ctx_t *ctx = NULL; + gf_boolean_t check_space_error = _gf_false; + struct stat statbuf = { + 0, + }; + int totlen = 0; + int idx = 0; - VALIDATE_OR_GOTO(frame, out); - VALIDATE_OR_GOTO(this, out); - VALIDATE_OR_GOTO(fd, out); - VALIDATE_OR_GOTO(fd->inode, out); - VALIDATE_OR_GOTO(vector, out); - VALIDATE_OR_GOTO(this->private, out); + VALIDATE_OR_GOTO(frame, unwind); + VALIDATE_OR_GOTO(this, unwind); + VALIDATE_OR_GOTO(fd, unwind); + VALIDATE_OR_GOTO(fd->inode, unwind); + VALIDATE_OR_GOTO(vector, unwind); + VALIDATE_OR_GOTO(this->private, unwind); priv = this->private; - VALIDATE_OR_GOTO(priv, out); + VALIDATE_OR_GOTO(priv, unwind); DISK_SPACE_CHECK_AND_GOTO(frame, priv, xdata, op_ret, op_errno, out); +overwrite: + + check_space_error = _gf_true; if ((fd->inode->ia_type == IA_IFBLK) || (fd->inode->ia_type == IA_IFCHR)) { gf_msg(this->name, GF_LOG_ERROR, EINVAL, P_MSG_INVALID_ARGUMENT, "writev received on a block/char file (%s)", @@ -2026,6 +2105,36 @@ out: locked = _gf_false; } + if (op_errno == ENOSPC && priv->disk_space_full && !check_space_error) { + ret = posix_fd_ctx_get(fd, this, &pfd, &op_errno); + if (ret < 0) { + gf_msg(this->name, GF_LOG_WARNING, ret, P_MSG_PFD_NULL, + "pfd is NULL from fd=%p", fd); + goto unwind; + } + + if (sys_fstat(pfd->fd, &statbuf) < 0) { + gf_msg(this->name, GF_LOG_WARNING, op_errno, P_MSG_FILE_OP_FAILED, + "%d", pfd->fd); + goto unwind; + } + + for (idx = 0; idx < count; idx++) { + totlen = vector[idx].iov_len; + } + + if ((offset + totlen <= statbuf.st_size) && + !(statbuf.st_blocks * statbuf.st_blksize < statbuf.st_size)) { + gf_msg_debug(this->name, 0, + "io vector size will not" + " change disk size so allow overwrite for" + " fd %d", + pfd->fd); + goto overwrite; + } + } + +unwind: STACK_UNWIND_STRICT(writev, frame, op_ret, op_errno, &preop, &postop, rsp_xdata); -- cgit