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:
Peter Maydell 2018-05-14 17:52:46 +01:00
commit a9cb55a356
5 changed files with 202 additions and 48 deletions

View File

@ -161,6 +161,7 @@ typedef struct BDRVRawState {
bool page_cache_inconsistent:1; bool page_cache_inconsistent:1;
bool has_fallocate; bool has_fallocate;
bool needs_alignment; bool needs_alignment;
bool check_cache_dropped;
PRManager *pr_mgr; PRManager *pr_mgr;
} BDRVRawState; } BDRVRawState;
@ -168,6 +169,7 @@ typedef struct BDRVRawState {
typedef struct BDRVRawReopenState { typedef struct BDRVRawReopenState {
int fd; int fd;
int open_flags; int open_flags;
bool check_cache_dropped;
} BDRVRawReopenState; } BDRVRawReopenState;
static int fd_open(BlockDriverState *bs); static int fd_open(BlockDriverState *bs);
@ -415,6 +417,11 @@ static QemuOptsList raw_runtime_opts = {
.type = QEMU_OPT_STRING, .type = QEMU_OPT_STRING,
.help = "id of persistent reservation manager object (default: none)", .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 */ } { /* 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; s->open_flags = open_flags;
raw_parse_flags(bdrv_flags, &s->open_flags); raw_parse_flags(bdrv_flags, &s->open_flags);
@ -777,6 +787,7 @@ static int raw_reopen_prepare(BDRVReopenState *state,
{ {
BDRVRawState *s; BDRVRawState *s;
BDRVRawReopenState *rs; BDRVRawReopenState *rs;
QemuOpts *opts;
int ret = 0; int ret = 0;
Error *local_err = NULL; Error *local_err = NULL;
@ -787,6 +798,19 @@ static int raw_reopen_prepare(BDRVReopenState *state,
state->opaque = g_new0(BDRVRawReopenState, 1); state->opaque = g_new0(BDRVRawReopenState, 1);
rs = state->opaque; 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) { if (s->type == FTYPE_CD) {
rs->open_flags |= O_NONBLOCK; rs->open_flags |= O_NONBLOCK;
@ -794,8 +818,6 @@ static int raw_reopen_prepare(BDRVReopenState *state,
raw_parse_flags(state->flags, &rs->open_flags); raw_parse_flags(state->flags, &rs->open_flags);
rs->fd = -1;
int fcntl_flags = O_APPEND | O_NONBLOCK; int fcntl_flags = O_APPEND | O_NONBLOCK;
#ifdef O_NOATIME #ifdef O_NOATIME
fcntl_flags |= O_NOATIME; fcntl_flags |= O_NOATIME;
@ -850,6 +872,8 @@ static int raw_reopen_prepare(BDRVReopenState *state,
} }
} }
out:
qemu_opts_del(opts);
return ret; return ret;
} }
@ -858,6 +882,7 @@ static void raw_reopen_commit(BDRVReopenState *state)
BDRVRawReopenState *rs = state->opaque; BDRVRawReopenState *rs = state->opaque;
BDRVRawState *s = state->bs->opaque; BDRVRawState *s = state->bs->opaque;
s->check_cache_dropped = rs->check_cache_dropped;
s->open_flags = rs->open_flags; s->open_flags = rs->open_flags;
qemu_close(s->fd); qemu_close(s->fd);
@ -2236,6 +2261,120 @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
return ret | BDRV_BLOCK_OFFSET_VALID; 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, static coroutine_fn BlockAIOCB *raw_aio_pdiscard(BlockDriverState *bs,
int64_t offset, int bytes, int64_t offset, int bytes,
BlockCompletionFunc *cb, void *opaque) BlockCompletionFunc *cb, void *opaque)
@ -2328,6 +2467,7 @@ BlockDriver bdrv_file = {
.bdrv_co_create_opts = raw_co_create_opts, .bdrv_co_create_opts = raw_co_create_opts,
.bdrv_has_zero_init = bdrv_has_zero_init_1, .bdrv_has_zero_init = bdrv_has_zero_init_1,
.bdrv_co_block_status = raw_co_block_status, .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_pwrite_zeroes = raw_co_pwrite_zeroes,
.bdrv_co_preadv = raw_co_preadv, .bdrv_co_preadv = raw_co_preadv,
@ -2805,6 +2945,7 @@ static BlockDriver bdrv_host_device = {
.bdrv_reopen_abort = raw_reopen_abort, .bdrv_reopen_abort = raw_reopen_abort,
.bdrv_co_create_opts = hdev_co_create_opts, .bdrv_co_create_opts = hdev_co_create_opts,
.create_opts = &raw_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_pwrite_zeroes = hdev_co_pwrite_zeroes,
.bdrv_co_preadv = raw_co_preadv, .bdrv_co_preadv = raw_co_preadv,
@ -2927,6 +3068,7 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_reopen_abort = raw_reopen_abort, .bdrv_reopen_abort = raw_reopen_abort,
.bdrv_co_create_opts = hdev_co_create_opts, .bdrv_co_create_opts = hdev_co_create_opts,
.create_opts = &raw_create_opts, .create_opts = &raw_create_opts,
.bdrv_co_invalidate_cache = raw_co_invalidate_cache,
.bdrv_co_preadv = raw_co_preadv, .bdrv_co_preadv = raw_co_preadv,

View File

@ -988,19 +988,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
return job; 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) void block_job_early_fail(BlockJob *job)
{ {
assert(job->status == BLOCK_JOB_STATUS_CREATED); 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 * Conditionally enter a block_job pending a call to fn() while
* under the block_job_lock critical section. * under the block_job_lock critical section.

View File

@ -168,20 +168,6 @@ void block_job_sleep_ns(BlockJob *job, int64_t ns);
*/ */
void block_job_yield(BlockJob *job); 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: * block_job_early_fail:
* @bs: The block device. * @bs: The block device.

View File

@ -2530,6 +2530,10 @@
# @locking: whether to enable file locking. If set to 'auto', only enable # @locking: whether to enable file locking. If set to 'auto', only enable
# when Open File Descriptor (OFD) locking API is available # when Open File Descriptor (OFD) locking API is available
# (default: auto, since 2.10) # (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 # Since: 2.9
## ##
@ -2537,7 +2541,8 @@
'data': { 'filename': 'str', 'data': { 'filename': 'str',
'*pr-manager': 'str', '*pr-manager': 'str',
'*locking': 'OnOffAuto', '*locking': 'OnOffAuto',
'*aio': 'BlockdevAioOptions' } } '*aio': 'BlockdevAioOptions',
'*x-check-cache-dropped': 'bool' } }
## ##
# @BlockdevOptionsNull: # @BlockdevOptionsNull:

