Patchwork [v3,2/9] block: add BlockJob interface for long-running operations

login
register
mail settings
Submitter Stefan Hajnoczi
Date Dec. 13, 2011, 1:52 p.m.
Message ID <1323784351-25531-3-git-send-email-stefanha@linux.vnet.ibm.com>
Download mbox | patch
Permalink /patch/131100/
State New
Headers show

Comments

Stefan Hajnoczi - Dec. 13, 2011, 1:52 p.m.
Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
---
 block_int.h |   83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 83 insertions(+), 0 deletions(-)
Kevin Wolf - Dec. 14, 2011, 1:51 p.m.
Am 13.12.2011 14:52, schrieb Stefan Hajnoczi:
> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
> ---
>  block_int.h |   83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 83 insertions(+), 0 deletions(-)

Why are these functions static inline in the header instead of being
implemented in block.c?

The other thing I was going to ask, but don't really know to which patch
I should reply, is whether we need to take care of bdrv_close/delete
while a block job is still running. What happens if you unplug a device
that is being streamed?

Kevin
Stefan Hajnoczi - Dec. 15, 2011, 8:50 a.m.
On Wed, Dec 14, 2011 at 02:51:47PM +0100, Kevin Wolf wrote:
> Am 13.12.2011 14:52, schrieb Stefan Hajnoczi:
> > Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
> > ---
> >  block_int.h |   83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  1 files changed, 83 insertions(+), 0 deletions(-)
> 
> Why are these functions static inline in the header instead of being
> implemented in block.c?

You are right, they should be moved.

> The other thing I was going to ask, but don't really know to which patch
> I should reply, is whether we need to take care of bdrv_close/delete
> while a block job is still running. What happens if you unplug a device
> that is being streamed?

Hotplug is protected by the bdrv_set_in_use() we issue during block job
creation/completion.

The 'change', 'resize', and 'snapshot_blkdev' operations are not
protected AFAICT.  I'll take a close look at them and send patches.

Stefan
Marcelo Tosatti - Dec. 15, 2011, 10:40 a.m.
On Wed, Dec 14, 2011 at 02:51:47PM +0100, Kevin Wolf wrote:
> Am 13.12.2011 14:52, schrieb Stefan Hajnoczi:
> > Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
> > ---
> >  block_int.h |   83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  1 files changed, 83 insertions(+), 0 deletions(-)
> 
> Why are these functions static inline in the header instead of being
> implemented in block.c?
> 
> The other thing I was going to ask, but don't really know to which patch
> I should reply, is whether we need to take care of bdrv_close/delete
> while a block job is still running. What happens if you unplug a device
> that is being streamed?

There is an additional reference, its not deleted until the operation
completes. Or at least it should be like that, Stefan?
Stefan Hajnoczi - Dec. 16, 2011, 8:09 a.m.
On Thu, Dec 15, 2011 at 08:40:08AM -0200, Marcelo Tosatti wrote:
> On Wed, Dec 14, 2011 at 02:51:47PM +0100, Kevin Wolf wrote:
> > Am 13.12.2011 14:52, schrieb Stefan Hajnoczi:
> > > Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
> > > ---
> > >  block_int.h |   83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> > >  1 files changed, 83 insertions(+), 0 deletions(-)
> > 
> > Why are these functions static inline in the header instead of being
> > implemented in block.c?
> > 
> > The other thing I was going to ask, but don't really know to which patch
> > I should reply, is whether we need to take care of bdrv_close/delete
> > while a block job is still running. What happens if you unplug a device
> > that is being streamed?
> 
> There is an additional reference, its not deleted until the operation
> completes. Or at least it should be like that, Stefan?

Right, the patch uses bdrv_set_in_use().  In my other reply to this
sub-thread I mentioned that certain operations like 'change', 'resize',
and 'snapshot_blkdev' do not seem to check bdrv_in_use() yet.

So I think in order to make image streaming safe additional checks will
need to be added in blockdev.c.

Stefan

Patch

diff --git a/block_int.h b/block_int.h
index 89a860c..bc397c4 100644
--- a/block_int.h
+++ b/block_int.h
@@ -69,6 +69,36 @@  typedef struct BlockIOBaseValue {
     uint64_t ios[2];
 } BlockIOBaseValue;
 
+typedef void BlockJobCancelFunc(void *opaque);
+typedef struct BlockJob BlockJob;
+typedef struct BlockJobType {
+    /** Derived BlockJob struct size */
+    size_t instance_size;
+
+    /** String describing the operation, part of query-block-jobs QMP API */
+    const char *job_type;
+
+    /** Optional callback for job types that support setting a speed limit */
+    int (*set_speed)(BlockJob *job, int64_t value);
+} BlockJobType;
+
+/**
+ * Long-running operation on a BlockDriverState
+ */
+struct BlockJob {
+    const BlockJobType *job_type;
+    BlockDriverState *bs;
+    bool cancelled;
+
+    /* These fields are published by the query-block-jobs QMP API */
+    int64_t offset;
+    int64_t len;
+    int64_t speed;
+
+    BlockDriverCompletionFunc *cb;
+    void *opaque;
+};
+
 struct BlockDriver {
     const char *format_name;
     int instance_size;
@@ -270,6 +300,9 @@  struct BlockDriverState {
     void *private;
 
     QLIST_HEAD(, BdrvTrackedRequest) tracked_requests;
+
+    /* long-running background operation */
+    BlockJob *job;
 };
 
 struct BlockDriverAIOCB {
@@ -293,4 +326,54 @@  void bdrv_set_io_limits(BlockDriverState *bs,
 int is_windows_drive(const char *filename);
 #endif
 
+static inline void *block_job_create(const BlockJobType *job_type,
+                                     BlockDriverState *bs,
+                                     BlockDriverCompletionFunc *cb,
+                                     void *opaque)
+{
+    BlockJob *job;
+
+    if (bdrv_in_use(bs)) {
+        return NULL;
+    }
+    bdrv_set_in_use(bs, 1);
+
+    job = g_malloc0(job_type->instance_size);
+    job->job_type      = job_type;
+    job->bs            = bs;
+    job->cb            = cb;
+    job->opaque        = opaque;
+    bs->job = job;
+    return job;
+}
+
+static inline void block_job_complete(BlockJob *job, int ret)
+{
+    BlockDriverState *bs = job->bs;
+
+    assert(bs->job == job);
+    job->cb(job->opaque, ret);
+    bs->job = NULL;
+    g_free(job);
+    bdrv_set_in_use(bs, 0);
+}
+
+static inline int block_job_set_speed(BlockJob *job, int64_t value)
+{
+    if (!job->job_type->set_speed) {
+        return -ENOTSUP;
+    }
+    return job->job_type->set_speed(job, value);
+}
+
+static inline void block_job_cancel(BlockJob *job)
+{
+    job->cancelled = true;
+}
+
+static inline bool block_job_is_cancelled(BlockJob *job)
+{
+    return job->cancelled;
+}
+
 #endif /* BLOCK_INT_H */