1
The following changes since commit 55a19ad8b2d0797e3a8fe90ab99a9bb713824059:
1
The following changes since commit 9c125d17e9402c232c46610802e5931b3639d77b:
2
2
3
Update version for v2.9.0-rc1 release (2017-03-21 17:13:29 +0000)
3
Merge tag 'pull-tcg-20220420' of https://gitlab.com/rth7680/qemu into staging (2022-04-20 16:43:11 -0700)
4
4
5
are available in the git repository at:
5
are available in the Git repository at:
6
6
7
https://github.com/codyprime/qemu-kvm-jtc.git tags/block-pull-request
7
https://gitlab.com/stefanha/qemu.git tags/block-pull-request
8
8
9
for you to fetch changes up to 600ac6a0ef5c06418446ef2f37407bddcc51b21c:
9
for you to fetch changes up to d45c83328feab2e4083991693160f0a417cfd9b0:
10
10
11
blockjob: add devops to blockjob backends (2017-03-22 13:26:27 -0400)
11
virtiofsd: Add docs/helper for killpriv_v2/no_killpriv_v2 option (2022-04-21 12:05:15 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block patches for 2.9
14
Pull request
15
16
Small contrib/vhost-user-blk, contrib/vhost-user-scsi, and tools/virtiofsd
17
improvements.
18
15
----------------------------------------------------------------
19
----------------------------------------------------------------
16
20
17
John Snow (3):
21
Liu Yiding (1):
18
blockjob: add block_job_start_shim
22
virtiofsd: Add docs/helper for killpriv_v2/no_killpriv_v2 option
19
block-backend: add drained_begin / drained_end ops
20
blockjob: add devops to blockjob backends
21
23
22
Paolo Bonzini (1):
24
Sakshi Kaushik (1):
23
blockjob: avoid recursive AioContext locking
25
Implements Backend Program conventions for vhost-user-scsi
24
26
25
block/block-backend.c | 24 ++++++++++++++--
27
Stefan Hajnoczi (1):
26
blockjob.c | 63 ++++++++++++++++++++++++++++++++----------
28
contrib/vhost-user-blk: add missing GOptionEntry NULL terminator
27
include/sysemu/block-backend.h | 8 ++++++
29
28
3 files changed, 79 insertions(+), 16 deletions(-)
30
docs/tools/virtiofsd.rst | 5 ++
31
contrib/vhost-user-blk/vhost-user-blk.c | 3 +-
32
contrib/vhost-user-scsi/vhost-user-scsi.c | 77 +++++++++++++++--------
33
tools/virtiofsd/helper.c | 3 +
34
4 files changed, 62 insertions(+), 26 deletions(-)
29
35
30
--
36
--
31
2.9.3
37
2.35.1
32
33
diff view generated by jsdifflib
Deleted patch
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
1
3
Streaming or any other block job hangs when performed on a block device
4
that has a non-default iothread. This happens because the AioContext
5
is acquired twice by block_job_defer_to_main_loop_bh and then released
6
only once by BDRV_POLL_WHILE. (Insert rants on recursive mutexes, which
7
unfortunately are a temporary but necessary evil for iothreads at the
8
moment).
9
10
Luckily, the reason for the double acquisition is simple; the function
11
acquires the AioContext for both the job iothread and the BDS iothread,
12
in case the BDS iothread was changed while the job was running. It
13
is therefore enough to skip the second acquisition when the two
14
AioContexts are one and the same.
15
16
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
17
Reviewed-by: Eric Blake <eblake@redhat.com>
18
Reviewed-by: Jeff Cody <jcody@redhat.com>
19
Message-id: 1490118490-5597-1-git-send-email-pbonzini@redhat.com
20
Signed-off-by: Jeff Cody <jcody@redhat.com>
21
---
22
blockjob.c | 8 ++++++--
23
1 file changed, 6 insertions(+), 2 deletions(-)
24
25
diff --git a/blockjob.c b/blockjob.c
26
index XXXXXXX..XXXXXXX 100644
27
--- a/blockjob.c
28
+++ b/blockjob.c
29
@@ -XXX,XX +XXX,XX @@ static void block_job_defer_to_main_loop_bh(void *opaque)
30
31
/* Fetch BDS AioContext again, in case it has changed */
32
aio_context = blk_get_aio_context(data->job->blk);
33
- aio_context_acquire(aio_context);
34
+ if (aio_context != data->aio_context) {
35
+ aio_context_acquire(aio_context);
36
+ }
37
38
data->job->deferred_to_main_loop = false;
39
data->fn(data->job, data->opaque);
40
41
- aio_context_release(aio_context);
42
+ if (aio_context != data->aio_context) {
43
+ aio_context_release(aio_context);
44
+ }
45
46
aio_context_release(data->aio_context);
47
48
--
49
2.9.3
50
51
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Sakshi Kaushik <sakshikaushik717@gmail.com>
2
2
3
This lets us hook into drained_begin and drained_end requests from the
3
Signed-off-by: Sakshi Kaushik <sakshikaushik717@gmail.com>
4
backend level, which is particularly useful for making sure that all
4
Message-id: 20220406162410.8536-1-sakshikaushik717@gmail.com
5
jobs associated with a particular node (whether the source or the target)
6
receive a drain request.
7
5
8
Suggested-by: Kevin Wolf <kwolf@redhat.com>
6
[Name the iSCSI URL long option --iscsi-uri instead of --iscsi_uri for
9
Signed-off-by: John Snow <jsnow@redhat.com>
7
consistency, fix --fd which was rejected due to an outdated
10
Reviewed-by: Jeff Cody <jcody@redhat.com>
8
--socket-path check, and add missing entries[] terminator.
11
Message-id: 20170316212351.13797-4-jsnow@redhat.com
9
--Stefan]
12
Signed-off-by: Jeff Cody <jcody@redhat.com>
10
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
---
12
---
14
blockjob.c | 29 ++++++++++++++++++++++++-----
13
contrib/vhost-user-scsi/vhost-user-scsi.c | 77 +++++++++++++++--------
15
1 file changed, 24 insertions(+), 5 deletions(-)
14
1 file changed, 52 insertions(+), 25 deletions(-)
16
15
17
diff --git a/blockjob.c b/blockjob.c
16
diff --git a/contrib/vhost-user-scsi/vhost-user-scsi.c b/contrib/vhost-user-scsi/vhost-user-scsi.c
18
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
19
--- a/blockjob.c
18
--- a/contrib/vhost-user-scsi/vhost-user-scsi.c
20
+++ b/blockjob.c
19
+++ b/contrib/vhost-user-scsi/vhost-user-scsi.c
21
@@ -XXX,XX +XXX,XX @@ static const BdrvChildRole child_job = {
20
@@ -XXX,XX +XXX,XX @@ fail:
22
.stay_at_node = true,
21
23
};
22
/** vhost-user-scsi **/
24
23
25
+static void block_job_drained_begin(void *opaque)
24
+static int opt_fdnum = -1;
26
+{
25
+static char *opt_socket_path;
27
+ BlockJob *job = opaque;
26
+static gboolean opt_print_caps;
28
+ block_job_pause(job);
27
+static char *iscsi_uri;
29
+}
30
+
28
+
31
+static void block_job_drained_end(void *opaque)
29
+static GOptionEntry entries[] = {
32
+{
30
+ { "print-capabilities", 'c', 0, G_OPTION_ARG_NONE, &opt_print_caps,
33
+ BlockJob *job = opaque;
31
+ "Print capabilities", NULL },
34
+ block_job_resume(job);
32
+ { "fd", 'f', 0, G_OPTION_ARG_INT, &opt_fdnum,
35
+}
33
+ "Use inherited fd socket", "FDNUM" },
36
+
34
+ { "iscsi-uri", 'i', 0, G_OPTION_ARG_FILENAME, &iscsi_uri,
37
+static const BlockDevOps block_job_dev_ops = {
35
+ "iSCSI URI to connect to", "FDNUM" },
38
+ .drained_begin = block_job_drained_begin,
36
+ { "socket-path", 's', 0, G_OPTION_ARG_FILENAME, &opt_socket_path,
39
+ .drained_end = block_job_drained_end,
37
+ "Use UNIX socket path", "PATH" },
38
+ { NULL, }
40
+};
39
+};
41
+
40
+
42
BlockJob *block_job_next(BlockJob *job)
41
int main(int argc, char **argv)
43
{
42
{
44
if (!job) {
43
VusDev *vdev_scsi = NULL;
45
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
44
- char *unix_fn = NULL;
45
- char *iscsi_uri = NULL;
46
- int lsock = -1, csock = -1, opt, err = EXIT_SUCCESS;
47
+ int lsock = -1, csock = -1, err = EXIT_SUCCESS;
48
49
- while ((opt = getopt(argc, argv, "u:i:")) != -1) {
50
- switch (opt) {
51
- case 'h':
52
- goto help;
53
- case 'u':
54
- unix_fn = g_strdup(optarg);
55
- break;
56
- case 'i':
57
- iscsi_uri = g_strdup(optarg);
58
- break;
59
- default:
60
- goto help;
61
- }
62
+ GError *error = NULL;
63
+ GOptionContext *context;
64
+
65
+ context = g_option_context_new(NULL);
66
+ g_option_context_add_main_entries(context, entries, NULL);
67
+ if (!g_option_context_parse(context, &argc, &argv, &error)) {
68
+ g_printerr("Option parsing failed: %s\n", error->message);
69
+ exit(EXIT_FAILURE);
70
+ }
71
+
72
+ if (opt_print_caps) {
73
+ g_print("{\n");
74
+ g_print(" \"type\": \"scsi\"\n");
75
+ g_print("}\n");
76
+ goto out;
46
}
77
}
47
78
- if (!unix_fn || !iscsi_uri) {
48
job = g_malloc0(driver->instance_size);
49
- error_setg(&job->blocker, "block device is in use by block job: %s",
50
- BlockJobType_lookup[driver->job_type]);
51
- block_job_add_bdrv(job, "main node", bs, 0, BLK_PERM_ALL, &error_abort);
52
- bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker);
53
-
54
job->driver = driver;
55
job->id = g_strdup(job_id);
56
job->blk = blk;
57
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
58
job->paused = true;
59
job->pause_count = 1;
60
job->refcnt = 1;
61
+
79
+
62
+ error_setg(&job->blocker, "block device is in use by block job: %s",
80
+ if (!iscsi_uri) {
63
+ BlockJobType_lookup[driver->job_type]);
81
goto help;
64
+ block_job_add_bdrv(job, "main node", bs, 0, BLK_PERM_ALL, &error_abort);
82
}
65
bs->job = job;
83
66
84
- lsock = unix_sock_new(unix_fn);
67
+ blk_set_dev_ops(blk, &block_job_dev_ops, job);
85
- if (lsock < 0) {
68
+ bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker);
86
- goto err;
69
+
87
+ if (opt_socket_path) {
70
QLIST_INSERT_HEAD(&block_jobs, job, job_list);
88
+ lsock = unix_sock_new(opt_socket_path);
71
89
+ if (lsock < 0) {
72
blk_add_aio_context_notifier(blk, block_job_attached_aio_context,
90
+ exit(EXIT_FAILURE);
91
+ }
92
+ } else if (opt_fdnum < 0) {
93
+ g_print("%s\n", g_option_context_get_help(context, true, NULL));
94
+ exit(EXIT_FAILURE);
95
+ } else {
96
+ lsock = opt_fdnum;
97
}
98
99
csock = accept(lsock, NULL, NULL);
100
@@ -XXX,XX +XXX,XX @@ out:
101
if (vdev_scsi) {
102
g_main_loop_unref(vdev_scsi->loop);
103
g_free(vdev_scsi);
104
- unlink(unix_fn);
105
+ unlink(opt_socket_path);
106
}
107
if (csock >= 0) {
108
close(csock);
109
@@ -XXX,XX +XXX,XX @@ out:
110
if (lsock >= 0) {
111
close(lsock);
112
}
113
- g_free(unix_fn);
114
+ g_free(opt_socket_path);
115
g_free(iscsi_uri);
116
117
return err;
118
@@ -XXX,XX +XXX,XX @@ err:
119
goto out;
120
121
help:
122
- fprintf(stderr, "Usage: %s [ -u unix_sock_path -i iscsi_uri ] | [ -h ]\n",
123
+ fprintf(stderr, "Usage: %s [ -s socket-path -i iscsi-uri -f fd -p print-capabilities ] | [ -h ]\n",
124
argv[0]);
125
- fprintf(stderr, " -u path to unix socket\n");
126
- fprintf(stderr, " -i iscsi uri for lun 0\n");
127
+ fprintf(stderr, " -s, --socket-path=SOCKET_PATH path to unix socket\n");
128
+ fprintf(stderr, " -i, --iscsi-uri=ISCSI_URI iscsi uri for lun 0\n");
129
+ fprintf(stderr, " -f, --fd=FILE_DESCRIPTOR file-descriptor\n");
130
+ fprintf(stderr, " -p, --print-capabilities=PRINT_CAPABILITIES denotes print-capabilities\n");
131
fprintf(stderr, " -h print help and quit\n");
132
133
goto err;
73
--
134
--
74
2.9.3
135
2.35.1
75
76
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
The GLib documentation says "a NULL-terminated array of GOptionEntrys"
2
so we'd better make sure there is a terminator that lets
3
g_option_context_add_main_entries() know when the end of the array has
4
been reached.
2
5
3
Allow block backends to forward drain requests to their devices/users.
6
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
4
The initial intended purpose for this patch is to allow BBs to forward
7
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
5
requests along to BlockJobs, which will want to pause if their associated
8
Message-id: 20220411150057.3009667-1-stefanha@redhat.com
6
BB has entered a drained region.
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
11
contrib/vhost-user-blk/vhost-user-blk.c | 3 ++-
12
1 file changed, 2 insertions(+), 1 deletion(-)
7
13
8
Signed-off-by: John Snow <jsnow@redhat.com>
14
diff --git a/contrib/vhost-user-blk/vhost-user-blk.c b/contrib/vhost-user-blk/vhost-user-blk.c
9
Reviewed-by: Jeff Cody <jcody@redhat.com>
10
Message-id: 20170316212351.13797-3-jsnow@redhat.com
11
Signed-off-by: Jeff Cody <jcody@redhat.com>
12
---
13
block/block-backend.c | 24 ++++++++++++++++++++++--
14
include/sysemu/block-backend.h | 8 ++++++++
15
2 files changed, 30 insertions(+), 2 deletions(-)
16
17
diff --git a/block/block-backend.c b/block/block-backend.c
18
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
19
--- a/block/block-backend.c
16
--- a/contrib/vhost-user-blk/vhost-user-blk.c
20
+++ b/block/block-backend.c
17
+++ b/contrib/vhost-user-blk/vhost-user-blk.c
21
@@ -XXX,XX +XXX,XX @@ struct BlockBackend {
18
@@ -XXX,XX +XXX,XX @@ static GOptionEntry entries[] = {
22
bool allow_write_beyond_eof;
19
{"blk-file", 'b', 0, G_OPTION_ARG_FILENAME, &opt_blk_file,
23
20
"block device or file path", "PATH"},
24
NotifierList remove_bs_notifiers, insert_bs_notifiers;
21
{ "read-only", 'r', 0, G_OPTION_ARG_NONE, &opt_read_only,
25
+
22
- "Enable read-only", NULL }
26
+ int quiesce_counter;
23
+ "Enable read-only", NULL },
24
+ { NULL, },
27
};
25
};
28
26
29
typedef struct BlockBackendAIOCB {
27
int main(int argc, char **argv)
30
@@ -XXX,XX +XXX,XX @@ void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops,
31
void *opaque)
32
{
33
/* All drivers that use blk_set_dev_ops() are qdevified and we want to keep
34
- * it that way, so we can assume blk->dev is a DeviceState if blk->dev_ops
35
- * is set. */
36
+ * it that way, so we can assume blk->dev, if present, is a DeviceState if
37
+ * blk->dev_ops is set. Non-device users may use dev_ops without device. */
38
assert(!blk->legacy_dev);
39
40
blk->dev_ops = ops;
41
blk->dev_opaque = opaque;
42
+
43
+ /* Are we currently quiesced? Should we enforce this right now? */
44
+ if (blk->quiesce_counter && ops->drained_begin) {
45
+ ops->drained_begin(opaque);
46
+ }
47
}
48
49
/*
50
@@ -XXX,XX +XXX,XX @@ static void blk_root_drained_begin(BdrvChild *child)
51
{
52
BlockBackend *blk = child->opaque;
53
54
+ if (++blk->quiesce_counter == 1) {
55
+ if (blk->dev_ops && blk->dev_ops->drained_begin) {
56
+ blk->dev_ops->drained_begin(blk->dev_opaque);
57
+ }
58
+ }
59
+
60
/* Note that blk->root may not be accessible here yet if we are just
61
* attaching to a BlockDriverState that is drained. Use child instead. */
62
63
@@ -XXX,XX +XXX,XX @@ static void blk_root_drained_begin(BdrvChild *child)
64
static void blk_root_drained_end(BdrvChild *child)
65
{
66
BlockBackend *blk = child->opaque;
67
+ assert(blk->quiesce_counter);
68
69
assert(blk->public.io_limits_disabled);
70
--blk->public.io_limits_disabled;
71
+
72
+ if (--blk->quiesce_counter == 0) {
73
+ if (blk->dev_ops && blk->dev_ops->drained_end) {
74
+ blk->dev_ops->drained_end(blk->dev_opaque);
75
+ }
76
+ }
77
}
78
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
79
index XXXXXXX..XXXXXXX 100644
80
--- a/include/sysemu/block-backend.h
81
+++ b/include/sysemu/block-backend.h
82
@@ -XXX,XX +XXX,XX @@ typedef struct BlockDevOps {
83
* Runs when the size changed (e.g. monitor command block_resize)
84
*/
85
void (*resize_cb)(void *opaque);
86
+ /*
87
+ * Runs when the backend receives a drain request.
88
+ */
89
+ void (*drained_begin)(void *opaque);
90
+ /*
91
+ * Runs when the backend's last drain request ends.
92
+ */
93
+ void (*drained_end)(void *opaque);
94
} BlockDevOps;
95
96
/* This struct is embedded in (the private) BlockBackend struct and contains
97
--
28
--
98
2.9.3
29
2.35.1
99
100
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Liu Yiding <liuyd.fnst@fujitsu.com>
2
2
3
The purpose of this shim is to allow us to pause pre-started jobs.
3
virtiofsd has introduced killpriv_v2/no_killpriv_v2 for a while. Add
4
The purpose of *that* is to allow us to buffer a pause request that
4
description of it to docs/helper.
5
will be able to take effect before the job ever does any work, allowing
6
us to create jobs during a quiescent state (under which they will be
7
automatically paused), then resuming the jobs after the critical section
8
in any order, either:
9
5
10
(1) -block_job_start
6
Signed-off-by: Liu Yiding <liuyd.fnst@fujitsu.com>
11
-block_job_resume (via e.g. drained_end)
7
Message-Id: <20220421095151.2231099-1-liuyd.fnst@fujitsu.com>
12
8
13
(2) -block_job_resume (via e.g. drained_end)
9
[Small documentation fixes: s/as client supports/as the client supports/
14
-block_job_start
10
and s/. /. /.
11
--Stefan]
15
12
16
The problem that requires a startup wrapper is the idea that a job must
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
17
start in the busy=true state only its first time-- all subsequent entries
14
---
18
require busy to be false, and the toggling of this state is otherwise
15
docs/tools/virtiofsd.rst | 5 +++++
19
handled during existing pause and yield points.
16
tools/virtiofsd/helper.c | 3 +++
17
2 files changed, 8 insertions(+)
20
18
21
The wrapper simply allows us to mandate that a job can "start," set busy
19
diff --git a/docs/tools/virtiofsd.rst b/docs/tools/virtiofsd.rst
22
to true, then immediately pause only if necessary. We could avoid
23
requiring a wrapper, but all jobs would need to do it, so it's been
24
factored out here.
25
26
Signed-off-by: John Snow <jsnow@redhat.com>
27
Reviewed-by: Jeff Cody <jcody@redhat.com>
28
Message-id: 20170316212351.13797-2-jsnow@redhat.com
29
Signed-off-by: Jeff Cody <jcody@redhat.com>
30
---
31
blockjob.c | 26 +++++++++++++++++++-------
32
1 file changed, 19 insertions(+), 7 deletions(-)
33
34
diff --git a/blockjob.c b/blockjob.c
35
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
36
--- a/blockjob.c
21
--- a/docs/tools/virtiofsd.rst
37
+++ b/blockjob.c
22
+++ b/docs/tools/virtiofsd.rst
38
@@ -XXX,XX +XXX,XX @@ static bool block_job_started(BlockJob *job)
23
@@ -XXX,XX +XXX,XX @@ Options
39
return job->co;
24
label. Server will try to set that label on newly created file
25
atomically wherever possible.
26
27
+ * killpriv_v2|no_killpriv_v2 -
28
+ Enable/disable ``FUSE_HANDLE_KILLPRIV_V2`` support. KILLPRIV_V2 is enabled
29
+ by default as long as the client supports it. Enabling this option helps
30
+ with performance in write path.
31
+
32
.. option:: --socket-path=PATH
33
34
Listen on vhost-user UNIX domain socket at PATH.
35
diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c
36
index XXXXXXX..XXXXXXX 100644
37
--- a/tools/virtiofsd/helper.c
38
+++ b/tools/virtiofsd/helper.c
39
@@ -XXX,XX +XXX,XX @@ void fuse_cmdline_help(void)
40
" -o announce_submounts Announce sub-mount points to the guest\n"
41
" -o posix_acl/no_posix_acl Enable/Disable posix_acl. (default: disabled)\n"
42
" -o security_label/no_security_label Enable/Disable security label. (default: disabled)\n"
43
+ " -o killpriv_v2/no_killpriv_v2\n"
44
+ " Enable/Disable FUSE_HANDLE_KILLPRIV_V2.\n"
45
+ " (default: enabled as long as client supports it)\n"
46
);
40
}
47
}
41
48
42
+/**
43
+ * All jobs must allow a pause point before entering their job proper. This
44
+ * ensures that jobs can be paused prior to being started, then resumed later.
45
+ */
46
+static void coroutine_fn block_job_co_entry(void *opaque)
47
+{
48
+ BlockJob *job = opaque;
49
+
50
+ assert(job && job->driver && job->driver->start);
51
+ block_job_pause_point(job);
52
+ job->driver->start(job);
53
+}
54
+
55
void block_job_start(BlockJob *job)
56
{
57
assert(job && !block_job_started(job) && job->paused &&
58
- !job->busy && job->driver->start);
59
- job->co = qemu_coroutine_create(job->driver->start, job);
60
- if (--job->pause_count == 0) {
61
- job->paused = false;
62
- job->busy = true;
63
- qemu_coroutine_enter(job->co);
64
- }
65
+ job->driver && job->driver->start);
66
+ job->co = qemu_coroutine_create(block_job_co_entry, job);
67
+ job->pause_count--;
68
+ job->busy = true;
69
+ job->paused = false;
70
+ qemu_coroutine_enter(job->co);
71
}
72
73
void block_job_ref(BlockJob *job)
74
--
49
--
75
2.9.3
50
2.35.1
76
77
diff view generated by jsdifflib