View File

@ -224,9 +224,8 @@ our $NonptrType;
our $Type; our $Type;
our $Declare; our $Declare;
our $UTF8 = qr { our $NON_ASCII_UTF8 = qr{
[\x09\x0A\x0D\x20-\x7E] # ASCII [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
| [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
@ -235,6 +234,11 @@ our $UTF8 = qr {
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
}x; }x;
our $UTF8 = qr{
[\x09\x0A\x0D\x20-\x7E] # ASCII
| $NON_ASCII_UTF8
}x;
# There are still some false positives, but this catches most # There are still some false positives, but this catches most
# common cases. # common cases.
our $typeTypedefs = qr{(?x: our $typeTypedefs = qr{(?x:
@ -1207,6 +1211,11 @@ sub process {
my $signoff = 0; my $signoff = 0;
my $is_patch = 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 @report = ();
our $cnt_lines = 0; our $cnt_lines = 0;
our $cnt_error = 0; our $cnt_error = 0;
@ -1359,7 +1368,6 @@ sub process {
if ($line =~ /^diff --git.*?(\S+)$/) { if ($line =~ /^diff --git.*?(\S+)$/) {
$realfile = $1; $realfile = $1;
$realfile =~ s@^([^/]*)/@@; $realfile =~ s@^([^/]*)/@@;
} elsif ($line =~ /^\+\+\+\s+(\S+)/) { } elsif ($line =~ /^\+\+\+\s+(\S+)/) {
$realfile = $1; $realfile = $1;
$realfile =~ s@^([^/]*)/@@; $realfile =~ s@^([^/]*)/@@;
@ -1398,6 +1406,8 @@ sub process {
if ($line =~ /^\s*signed-off-by:/i) { if ($line =~ /^\s*signed-off-by:/i) {
# This is a signoff, if ugly, so do not double report. # This is a signoff, if ugly, so do not double report.
$signoff++; $signoff++;
$in_commit_log = 0;
if (!($line =~ /^\s*Signed-off-by:/)) { if (!($line =~ /^\s*Signed-off-by:/)) {
ERROR("The correct form is \"Signed-off-by\"\n" . ERROR("The correct form is \"Signed-off-by\"\n" .
$herecurr); $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 # Check for wrappage within a valid hunk of the file
if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) { if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) {
ERROR("patch seems to be corrupt (line wrapped?)\n" . 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); 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 # ignore non-hunk lines and lines being removed
next if (!$hunk_line || $line =~ /^-/); next if (!$hunk_line || $line =~ /^-/);