From ea1039c177ec781506fdae01132a7a876620693f Mon Sep 17 00:00:00 2001 From: Krutika Dhananjay Date: Mon, 22 Jun 2015 17:06:07 +0530 Subject: storage/posix: Introduce flag instructing posix to perform prestat, writev and poststat atomically Backport of: http://review.gluster.org/11345 Change-Id: I0d7e3a851c744777083974ec4cdb01b08c23727b BUG: 1236271 Signed-off-by: Krutika Dhananjay Reviewed-on: http://review.gluster.org/11439 Tested-by: NetBSD Build System Tested-by: Gluster Build System Reviewed-by: Pranith Kumar Karampuri --- xlators/storage/posix/src/posix.c | 95 ++++++++++++++++++++++++--------------- 1 file changed, 58 insertions(+), 37 deletions(-) (limited to 'xlators/storage') diff --git a/xlators/storage/posix/src/posix.c b/xlators/storage/posix/src/posix.c index 42b1d0f112f..008fd004cdb 100644 --- a/xlators/storage/posix/src/posix.c +++ b/xlators/storage/posix/src/posix.c @@ -2830,6 +2830,8 @@ posix_writev (call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *rsp_xdata = NULL; int is_append = 0; gf_boolean_t locked = _gf_false; + gf_boolean_t write_append = _gf_false; + gf_boolean_t update_atomic = _gf_false; VALIDATE_OR_GOTO (frame, out); VALIDATE_OR_GOTO (this, out); @@ -2851,16 +2853,32 @@ posix_writev (call_frame_t *frame, xlator_t *this, fd_t *fd, _fd = pfd->fd; - if (xdata && dict_get (xdata, GLUSTERFS_WRITE_IS_APPEND)) { - /* The write_is_append check and write must happen - atomically. Else another write can overtake this - write after the check and get written earlier. + if (xdata) { + if (dict_get (xdata, GLUSTERFS_WRITE_IS_APPEND)) + write_append = _gf_true; + if (dict_get (xdata, GLUSTERFS_WRITE_UPDATE_ATOMIC)) + update_atomic = _gf_true; + } - So lock before preop-stat and unlock after write. - */ + /* The write_is_append check and write must happen + atomically. Else another write can overtake this + write after the check and get written earlier. + + So lock before preop-stat and unlock after write. + */ + + /* + * The update_atomic option is to instruct posix to do prestat, + * write and poststat atomically. This is to prevent any modification to + * ia_size and ia_blocks until poststat and the diff in their values + * between pre and poststat could be of use for some translators (shard + * as of today). + */ + + if (write_append || update_atomic) { locked = _gf_true; LOCK(&fd->inode->lock); - } + } op_ret = posix_fdstat (this, _fd, &preop); if (op_ret == -1) { @@ -2870,7 +2888,7 @@ posix_writev (call_frame_t *frame, xlator_t *this, fd_t *fd, goto out; } - if (locked) { + if (locked && write_append) { if (preop.ia_size == offset || (fd->flags & O_APPEND)) is_append = 1; } @@ -2878,7 +2896,7 @@ posix_writev (call_frame_t *frame, xlator_t *this, fd_t *fd, op_ret = __posix_writev (_fd, vector, count, offset, (pfd->flags & O_DIRECT)); - if (locked) { + if (locked && (!update_atomic)) { UNLOCK (&fd->inode->lock); locked = _gf_false; } @@ -2892,43 +2910,46 @@ posix_writev (call_frame_t *frame, xlator_t *this, fd_t *fd, goto out; } - LOCK (&priv->lock); - { - priv->write_value += op_ret; - } - UNLOCK (&priv->lock); + rsp_xdata = _fill_writev_xdata (fd, xdata, this, is_append); + /* writev successful, we also need to get the stat of + * the file we wrote to + */ - if (op_ret >= 0) { - rsp_xdata = _fill_writev_xdata (fd, xdata, this, is_append); - /* wiretv successful, we also need to get the stat of - * the file we wrote to - */ + ret = posix_fdstat (this, _fd, &postop); + if (ret == -1) { + op_ret = -1; + op_errno = errno; + gf_msg (this->name, GF_LOG_ERROR, errno, + P_MSG_FSTAT_FAILED, + "post-operation fstat failed on fd=%p", + fd); + goto out; + } - if (flags & (O_SYNC|O_DSYNC)) { - ret = fsync (_fd); - if (ret) { - gf_msg (this->name, GF_LOG_ERROR, errno, - P_MSG_WRITEV_FAILED, - "fsync() in writev on fd %d failed", - _fd); - op_ret = -1; - op_errno = errno; - goto out; - } - } + if (locked) { + UNLOCK (&fd->inode->lock); + locked = _gf_false; + } - ret = posix_fdstat (this, _fd, &postop); - if (ret == -1) { + if (flags & (O_SYNC|O_DSYNC)) { + ret = fsync (_fd); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, errno, + P_MSG_WRITEV_FAILED, + "fsync() in writev on fd %d failed", + _fd); op_ret = -1; op_errno = errno; - gf_msg (this->name, GF_LOG_ERROR, errno, - P_MSG_FSTAT_FAILED, - "post-operation fstat failed on fd=%p", - fd); goto out; } } + LOCK (&priv->lock); + { + priv->write_value += op_ret; + } + UNLOCK (&priv->lock); + out: if (locked) { -- cgit