From: David Howells <dhowells@redhat.com>
To: linux-cachefs@redhat.com, nfsv4@linux-nfs.org,
linux-kernel@vger.kernel.org
Cc: dhowells@redhat.com, steved@redhat.com
Subject: [PATCH 03/28] SLOW_WORK: Add support for cancellation of slow work
Date: Thu, 19 Nov 2009 17:20:49 +0000 [thread overview]
Message-ID: <20091119172049.1679.58503.stgit@warthog.procyon.org.uk> (raw)
In-Reply-To: <20091119172033.1679.87046.stgit@warthog.procyon.org.uk>
From: Jens Axboe <jens.axboe@oracle.com>
Add support for cancellation of queued slow work and delayed slow work items.
The cancellation functions will wait for items that are pending or undergoing
execution to be discarded by the slow work facility.
Attempting to enqueue work that is in the process of being cancelled will
result in ECANCELED.
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Signed-off-by: David Howells <dhowells@redhat.com>
---
Documentation/slow-work.txt | 12 ++++++
include/linux/slow-work.h | 2 +
kernel/slow-work.c | 81 ++++++++++++++++++++++++++++++++++++++++---
3 files changed, 88 insertions(+), 7 deletions(-)
diff --git a/Documentation/slow-work.txt b/Documentation/slow-work.txt
index c655c51..2e384bd 100644
--- a/Documentation/slow-work.txt
+++ b/Documentation/slow-work.txt
@@ -108,7 +108,17 @@ on the item, 0 otherwise.
The items are reference counted, so there ought to be no need for a flush
-operation. When all a module's slow work items have been processed, and the
+operation. But as the reference counting is optional, means to cancel
+existing work items are also included:
+
+ cancel_slow_work(&myitem);
+
+can be used to cancel pending work. The above cancel function waits for
+existing work to have been executed (or prevent execution of them, depending
+on timing).
+
+
+When all a module's slow work items have been processed, and the
module has no further interest in the facility, it should unregister its
interest:
diff --git a/include/linux/slow-work.h b/include/linux/slow-work.h
index 9adb2b3..eef2018 100644
--- a/include/linux/slow-work.h
+++ b/include/linux/slow-work.h
@@ -51,6 +51,7 @@ struct slow_work {
#define SLOW_WORK_EXECUTING 1 /* item currently executing */
#define SLOW_WORK_ENQ_DEFERRED 2 /* item enqueue deferred */
#define SLOW_WORK_VERY_SLOW 3 /* item is very slow */
+#define SLOW_WORK_CANCELLING 4 /* item is being cancelled, don't enqueue */
const struct slow_work_ops *ops; /* operations table for this item */
struct list_head link; /* link in queue */
};
@@ -88,6 +89,7 @@ static inline void vslow_work_init(struct slow_work *work,
}
extern int slow_work_enqueue(struct slow_work *work);
+extern void slow_work_cancel(struct slow_work *work);
extern int slow_work_register_user(struct module *owner);
extern void slow_work_unregister_user(struct module *owner);
diff --git a/kernel/slow-work.c b/kernel/slow-work.c
index fccf421..671cc43 100644
--- a/kernel/slow-work.c
+++ b/kernel/slow-work.c
@@ -236,12 +236,17 @@ static bool slow_work_execute(int id)
if (!test_and_clear_bit(SLOW_WORK_PENDING, &work->flags))
BUG();
- work->ops->execute(work);
+ /* don't execute if the work is in the process of being cancelled */
+ if (!test_bit(SLOW_WORK_CANCELLING, &work->flags))
+ work->ops->execute(work);
if (very_slow)
atomic_dec(&vslow_work_executing_count);
clear_bit_unlock(SLOW_WORK_EXECUTING, &work->flags);
+ /* wake up anyone waiting for this work to be complete */
+ wake_up_bit(&work->flags, SLOW_WORK_EXECUTING);
+
/* if someone tried to enqueue the item whilst we were executing it,
* then it'll be left unenqueued to avoid multiple threads trying to
* execute it simultaneously
@@ -314,11 +319,16 @@ auto_requeue:
* allowed to pick items to execute. This ensures that very slow items won't
* overly block ones that are just ordinarily slow.
*
- * Returns 0 if successful, -EAGAIN if not.
+ * Returns 0 if successful, -EAGAIN if not (or -ECANCELED if cancelled work is
+ * attempted queued)
*/
int slow_work_enqueue(struct slow_work *work)
{
unsigned long flags;
+ int ret;
+
+ if (test_bit(SLOW_WORK_CANCELLING, &work->flags))
+ return -ECANCELED;
BUG_ON(slow_work_user_count <= 0);
BUG_ON(!work);
@@ -335,6 +345,9 @@ int slow_work_enqueue(struct slow_work *work)
if (!test_and_set_bit_lock(SLOW_WORK_PENDING, &work->flags)) {
spin_lock_irqsave(&slow_work_queue_lock, flags);
+ if (unlikely(test_bit(SLOW_WORK_CANCELLING, &work->flags)))
+ goto cancelled;
+
/* we promise that we will not attempt to execute the work
* function in more than one thread simultaneously
*
@@ -352,8 +365,9 @@ int slow_work_enqueue(struct slow_work *work)
if (test_bit(SLOW_WORK_EXECUTING, &work->flags)) {
set_bit(SLOW_WORK_ENQ_DEFERRED, &work->flags);
} else {
- if (slow_work_get_ref(work) < 0)
- goto cant_get_ref;
+ ret = slow_work_get_ref(work);
+ if (ret < 0)
+ goto failed;
if (test_bit(SLOW_WORK_VERY_SLOW, &work->flags))
list_add_tail(&work->link, &vslow_work_queue);
else
@@ -365,12 +379,67 @@ int slow_work_enqueue(struct slow_work *work)
}
return 0;
-cant_get_ref:
+cancelled:
+ ret = -ECANCELED;
+failed:
spin_unlock_irqrestore(&slow_work_queue_lock, flags);
- return -EAGAIN;
+ return ret;
}
EXPORT_SYMBOL(slow_work_enqueue);
+static int slow_work_wait(void *word)
+{
+ schedule();
+ return 0;
+}
+
+/**
+ * slow_work_cancel - Cancel a slow work item
+ * @work: The work item to cancel
+ *
+ * This function will cancel a previously enqueued work item. If we cannot
+ * cancel the work item, it is guarenteed to have run when this function
+ * returns.
+ */
+void slow_work_cancel(struct slow_work *work)
+{
+ bool wait = true, put = false;
+
+ set_bit(SLOW_WORK_CANCELLING, &work->flags);
+
+ spin_lock_irq(&slow_work_queue_lock);
+
+ if (test_bit(SLOW_WORK_PENDING, &work->flags) &&
+ !list_empty(&work->link)) {
+ /* the link in the pending queue holds a reference on the item
+ * that we will need to release */
+ list_del_init(&work->link);
+ wait = false;
+ put = true;
+ clear_bit(SLOW_WORK_PENDING, &work->flags);
+
+ } else if (test_and_clear_bit(SLOW_WORK_ENQ_DEFERRED, &work->flags)) {
+ /* the executor is holding our only reference on the item, so
+ * we merely need to wait for it to finish executing */
+ clear_bit(SLOW_WORK_PENDING, &work->flags);
+ }
+
+ spin_unlock_irq(&slow_work_queue_lock);
+
+ /* the EXECUTING flag is set by the executor whilst the spinlock is set
+ * and before the item is dequeued - so assuming the above doesn't
+ * actually dequeue it, simply waiting for the EXECUTING flag to be
+ * released here should be sufficient */
+ if (wait)
+ wait_on_bit(&work->flags, SLOW_WORK_EXECUTING, slow_work_wait,
+ TASK_UNINTERRUPTIBLE);
+
+ clear_bit(SLOW_WORK_CANCELLING, &work->flags);
+ if (put)
+ slow_work_put_ref(work);
+}
+EXPORT_SYMBOL(slow_work_cancel);
+
/*
* Schedule a cull of the thread pool at some time in the near future
*/
next prev parent reply other threads:[~2009-11-19 18:04 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-11-19 17:20 [PATCH 00/28] Fixes for FS-Cache and CacheFiles David Howells
2009-11-19 17:20 ` [PATCH 01/28] SLOW_WORK: Wait for outstanding work items belonging to a module to clear David Howells
2009-11-20 9:19 ` steve
2009-11-19 17:20 ` [PATCH 02/28] SLOW_WORK: Make slow_work_ops ->get_ref/->put_ref optional David Howells
2009-11-19 17:20 ` David Howells [this message]
2009-11-19 17:20 ` [PATCH 04/28] SLOW_WORK: Add delayed_slow_work support David Howells
2009-11-19 17:20 ` [PATCH 05/28] SLOW_WORK: Allow the work items to be viewed through a /proc file David Howells
2009-11-19 17:21 ` [PATCH 06/28] SLOW_WORK: Allow the owner of a work item to determine if it is queued or not David Howells
2009-11-19 17:21 ` [PATCH 07/28] SLOW_WORK: Allow a requeueable work item to sleep till the thread is needed David Howells
2009-11-19 17:21 ` [PATCH 08/28] FS-Cache: Annotate slow-work runqueue proc lines for FS-Cache work items David Howells
2009-11-19 17:21 ` [PATCH 09/28] FS-Cache: Allow the current state of all objects to be dumped David Howells
2009-11-19 17:21 ` [PATCH 10/28] FS-Cache: Add counters for entry/exit to/from cache operation functions David Howells
2009-11-19 17:21 ` [PATCH 11/28] FS-Cache: Clear netfs pointers in cookie after detaching object, not before David Howells
2009-11-19 17:21 ` [PATCH 12/28] FS-Cache: Use radix tree preload correctly in tracking of pages to be stored David Howells
2009-11-19 17:21 ` [PATCH 13/28] FS-Cache: Permit cache retrieval ops to be interrupted in the initial wait phase David Howells
2009-11-19 17:21 ` [PATCH 14/28] FS-Cache: The object-available state can't rely on the cookie to be available David Howells
2009-11-19 17:21 ` [PATCH 15/28] FS-Cache: Fix lock misorder in fscache_write_op() David Howells
2009-11-19 17:21 ` [PATCH 16/28] FS-Cache: Don't delete pending pages from the page-store tracking tree David Howells
2009-11-19 17:22 ` [PATCH 17/28] FS-Cache: Handle read request vs lookup, creation or other cache failure David Howells
2009-11-19 17:22 ` [PATCH 18/28] FS-Cache: Handle pages pending storage that get evicted under OOM conditions David Howells
2009-11-19 17:22 ` [PATCH 19/28] FS-Cache: Add a retirement stat counter David Howells
2009-11-19 17:22 ` [PATCH 20/28] FS-Cache: Make sure FSCACHE_COOKIE_LOOKING_UP cleared on lookup failure David Howells
2009-11-19 17:22 ` [PATCH 21/28] FS-Cache: Start processing an object's operations on that object's death David Howells
2009-11-19 17:22 ` [PATCH 22/28] FS-Cache: Actually requeue an object when requested David Howells
2009-11-19 17:22 ` [PATCH 23/28] CacheFiles: Don't write a full page if there's only a partial page to cache David Howells
2009-11-19 17:22 ` [PATCH 24/28] CacheFiles: Handle truncate unlocking the page we're reading David Howells
2009-11-19 17:22 ` [PATCH 25/28] CacheFiles: Mark parent directory locks as I_MUTEX_PARENT to keep lockdep happy David Howells
2009-11-19 17:22 ` [PATCH 26/28] CacheFiles: Better showing of debugging information in active object problems David Howells
2009-11-19 17:22 ` [PATCH 27/28] CacheFiles: Catch an overly long wait for an old active object David Howells
2009-11-19 17:22 ` [PATCH 28/28] CacheFiles: Don't log lookup/create failing with ENOBUFS David Howells
2009-11-20 8:16 ` [PATCH 00/28] Fixes for FS-Cache and CacheFiles David Howells
2009-11-20 21:54 ` [PATCH 0/3] " David Howells
2009-11-20 21:54 ` [PATCH 1/3] SLOW_WORK: Fix CIFS to pass THIS_MODULE to slow_work_register_user() David Howells
2009-11-20 21:54 ` [PATCH 2/3] SLOW_WORK: Fix GFS2 to #include <linux/module.h> before using THIS_MODULE David Howells
2009-11-20 21:54 ` [PATCH 3/3] FS-Cache: Provide nop fscache_stat_d() if CONFIG_FSCACHE_STATS=n David Howells
2009-11-20 8:18 ` [PATCH 00/28] Fixes for FS-Cache and CacheFiles David Howells
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20091119172049.1679.58503.stgit@warthog.procyon.org.uk \
--to=dhowells@redhat.com \
--cc=linux-cachefs@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=nfsv4@linux-nfs.org \
--cc=steved@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®