Block pull request
* Support -drive cache.direct=off live migration for POSIX files -----BEGIN PGP SIGNATURE----- iQEcBAABAgAGBQJa9rOXAAoJEJykq7OBq3PIsEYH/RQtBexXbqiosBvHkoZUwEjG +lepQXEgJjhNoHil23q/2Ilo16w4gSoV0HA1AGs2Ka5eoWvOj+mwmE+mxPV3mdBy jJt0FVWJxh0Ak9bKEEl3LYDu/yRt2gAyiCWVZcgTJNXepXagLMcwZ8mNsyb4R+Lh EWroCBGp1de4kUhNmx/639DQCc5Wm9c6rTHnBt/jfCo2IRA6Wm/AsBXZKhZ4+RY9 4qyujA7rUjCK2lOHHOw2tsABxhsfMiLlbW4K78Z5cIzjudMHhUMgvkFp7FvDEmQC 61b0ogLErewhKwGdaVrjN4iSnFv2mJz1GJQGe5n9C2CYvUzxlEW7l+mV5kxNjsk= =GmNn -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' into staging Block pull request * Support -drive cache.direct=off live migration for POSIX files # gpg: Signature made Sat 12 May 2018 10:27:51 BST # gpg: using RSA key 9CA4ABB381AB73C8 # gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>" # gpg: aka "Stefan Hajnoczi <stefanha@gmail.com>" # Primary key fingerprint: 8695 A8BF D3F9 7CDA AC35 775A 9CA4 ABB3 81AB 73C8 * remotes/stefanha/tags/block-pull-request: block/file-posix: add x-check-page-cache=on|off option block/file-posix: implement bdrv_co_invalidate_cache() on Linux checkpatch: reduce MAINTAINERS update message frequency checkpatch: emit a warning on file add/move/delete checkpatch: ignore email headers better checkpatch: check utf-8 content from a commit log when it's missing from charset checkpatch: add a --strict check for utf-8 in commit logs blockjob: drop block_job_pause/resume_all() Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
a9cb55a356
@ -161,6 +161,7 @@ typedef struct BDRVRawState {
|
||||
bool page_cache_inconsistent:1;
|
||||
bool has_fallocate;
|
||||
bool needs_alignment;
|
||||
bool check_cache_dropped;
|
||||
|
||||
PRManager *pr_mgr;
|
||||
} BDRVRawState;
|
||||
@ -168,6 +169,7 @@ typedef struct BDRVRawState {
|
||||
typedef struct BDRVRawReopenState {
|
||||
int fd;
|
||||
int open_flags;
|
||||
bool check_cache_dropped;
|
||||
} BDRVRawReopenState;
|
||||
|
||||
static int fd_open(BlockDriverState *bs);
|
||||
@ -415,6 +417,11 @@ static QemuOptsList raw_runtime_opts = {
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "id of persistent reservation manager object (default: none)",
|
||||
},
|
||||
{
|
||||
.name = "x-check-cache-dropped",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "check that page cache was dropped on live migration (default: off)"
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
@ -500,6 +507,9 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
}
|
||||
}
|
||||
|
||||
s->check_cache_dropped = qemu_opt_get_bool(opts, "x-check-cache-dropped",
|
||||
false);
|
||||
|
||||
s->open_flags = open_flags;
|
||||
raw_parse_flags(bdrv_flags, &s->open_flags);
|
||||
|
||||
@ -777,6 +787,7 @@ static int raw_reopen_prepare(BDRVReopenState *state,
|
||||
{
|
||||
BDRVRawState *s;
|
||||
BDRVRawReopenState *rs;
|
||||
QemuOpts *opts;
|
||||
int ret = 0;
|
||||
Error *local_err = NULL;
|
||||
|
||||
@ -787,6 +798,19 @@ static int raw_reopen_prepare(BDRVReopenState *state,
|
||||
|
||||
state->opaque = g_new0(BDRVRawReopenState, 1);
|
||||
rs = state->opaque;
|
||||
rs->fd = -1;
|
||||
|
||||
/* Handle options changes */
|
||||
opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort);
|
||||
qemu_opts_absorb_qdict(opts, state->options, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rs->check_cache_dropped = qemu_opt_get_bool(opts, "x-check-cache-dropped",
|
||||
s->check_cache_dropped);
|
||||
|
||||
if (s->type == FTYPE_CD) {
|
||||
rs->open_flags |= O_NONBLOCK;
|
||||
@ -794,8 +818,6 @@ static int raw_reopen_prepare(BDRVReopenState *state,
|
||||
|
||||
raw_parse_flags(state->flags, &rs->open_flags);
|
||||
|
||||
rs->fd = -1;
|
||||
|
||||
int fcntl_flags = O_APPEND | O_NONBLOCK;
|
||||
#ifdef O_NOATIME
|
||||
fcntl_flags |= O_NOATIME;
|
||||
@ -850,6 +872,8 @@ static int raw_reopen_prepare(BDRVReopenState *state,
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
qemu_opts_del(opts);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -858,6 +882,7 @@ static void raw_reopen_commit(BDRVReopenState *state)
|
||||
BDRVRawReopenState *rs = state->opaque;
|
||||
BDRVRawState *s = state->bs->opaque;
|
||||
|
||||
s->check_cache_dropped = rs->check_cache_dropped;
|
||||
s->open_flags = rs->open_flags;
|
||||
|
||||
qemu_close(s->fd);
|
||||
@ -2236,6 +2261,120 @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
|
||||
return ret | BDRV_BLOCK_OFFSET_VALID;
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
/* Verify that the file is not in the page cache */
|
||||
static void check_cache_dropped(BlockDriverState *bs, Error **errp)
|
||||
{
|
||||
const size_t window_size = 128 * 1024 * 1024;
|
||||
BDRVRawState *s = bs->opaque;
|
||||
void *window = NULL;
|
||||
size_t length = 0;
|
||||
unsigned char *vec;
|
||||
size_t page_size;
|
||||
off_t offset;
|
||||
off_t end;
|
||||
|
||||
/* mincore(2) page status information requires 1 byte per page */
|
||||
page_size = sysconf(_SC_PAGESIZE);
|
||||
vec = g_malloc(DIV_ROUND_UP(window_size, page_size));
|
||||
|
||||
end = raw_getlength(bs);
|
||||
|
||||
for (offset = 0; offset < end; offset += window_size) {
|
||||
void *new_window;
|
||||
size_t new_length;
|
||||
size_t vec_end;
|
||||
size_t i;
|
||||
int ret;
|
||||
|
||||
/* Unmap previous window if size has changed */
|
||||
new_length = MIN(end - offset, window_size);
|
||||
if (new_length != length) {
|
||||
munmap(window, length);
|
||||
window = NULL;
|
||||
length = 0;
|
||||
}
|
||||
|
||||
new_window = mmap(window, new_length, PROT_NONE, MAP_PRIVATE,
|
||||
s->fd, offset);
|
||||
if (new_window == MAP_FAILED) {
|
||||
error_setg_errno(errp, errno, "mmap failed");
|
||||
break;
|
||||
}
|
||||
|
||||
window = new_window;
|
||||
length = new_length;
|
||||
|
||||
ret = mincore(window, length, vec);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, errno, "mincore failed");
|
||||
break;
|
||||
}
|
||||
|
||||
vec_end = DIV_ROUND_UP(length, page_size);
|
||||
for (i = 0; i < vec_end; i++) {
|
||||
if (vec[i] & 0x1) {
|
||||
error_setg(errp, "page cache still in use!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (window) {
|
||||
munmap(window, length);
|
||||
}
|
||||
|
||||
g_free(vec);
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
|
||||
static void coroutine_fn raw_co_invalidate_cache(BlockDriverState *bs,
|
||||
Error **errp)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int ret;
|
||||
|
||||
ret = fd_open(bs);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "The file descriptor is not open");
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->open_flags & O_DIRECT) {
|
||||
return; /* No host kernel page cache */
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
/* This sets the scene for the next syscall... */
|
||||
ret = bdrv_co_flush(bs);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "flush failed");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Linux does not invalidate pages that are dirty, locked, or mmapped by a
|
||||
* process. These limitations are okay because we just fsynced the file,
|
||||
* we don't use mmap, and the file should not be in use by other processes.
|
||||
*/
|
||||
ret = posix_fadvise(s->fd, 0, 0, POSIX_FADV_DONTNEED);
|
||||
if (ret != 0) { /* the return value is a positive errno */
|
||||
error_setg_errno(errp, ret, "fadvise failed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->check_cache_dropped) {
|
||||
check_cache_dropped(bs, errp);
|
||||
}
|
||||
#else /* __linux__ */
|
||||
/* Do nothing. Live migration to a remote host with cache.direct=off is
|
||||
* unsupported on other host operating systems. Cache consistency issues
|
||||
* may occur but no error is reported here, partly because that's the
|
||||
* historical behavior and partly because it's hard to differentiate valid
|
||||
* configurations that should not cause errors.
|
||||
*/
|
||||
#endif /* !__linux__ */
|
||||
}
|
||||
|
||||
static coroutine_fn BlockAIOCB *raw_aio_pdiscard(BlockDriverState *bs,
|
||||
int64_t offset, int bytes,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
@ -2328,6 +2467,7 @@ BlockDriver bdrv_file = {
|
||||
.bdrv_co_create_opts = raw_co_create_opts,
|
||||
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
||||
.bdrv_co_block_status = raw_co_block_status,
|
||||
.bdrv_co_invalidate_cache = raw_co_invalidate_cache,
|
||||
.bdrv_co_pwrite_zeroes = raw_co_pwrite_zeroes,
|
||||
|
||||
.bdrv_co_preadv = raw_co_preadv,
|
||||
@ -2805,6 +2945,7 @@ static BlockDriver bdrv_host_device = {
|
||||
.bdrv_reopen_abort = raw_reopen_abort,
|
||||
.bdrv_co_create_opts = hdev_co_create_opts,
|
||||
.create_opts = &raw_create_opts,
|
||||
.bdrv_co_invalidate_cache = raw_co_invalidate_cache,
|
||||
.bdrv_co_pwrite_zeroes = hdev_co_pwrite_zeroes,
|
||||
|
||||
.bdrv_co_preadv = raw_co_preadv,
|
||||
@ -2927,6 +3068,7 @@ static BlockDriver bdrv_host_cdrom = {
|
||||
.bdrv_reopen_abort = raw_reopen_abort,
|
||||
.bdrv_co_create_opts = hdev_co_create_opts,
|
||||
.create_opts = &raw_create_opts,
|
||||
.bdrv_co_invalidate_cache = raw_co_invalidate_cache,
|
||||
|
||||
|
||||
.bdrv_co_preadv = raw_co_preadv,
|
||||
|
27
blockjob.c
27
blockjob.c
@ -988,19 +988,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
|
||||
return job;
|
||||
}
|
||||
|
||||
void block_job_pause_all(void)
|
||||
{
|
||||
BlockJob *job = NULL;
|
||||
while ((job = block_job_next(job))) {
|
||||
AioContext *aio_context = blk_get_aio_context(job->blk);
|
||||
|
||||
aio_context_acquire(aio_context);
|
||||
block_job_ref(job);
|
||||
block_job_pause(job);
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
}
|
||||
|
||||
void block_job_early_fail(BlockJob *job)
|
||||
{
|
||||
assert(job->status == BLOCK_JOB_STATUS_CREATED);
|
||||
@ -1078,20 +1065,6 @@ void coroutine_fn block_job_pause_point(BlockJob *job)
|
||||
}
|
||||
}
|
||||
|
||||
void block_job_resume_all(void)
|
||||
{
|
||||
BlockJob *job, *next;
|
||||
|
||||
QLIST_FOREACH_SAFE(job, &block_jobs, job_list, next) {
|
||||
AioContext *aio_context = blk_get_aio_context(job->blk);
|
||||
|
||||
aio_context_acquire(aio_context);
|
||||
block_job_resume(job);
|
||||
block_job_unref(job);
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Conditionally enter a block_job pending a call to fn() while
|
||||
* under the block_job_lock critical section.
|
||||
|
@ -168,20 +168,6 @@ void block_job_sleep_ns(BlockJob *job, int64_t ns);
|
||||
*/
|
||||
void block_job_yield(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_pause_all:
|
||||
*
|
||||
* Asynchronously pause all jobs.
|
||||
*/
|
||||
void block_job_pause_all(void);
|
||||
|
||||
/**
|
||||
* block_job_resume_all:
|
||||
*
|
||||
* Resume all block jobs. Must be paired with a preceding block_job_pause_all.
|
||||
*/
|
||||
void block_job_resume_all(void);
|
||||
|
||||
/**
|
||||
* block_job_early_fail:
|
||||
* @bs: The block device.
|
||||
|
@ -2530,6 +2530,10 @@
|
||||
# @locking: whether to enable file locking. If set to 'auto', only enable
|
||||
# when Open File Descriptor (OFD) locking API is available
|
||||
# (default: auto, since 2.10)
|
||||
# @x-check-cache-dropped: whether to check that page cache was dropped on live
|
||||
# migration. May cause noticeable delays if the image
|
||||
# file is large, do not use in production.
|
||||
# (default: off) (since: 2.13)
|
||||
#
|
||||
# Since: 2.9
|
||||
##
|
||||
@ -2537,7 +2541,8 @@
|
||||
'data': { 'filename': 'str',
|
||||
'*pr-manager': 'str',
|
||||
'*locking': 'OnOffAuto',
|
||||
'*aio': 'BlockdevAioOptions' } }
|
||||
'*aio': 'BlockdevAioOptions',
|
||||
'*x-check-cache-dropped': 'bool' } }
|
||||
|
||||
##
|
||||
# @BlockdevOptionsNull:
|
||||
|
@ -224,9 +224,8 @@ our $NonptrType;
|
||||
our $Type;
|
||||
our $Declare;
|
||||
|
||||
our $UTF8 = qr {
|
||||
[\x09\x0A\x0D\x20-\x7E] # ASCII
|
||||
| [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
|
||||
our $NON_ASCII_UTF8 = qr{
|
||||
[\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
|
||||
| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
|
||||
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
|
||||
| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
|
||||
@ -235,6 +234,11 @@ our $UTF8 = qr {
|
||||
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
|
||||
}x;
|
||||
|
||||
our $UTF8 = qr{
|
||||
[\x09\x0A\x0D\x20-\x7E] # ASCII
|
||||
| $NON_ASCII_UTF8
|
||||
}x;
|
||||
|
||||
# There are still some false positives, but this catches most
|
||||
# common cases.
|
||||
our $typeTypedefs = qr{(?x:
|
||||
@ -1207,6 +1211,11 @@ sub process {
|
||||
my $signoff = 0;
|
||||
my $is_patch = 0;
|
||||
|
||||
my $in_header_lines = $file ? 0 : 1;
|
||||
my $in_commit_log = 0; #Scanning lines before patch
|
||||
my $reported_maintainer_file = 0;
|
||||
my $non_utf8_charset = 0;
|
||||
|
||||
our @report = ();
|
||||
our $cnt_lines = 0;
|
||||
our $cnt_error = 0;
|
||||
@ -1359,7 +1368,6 @@ sub process {
|
||||
if ($line =~ /^diff --git.*?(\S+)$/) {
|
||||
$realfile = $1;
|
||||
$realfile =~ s@^([^/]*)/@@;
|
||||
|
||||
} elsif ($line =~ /^\+\+\+\s+(\S+)/) {
|
||||
$realfile = $1;
|
||||
$realfile =~ s@^([^/]*)/@@;
|
||||
@ -1398,6 +1406,8 @@ sub process {
|
||||
if ($line =~ /^\s*signed-off-by:/i) {
|
||||
# This is a signoff, if ugly, so do not double report.
|
||||
$signoff++;
|
||||
$in_commit_log = 0;
|
||||
|
||||
if (!($line =~ /^\s*Signed-off-by:/)) {
|
||||
ERROR("The correct form is \"Signed-off-by\"\n" .
|
||||
$herecurr);
|
||||
@ -1408,6 +1418,22 @@ sub process {
|
||||
}
|
||||
}
|
||||
|
||||
# Check if MAINTAINERS is being updated. If so, there's probably no need to
|
||||
# emit the "does MAINTAINERS need updating?" message on file add/move/delete
|
||||
if ($line =~ /^\s*MAINTAINERS\s*\|/) {
|
||||
$reported_maintainer_file = 1;
|
||||
}
|
||||
|
||||
# Check for added, moved or deleted files
|
||||
if (!$reported_maintainer_file && !$in_commit_log &&
|
||||
($line =~ /^(?:new|deleted) file mode\s*\d+\s*$/ ||
|
||||
$line =~ /^rename (?:from|to) [\w\/\.\-]+\s*$/ ||
|
||||
($line =~ /\{\s*([\w\/\.\-]*)\s*\=\>\s*([\w\/\.\-]*)\s*\}/ &&
|
||||
(defined($1) || defined($2))))) {
|
||||
$reported_maintainer_file = 1;
|
||||
WARN("added, moved or deleted file(s), does MAINTAINERS need updating?\n" . $herecurr);
|
||||
}
|
||||
|
||||
# Check for wrappage within a valid hunk of the file
|
||||
if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) {
|
||||
ERROR("patch seems to be corrupt (line wrapped?)\n" .
|
||||
@ -1426,6 +1452,28 @@ sub process {
|
||||
ERROR("Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $hereptr);
|
||||
}
|
||||
|
||||
# Check if it's the start of a commit log
|
||||
# (not a header line and we haven't seen the patch filename)
|
||||
if ($in_header_lines && $realfile =~ /^$/ &&
|
||||
!($rawline =~ /^\s+\S/ ||
|
||||
$rawline =~ /^(commit\b|from\b|[\w-]+:).*$/i)) {
|
||||
$in_header_lines = 0;
|
||||
$in_commit_log = 1;
|
||||
}
|
||||
|
||||
# Check if there is UTF-8 in a commit log when a mail header has explicitly
|
||||
# declined it, i.e defined some charset where it is missing.
|
||||
if ($in_header_lines &&
|
||||
$rawline =~ /^Content-Type:.+charset="(.+)".*$/ &&
|
||||
$1 !~ /utf-8/i) {
|
||||
$non_utf8_charset = 1;
|
||||
}
|
||||
|
||||
if ($in_commit_log && $non_utf8_charset && $realfile =~ /^$/ &&
|
||||
$rawline =~ /$NON_ASCII_UTF8/) {
|
||||
WARN("8-bit UTF-8 used in possible commit log\n" . $herecurr);
|
||||
}
|
||||
|
||||
# ignore non-hunk lines and lines being removed
|
||||
next if (!$hunk_line || $line =~ /^-/);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user