summaryrefslogtreecommitdiffstats
path: root/xlators/performance
diff options
context:
space:
mode:
Diffstat (limited to 'xlators/performance')
-rw-r--r--xlators/performance/write-behind/src/write-behind.c54
1 files changed, 45 insertions, 9 deletions
diff --git a/xlators/performance/write-behind/src/write-behind.c b/xlators/performance/write-behind/src/write-behind.c
index c6bc5ef573e..c3c42cd1a4f 100644
--- a/xlators/performance/write-behind/src/write-behind.c
+++ b/xlators/performance/write-behind/src/write-behind.c
@@ -837,7 +837,7 @@ out:
}
int
-__wb_fulfill_short_write (wb_request_t *req, int size)
+__wb_fulfill_short_write (wb_request_t *req, int size, gf_boolean_t *fulfilled)
{
int accounted_size = 0;
@@ -847,6 +847,7 @@ __wb_fulfill_short_write (wb_request_t *req, int size)
if (req->write_size <= size) {
accounted_size = req->write_size;
__wb_fulfill_request (req);
+ *fulfilled = 1;
} else {
accounted_size = size;
__wb_modify_write_request (req, size);
@@ -859,9 +860,10 @@ out:
void
wb_fulfill_short_write (wb_request_t *head, int size)
{
- wb_inode_t *wb_inode = NULL;
- wb_request_t *req = NULL, *tmp = NULL;
- int accounted_size = 0;
+ wb_inode_t *wb_inode = NULL;
+ wb_request_t *req = NULL, *next = NULL;
+ int accounted_size = 0;
+ gf_boolean_t fulfilled = _gf_false;
if (!head)
goto out;
@@ -872,25 +874,48 @@ wb_fulfill_short_write (wb_request_t *head, int size)
LOCK (&wb_inode->lock);
{
- accounted_size = __wb_fulfill_short_write (head, size);
+ /* hold a reference to head so that __wb_fulfill_short_write
+ * won't free it. We need head for a cleaner list traversal as
+ * list_for_each_entry_safe doesn't iterate over "head" member.
+ * So, if we pass "next->winds" as head to list_for_each_entry,
+ * "next" is skipped. For a simpler logic we need to traverse
+ * the list in the order. So, we start traversal from
+ * "head->winds" and hence we want head to be alive.
+ */
+ __wb_request_ref (head);
+
+ next = list_entry (head->winds.next, wb_request_t, winds);
+
+ accounted_size = __wb_fulfill_short_write (head, size,
+ &fulfilled);
size -= accounted_size;
- if (size == 0)
+ if (size == 0) {
+ if (fulfilled)
+ req = next;
+
goto done;
+ }
- list_for_each_entry_safe (req, tmp, &head->winds, winds) {
- accounted_size = __wb_fulfill_short_write (req, size);
+ list_for_each_entry_safe (req, next, &head->winds, winds) {
+ accounted_size = __wb_fulfill_short_write (req, size,
+ &fulfilled);
size -= accounted_size;
- if (size == 0)
+ if (size == 0) {
+ if (fulfilled)
+ req = next;
break;
+ }
}
}
done:
UNLOCK (&wb_inode->lock);
+ __wb_request_unref (head);
+
wb_fulfill_err (req, EIO);
out:
return;
@@ -1314,6 +1339,16 @@ __wb_handle_failed_conflict (wb_request_t *req, wb_request_t *conflict,
list_del_init (&req->todo);
list_add_tail (&req->winds, tasks);
+
+ if (req->ordering.tempted) {
+ /* make sure that it won't be unwound in
+ * wb_do_unwinds too. Otherwise there'll be
+ * a double wind.
+ */
+ list_del_init (&req->lie);
+ __wb_fulfill_request (req);
+ }
+
}
} else {
/* flush and fsync (without conf->resync_after_fsync) act as
@@ -1421,6 +1456,7 @@ wb_do_winds (wb_inode_t *wb_inode, list_head_t *tasks)
call_resume (req->stub);
}
+ req->stub = NULL;
wb_request_unref (req);
}
}