diff options
Diffstat (limited to 'xlators/performance/open-behind')
-rw-r--r-- | xlators/performance/open-behind/src/open-behind-mem-types.h | 1 | ||||
-rw-r--r-- | xlators/performance/open-behind/src/open-behind.c | 396 |
2 files changed, 330 insertions, 67 deletions
diff --git a/xlators/performance/open-behind/src/open-behind-mem-types.h b/xlators/performance/open-behind/src/open-behind-mem-types.h index 1e94296f424..8ddd061a835 100644 --- a/xlators/performance/open-behind/src/open-behind-mem-types.h +++ b/xlators/performance/open-behind/src/open-behind-mem-types.h @@ -16,6 +16,7 @@ enum gf_ob_mem_types_ { gf_ob_mt_fd_t = gf_common_mt_end + 1, gf_ob_mt_conf_t, + gf_ob_mt_inode_t, gf_ob_mt_end }; #endif diff --git a/xlators/performance/open-behind/src/open-behind.c b/xlators/performance/open-behind/src/open-behind.c index 396bf29f40e..ec2be508bda 100644 --- a/xlators/performance/open-behind/src/open-behind.c +++ b/xlators/performance/open-behind/src/open-behind.c @@ -32,6 +32,16 @@ typedef struct ob_conf { */ } ob_conf_t; +typedef struct ob_inode { + inode_t *inode; + struct list_head resume_fops; + struct list_head ob_fds; + int count; + int op_ret; + int op_errno; + gf_boolean_t open_in_progress; + int unlinked; +} ob_inode_t; typedef struct ob_fd { call_frame_t *open_frame; @@ -39,9 +49,79 @@ typedef struct ob_fd { dict_t *xdata; int flags; int op_errno; + ob_inode_t *ob_inode; + fd_t *fd; + gf_boolean_t opened; + gf_boolean_t ob_inode_fops_waiting; struct list_head list; + struct list_head ob_fds_on_inode; } ob_fd_t; +ob_inode_t * +ob_inode_alloc (inode_t *inode) +{ + ob_inode_t *ob_inode = NULL; + + ob_inode = GF_CALLOC (1, sizeof (*ob_inode), gf_ob_mt_inode_t); + if (ob_inode == NULL) + goto out; + + ob_inode->inode = inode; + INIT_LIST_HEAD (&ob_inode->resume_fops); + INIT_LIST_HEAD (&ob_inode->ob_fds); +out: + return ob_inode; +} + +void +ob_inode_free (ob_inode_t *ob_inode) +{ + if (ob_inode == NULL) + goto out; + + list_del_init (&ob_inode->resume_fops); + list_del_init (&ob_inode->ob_fds); + + GF_FREE (ob_inode); +out: + return; +} + +ob_inode_t * +ob_inode_get (xlator_t *this, inode_t *inode) +{ + ob_inode_t *ob_inode = NULL; + uint64_t value = 0; + int ret = 0; + + if (!inode) + goto out; + + LOCK (&inode->lock); + { + __inode_ctx_get (inode, this, &value); + if (value == 0) { + ob_inode = ob_inode_alloc (inode); + if (ob_inode == NULL) + goto unlock; + + value = (uint64_t)((void *)ob_inode); + ret = __inode_ctx_set (inode, this, &value); + if (ret < 0) { + ob_inode_free (ob_inode); + ob_inode = NULL; + } + } else { + ob_inode = (ob_inode_t *) value; + } + } +unlock: + UNLOCK (&inode->lock); + +out: + return ob_inode; +} + ob_fd_t * __ob_fd_ctx_get (xlator_t *this, fd_t *fd) @@ -112,6 +192,7 @@ ob_fd_new (void) ob_fd = GF_CALLOC (1, sizeof (*ob_fd), gf_ob_mt_fd_t); INIT_LIST_HEAD (&ob_fd->list); + INIT_LIST_HEAD (&ob_fd->ob_fds_on_inode); return ob_fd; } @@ -120,6 +201,12 @@ ob_fd_new (void) void ob_fd_free (ob_fd_t *ob_fd) { + LOCK (&ob_fd->fd->inode->lock); + { + list_del_init (&ob_fd->ob_fds_on_inode); + } + UNLOCK (&ob_fd->fd->inode->lock); + loc_wipe (&ob_fd->loc); if (ob_fd->xdata) @@ -136,21 +223,32 @@ int ob_wake_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int op_ret, int op_errno, fd_t *fd_ret, dict_t *xdata) { - fd_t *fd = NULL; - struct list_head list; - ob_fd_t *ob_fd = NULL; - call_stub_t *stub = NULL, *tmp = NULL; + fd_t *fd = NULL; + int count = 0; + int ob_inode_op_ret = 0; + int ob_inode_op_errno = 0; + ob_fd_t *ob_fd = NULL; + call_stub_t *stub = NULL, *tmp = NULL; + ob_inode_t *ob_inode = NULL; + gf_boolean_t ob_inode_fops_waiting = _gf_false; + struct list_head fops_waiting_on_fd, fops_waiting_on_inode; fd = frame->local; frame->local = NULL; - INIT_LIST_HEAD (&list); + INIT_LIST_HEAD (&fops_waiting_on_fd); + INIT_LIST_HEAD (&fops_waiting_on_inode); + + ob_inode = ob_inode_get (this, fd->inode); LOCK (&fd->lock); { ob_fd = __ob_fd_ctx_get (this, fd); + ob_fd->opened = _gf_true; - list_splice_init (&ob_fd->list, &list); + ob_inode_fops_waiting = ob_fd->ob_inode_fops_waiting; + + list_splice_init (&ob_fd->list, &fops_waiting_on_fd); if (op_ret < 0) { /* mark fd BAD for ever */ @@ -162,10 +260,31 @@ ob_wake_cbk (call_frame_t *frame, void *cookie, xlator_t *this, } UNLOCK (&fd->lock); + if (ob_inode_fops_waiting) { + LOCK (&fd->inode->lock); + { + count = --ob_inode->count; + if (op_ret < 0) { + /* TODO: when to reset the error? */ + ob_inode->op_ret = -1; + ob_inode->op_errno = op_errno; + } + + if (count == 0) { + ob_inode->open_in_progress = _gf_false; + ob_inode_op_ret = ob_inode->op_ret; + ob_inode_op_errno = ob_inode->op_errno; + list_splice_init (&ob_inode->resume_fops, + &fops_waiting_on_inode); + } + } + UNLOCK (&fd->inode->lock); + } + if (ob_fd) ob_fd_free (ob_fd); - list_for_each_entry_safe (stub, tmp, &list, list) { + list_for_each_entry_safe (stub, tmp, &fops_waiting_on_fd, list) { list_del_init (&stub->list); if (op_ret < 0) @@ -174,6 +293,15 @@ ob_wake_cbk (call_frame_t *frame, void *cookie, xlator_t *this, call_resume (stub); } + list_for_each_entry_safe (stub, tmp, &fops_waiting_on_inode, list) { + list_del_init (&stub->list); + + if (ob_inode_op_ret < 0) + call_unwind_error (stub, -1, ob_inode_op_errno); + else + call_resume (stub); + } + fd_unref (fd); STACK_DESTROY (frame->root); @@ -183,22 +311,30 @@ ob_wake_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int -ob_fd_wake (xlator_t *this, fd_t *fd) +ob_fd_wake (xlator_t *this, fd_t *fd, ob_fd_t *ob_fd) { call_frame_t *frame = NULL; - ob_fd_t *ob_fd = NULL; - LOCK (&fd->lock); - { - ob_fd = __ob_fd_ctx_get (this, fd); - if (!ob_fd) - goto unlock; - - frame = ob_fd->open_frame; - ob_fd->open_frame = NULL; - } -unlock: - UNLOCK (&fd->lock); + if (ob_fd == NULL) { + LOCK (&fd->lock); + { + ob_fd = __ob_fd_ctx_get (this, fd); + if (!ob_fd) + goto unlock; + + frame = ob_fd->open_frame; + ob_fd->open_frame = NULL; + } + unlock: + UNLOCK (&fd->lock); + } else { + LOCK (&fd->lock); + { + frame = ob_fd->open_frame; + ob_fd->open_frame = NULL; + } + UNLOCK (&fd->lock); + } if (frame) { frame->local = fd_ref (fd); @@ -211,6 +347,108 @@ unlock: return 0; } +void +ob_inode_wake (xlator_t *this, struct list_head *ob_fds) +{ + ob_fd_t *ob_fd = NULL, *tmp = NULL; + fd_t *fd = NULL; + + list_for_each_entry_safe (ob_fd, tmp, ob_fds, ob_fds_on_inode) { + ob_fd_wake (this, ob_fd->fd, ob_fd); + fd = ob_fd->fd; + ob_fd_free (ob_fd); + fd_unref (fd); + } +} + +/* called holding inode->lock and fd->lock */ +void +ob_fd_copy (ob_fd_t *src, ob_fd_t *dst) +{ + if (!src || !dst) + goto out; + + dst->fd = __fd_ref (src->fd); + dst->loc.inode = inode_ref (src->loc.inode); + gf_uuid_copy (dst->loc.gfid, src->loc.gfid); + dst->flags = src->flags; + dst->xdata = dict_ref (src->xdata); + dst->ob_inode = src->ob_inode; +out: + return; +} + +int +open_all_pending_fds_and_resume (xlator_t *this, inode_t *inode, + call_stub_t *stub) +{ + ob_inode_t *ob_inode = NULL; + ob_fd_t *ob_fd = NULL, *tmp = NULL; + gf_boolean_t was_open_in_progress = _gf_false; + gf_boolean_t wait_for_open = _gf_false; + struct list_head ob_fds = {0, }; + + ob_inode = ob_inode_get (this, inode); + if (ob_inode == NULL) + goto out; + + INIT_LIST_HEAD (&ob_fds); + + LOCK (&inode->lock); + { + was_open_in_progress = ob_inode->open_in_progress; + ob_inode->unlinked = 1; + + if (was_open_in_progress) { + list_add_tail (&stub->list, &ob_inode->resume_fops); + goto inode_unlock; + } + + list_for_each_entry (ob_fd, &ob_inode->ob_fds, + ob_fds_on_inode) { + LOCK (&ob_fd->fd->lock); + { + if (ob_fd->opened) + goto fd_unlock; + + ob_inode->count++; + ob_fd->ob_inode_fops_waiting = _gf_true; + + if (ob_fd->open_frame == NULL) { + /* open in progress no need of wake */ + } else { + tmp = ob_fd_new (); + tmp->open_frame = ob_fd->open_frame; + ob_fd->open_frame = NULL; + + ob_fd_copy (ob_fd, tmp); + list_add_tail (&tmp->ob_fds_on_inode, + &ob_fds); + } + } + fd_unlock: + UNLOCK (&ob_fd->fd->lock); + } + + if (ob_inode->count) { + wait_for_open = ob_inode->open_in_progress = _gf_true; + list_add_tail (&stub->list, &ob_inode->resume_fops); + } + } +inode_unlock: + UNLOCK (&inode->lock); + +out: + if (!was_open_in_progress) { + if (!wait_for_open) { + call_resume (stub); + } else { + ob_inode_wake (this, &ob_fds); + } + } + + return 0; +} int open_and_resume (xlator_t *this, fd_t *fd, call_stub_t *stub) @@ -241,7 +479,7 @@ nofd: if (op_errno) call_unwind_error (stub, -1, op_errno); else if (ob_fd) - ob_fd_wake (this, fd); + ob_fd_wake (this, fd, NULL); else call_resume (stub); @@ -253,10 +491,12 @@ int ob_open_behind (call_frame_t *frame, xlator_t *this, loc_t *loc, int flags, fd_t *fd, dict_t *xdata) { - ob_fd_t *ob_fd = NULL; - int ret = -1; - ob_conf_t *conf = NULL; - + ob_fd_t *ob_fd = NULL; + int ret = -1; + ob_conf_t *conf = NULL; + ob_inode_t *ob_inode = NULL; + gf_boolean_t open_in_progress = _gf_false; + int unlinked = 0; conf = this->private; @@ -267,10 +507,17 @@ ob_open_behind (call_frame_t *frame, xlator_t *this, loc_t *loc, int flags, return 0; } + ob_inode = ob_inode_get (this, fd->inode); + ob_fd = ob_fd_new (); if (!ob_fd) goto enomem; + ob_fd->ob_inode = ob_inode; + + /* don't do fd_ref, it'll cause leaks */ + ob_fd->fd = fd; + ob_fd->open_frame = copy_frame (frame); if (!ob_fd->open_frame) goto enomem; @@ -282,27 +529,49 @@ ob_open_behind (call_frame_t *frame, xlator_t *this, loc_t *loc, int flags, if (xdata) ob_fd->xdata = dict_ref (xdata); - ret = ob_fd_ctx_set (this, fd, ob_fd); - if (ret) - goto enomem; + LOCK (&fd->inode->lock); + { + open_in_progress = ob_inode->open_in_progress; + unlinked = ob_inode->unlinked; + if (!open_in_progress && !unlinked) { + ret = ob_fd_ctx_set (this, fd, ob_fd); + if (ret) { + UNLOCK (&fd->inode->lock); + goto enomem; + } + + list_add (&ob_fd->ob_fds_on_inode, &ob_inode->ob_fds); + } + } + UNLOCK (&fd->inode->lock); - fd_ref (fd); - STACK_UNWIND_STRICT (open, frame, 0, 0, fd, xdata); + if (!open_in_progress && !unlinked) { + fd_ref (fd); - if (!conf->lazy_open) - ob_fd_wake (this, fd); + STACK_UNWIND_STRICT (open, frame, 0, 0, fd, xdata); - fd_unref (fd); + if (!conf->lazy_open) + ob_fd_wake (this, fd, NULL); + + fd_unref (fd); + } else { + ob_fd_free (ob_fd); + STACK_WIND (frame, default_open_cbk, + FIRST_CHILD (this), FIRST_CHILD (this)->fops->open, + loc, flags, fd, xdata); + } return 0; enomem: if (ob_fd) { if (ob_fd->open_frame) STACK_DESTROY (ob_fd->open_frame->root); + loc_wipe (&ob_fd->loc); if (ob_fd->xdata) dict_unref (ob_fd->xdata); + GF_FREE (ob_fd); } @@ -314,10 +583,10 @@ int ob_open (call_frame_t *frame, xlator_t *this, loc_t *loc, int flags, fd_t *fd, dict_t *xdata) { - fd_t *old_fd = NULL; - int ret = -1; - int op_errno = 0; - call_stub_t *stub = NULL; + fd_t *old_fd = NULL; + int ret = -1; + int op_errno = 0; + call_stub_t *stub = NULL; old_fd = fd_lookup (fd->inode, 0); if (old_fd) { @@ -365,7 +634,7 @@ ob_get_wind_fd (xlator_t *this, fd_t *fd, uint32_t *flag) ob_fd = ob_fd_ctx_get (this, fd); - if (ob_fd && conf->use_anonymous_fd) { + if (ob_fd && ob_fd->open_frame && conf->use_anonymous_fd) { wind_fd = fd_anonymous (fd->inode); if ((ob_fd->flags & O_DIRECT) && (flag)) *flag = *flag | O_DIRECT; @@ -760,12 +1029,10 @@ err: return 0; } - int ob_unlink (call_frame_t *frame, xlator_t *this, loc_t *loc, int xflags, dict_t *xdata) { - fd_t *fd = NULL; call_stub_t *stub = NULL; stub = fop_unlink_stub (frame, default_unlink_resume, loc, @@ -773,11 +1040,7 @@ ob_unlink (call_frame_t *frame, xlator_t *this, loc_t *loc, int xflags, if (!stub) goto err; - fd = fd_lookup (loc->inode, 0); - - open_and_resume (this, fd, stub); - if (fd) - fd_unref (fd); + open_all_pending_fds_and_resume (this, loc->inode, stub); return 0; err: @@ -786,24 +1049,17 @@ err: return 0; } - int ob_rename (call_frame_t *frame, xlator_t *this, loc_t *src, loc_t *dst, dict_t *xdata) { - fd_t *fd = NULL; call_stub_t *stub = NULL; stub = fop_rename_stub (frame, default_rename_resume, src, dst, xdata); if (!stub) goto err; - if (dst->inode) - fd = fd_lookup (dst->inode, 0); - - open_and_resume (this, fd, stub); - if (fd) - fd_unref (fd); + open_all_pending_fds_and_resume (this, dst->inode, stub); return 0; err: @@ -816,7 +1072,6 @@ int32_t ob_setattr (call_frame_t *frame, xlator_t *this, loc_t *loc, struct iatt *stbuf, int32_t valid, dict_t *xdata) { - fd_t *fd = NULL; call_stub_t *stub = NULL; stub = fop_setattr_stub (frame, default_setattr_resume, loc, stbuf, @@ -824,11 +1079,7 @@ ob_setattr (call_frame_t *frame, xlator_t *this, loc_t *loc, if (!stub) goto err; - fd = fd_lookup (loc->inode, 0); - - open_and_resume (this, fd, stub); - if (fd) - fd_unref (fd); + open_all_pending_fds_and_resume (this, loc->inode, stub); return 0; err: @@ -841,7 +1092,6 @@ int32_t ob_setxattr (call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict, int32_t flags, dict_t *xdata) { - fd_t *fd = NULL; call_stub_t *stub = NULL; gf_boolean_t access_xattr = _gf_false; @@ -858,11 +1108,7 @@ ob_setxattr (call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict, if (!stub) goto err; - fd = fd_lookup (loc->inode, 0); - - open_and_resume (this, fd, stub); - if (fd) - fd_unref (fd); + open_all_pending_fds_and_resume (this, loc->inode, stub); return 0; err: @@ -873,7 +1119,7 @@ err: int ob_release (xlator_t *this, fd_t *fd) { - ob_fd_t *ob_fd = NULL; + ob_fd_t *ob_fd = NULL; ob_fd = ob_fd_ctx_get (this, fd); @@ -882,6 +1128,21 @@ ob_release (xlator_t *this, fd_t *fd) return 0; } +int +ob_forget (xlator_t *this, inode_t *inode) +{ + ob_inode_t *ob_inode = NULL; + uint64_t value = 0; + + inode_ctx_del (inode, this, &value); + + if (value) { + ob_inode = (ob_inode_t *)((void *) value); + ob_inode_free (ob_inode); + } + + return 0; +} int ob_priv_dump (xlator_t *this) @@ -1068,6 +1329,7 @@ struct xlator_fops fops = { struct xlator_cbks cbks = { .release = ob_release, + .forget = ob_forget, }; struct xlator_dumpops dumpops = { @@ -1079,7 +1341,7 @@ struct xlator_dumpops dumpops = { struct volume_options options[] = { { .key = {"use-anonymous-fd"}, .type = GF_OPTION_TYPE_BOOL, - .default_value = "yes", + .default_value = "no", .description = "For read operations, use anonymous FD when " "original FD is open-behind and not yet opened in the backend.", }, |