mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
sparsify: Get free space on TMPDIR and give a warning if we estimate it is too little.
This commit is contained in:
5
TODO
5
TODO
@@ -465,11 +465,6 @@ opened with O_CLOEXEC. Therefore we need to examine every call to:
|
|||||||
virt-sparsify enhancements
|
virt-sparsify enhancements
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
TMPDIR should be checked to ensure that we won't run out of space
|
|
||||||
during the conversion, since current behaviour is very bad when this
|
|
||||||
happens (it usually causes virt-sparsify to hang). This requires
|
|
||||||
writing a small C binding to statvfs for OCaml.
|
|
||||||
|
|
||||||
'virt-sparsify --whitelist' option to generate skeletons (for
|
'virt-sparsify --whitelist' option to generate skeletons (for
|
||||||
debugging, bug forensics, diagnosis). The whilelist option would
|
debugging, bug forensics, diagnosis). The whilelist option would
|
||||||
specify a list of files to be *preserved*. All other files in the
|
specify a list of files to be *preserved*. All other files in the
|
||||||
|
|||||||
@@ -239,6 +239,7 @@ resize/progress-c.c
|
|||||||
resize/tty-c.c
|
resize/tty-c.c
|
||||||
resize/uri-c.c
|
resize/uri-c.c
|
||||||
ruby/ext/guestfs/_guestfs.c
|
ruby/ext/guestfs/_guestfs.c
|
||||||
|
sparsify/statvfs-c.c
|
||||||
src/actions-0.c
|
src/actions-0.c
|
||||||
src/actions-1.c
|
src/actions-1.c
|
||||||
src/actions-2.c
|
src/actions-2.c
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ CLEANFILES = *~ *.cmi *.cmo *.cmx *.cmxa *.o virt-sparsify
|
|||||||
|
|
||||||
# Alphabetical order.
|
# Alphabetical order.
|
||||||
SOURCES = \
|
SOURCES = \
|
||||||
sparsify.ml
|
sparsify.ml \
|
||||||
|
statvfs-c.c
|
||||||
|
|
||||||
if HAVE_OCAML
|
if HAVE_OCAML
|
||||||
|
|
||||||
@@ -39,6 +40,7 @@ OBJECTS = \
|
|||||||
$(top_builddir)/resize/common_utils.cmx \
|
$(top_builddir)/resize/common_utils.cmx \
|
||||||
$(top_builddir)/resize/tTY.cmx \
|
$(top_builddir)/resize/tTY.cmx \
|
||||||
$(top_builddir)/resize/progress.cmx \
|
$(top_builddir)/resize/progress.cmx \
|
||||||
|
statvfs-c.o \
|
||||||
sparsify.cmx
|
sparsify.cmx
|
||||||
|
|
||||||
bin_SCRIPTS = virt-sparsify
|
bin_SCRIPTS = virt-sparsify
|
||||||
|
|||||||
@@ -26,12 +26,15 @@ module G = Guestfs
|
|||||||
|
|
||||||
open Common_utils
|
open Common_utils
|
||||||
|
|
||||||
|
external statvfs_free_space : string -> int64 =
|
||||||
|
"virt_sparsify_statvfs_free_space"
|
||||||
|
|
||||||
let () = Random.self_init ()
|
let () = Random.self_init ()
|
||||||
|
|
||||||
(* Command line argument parsing. *)
|
(* Command line argument parsing. *)
|
||||||
let prog = Filename.basename Sys.executable_name
|
let prog = Filename.basename Sys.executable_name
|
||||||
|
|
||||||
let indisk, outdisk, compress, convert, debug_gc,
|
let indisk, outdisk, check_tmpdir, compress, convert, debug_gc,
|
||||||
format, ignores, machine_readable,
|
format, ignores, machine_readable,
|
||||||
option, quiet, verbose, trace, zeroes =
|
option, quiet, verbose, trace, zeroes =
|
||||||
let display_version () =
|
let display_version () =
|
||||||
@@ -44,6 +47,17 @@ let indisk, outdisk, compress, convert, debug_gc,
|
|||||||
|
|
||||||
let add xs s = xs := s :: !xs in
|
let add xs s = xs := s :: !xs in
|
||||||
|
|
||||||
|
let check_tmpdir = ref `Warn in
|
||||||
|
let set_check_tmpdir = function
|
||||||
|
| "ignore" | "i" -> check_tmpdir := `Ignore
|
||||||
|
| "continue" | "cont" | "c" -> check_tmpdir := `Continue
|
||||||
|
| "warn" | "warning" | "w" -> check_tmpdir := `Warn
|
||||||
|
| "fail" | "f" | "error" -> check_tmpdir := `Fail
|
||||||
|
| str ->
|
||||||
|
eprintf (f_"--check-tmpdir: unknown argument `%s'\n") str;
|
||||||
|
exit 1
|
||||||
|
in
|
||||||
|
|
||||||
let compress = ref false in
|
let compress = ref false in
|
||||||
let convert = ref "" in
|
let convert = ref "" in
|
||||||
let debug_gc = ref false in
|
let debug_gc = ref false in
|
||||||
@@ -57,6 +71,7 @@ let indisk, outdisk, compress, convert, debug_gc,
|
|||||||
let zeroes = ref [] in
|
let zeroes = ref [] in
|
||||||
|
|
||||||
let argspec = Arg.align [
|
let argspec = Arg.align [
|
||||||
|
"--check-tmpdir", Arg.String set_check_tmpdir, "ignore|..." ^ " " ^ s_"Check there is enough space in $TMPDIR";
|
||||||
"--compress", Arg.Set compress, " " ^ s_"Compressed output format";
|
"--compress", Arg.Set compress, " " ^ s_"Compressed output format";
|
||||||
"--convert", Arg.Set_string convert, s_"format" ^ " " ^ s_"Format of output disk (default: same as input)";
|
"--convert", Arg.Set_string convert, s_"format" ^ " " ^ s_"Format of output disk (default: same as input)";
|
||||||
"--debug-gc", Arg.Set debug_gc, " " ^ s_"Debug GC and memory allocations";
|
"--debug-gc", Arg.Set debug_gc, " " ^ s_"Debug GC and memory allocations";
|
||||||
@@ -90,6 +105,7 @@ read the man page virt-sparsify(1).
|
|||||||
Arg.parse argspec anon_fun usage_msg;
|
Arg.parse argspec anon_fun usage_msg;
|
||||||
|
|
||||||
(* Dereference the rest of the args. *)
|
(* Dereference the rest of the args. *)
|
||||||
|
let check_tmpdir = !check_tmpdir in
|
||||||
let compress = !compress in
|
let compress = !compress in
|
||||||
let convert = match !convert with "" -> None | str -> Some str in
|
let convert = match !convert with "" -> None | str -> Some str in
|
||||||
let debug_gc = !debug_gc in
|
let debug_gc = !debug_gc in
|
||||||
@@ -151,7 +167,7 @@ read the man page virt-sparsify(1).
|
|||||||
if contains_colon outdisk then
|
if contains_colon outdisk then
|
||||||
error (f_"output filename '%s' contains a colon (':'); qemu-img command line syntax prevents us from using such an image") outdisk;
|
error (f_"output filename '%s' contains a colon (':'); qemu-img command line syntax prevents us from using such an image") outdisk;
|
||||||
|
|
||||||
indisk, outdisk, compress, convert,
|
indisk, outdisk, check_tmpdir, compress, convert,
|
||||||
debug_gc, format, ignores, machine_readable,
|
debug_gc, format, ignores, machine_readable,
|
||||||
option, quiet, verbose, trace, zeroes
|
option, quiet, verbose, trace, zeroes
|
||||||
|
|
||||||
@@ -213,9 +229,58 @@ let () =
|
|||||||
if output_format = "raw" && compress then
|
if output_format = "raw" && compress then
|
||||||
error (f_"--compress cannot be used for raw output. Remove this option or use --convert qcow2.")
|
error (f_"--compress cannot be used for raw output. Remove this option or use --convert qcow2.")
|
||||||
|
|
||||||
|
(* Get virtual size of the input disk. *)
|
||||||
|
let virtual_size = (new G.guestfs ())#disk_virtual_size indisk
|
||||||
let () =
|
let () =
|
||||||
if not quiet then
|
if not quiet then
|
||||||
printf (f_"Create overlay file to protect source disk ...\n%!")
|
printf (f_"Input disk virtual size = %Ld bytes (%s)\n%!")
|
||||||
|
virtual_size (human_size virtual_size)
|
||||||
|
|
||||||
|
(* Check there is enough space in $TMPDIR. *)
|
||||||
|
let tmpdir = Filename.get_temp_dir_name ()
|
||||||
|
|
||||||
|
let () =
|
||||||
|
let print_warning () =
|
||||||
|
let free_space = statvfs_free_space tmpdir in
|
||||||
|
let extra_needed = virtual_size -^ free_space in
|
||||||
|
if extra_needed > 0L then (
|
||||||
|
eprintf (f_"\
|
||||||
|
|
||||||
|
WARNING: There may not be enough free space on %s.
|
||||||
|
You may need to set TMPDIR to point to a directory with more free space.
|
||||||
|
|
||||||
|
Max needed: %s. Free: %s. May need another %s.
|
||||||
|
|
||||||
|
Note this is an overestimate. If the guest disk is full of data
|
||||||
|
then not as much free space would be required.
|
||||||
|
|
||||||
|
You can ignore this warning or change it to a hard failure using the
|
||||||
|
--check-tmpdir=(ignore|continue|warn|fail) option. See virt-sysprep(1).
|
||||||
|
|
||||||
|
%!")
|
||||||
|
tmpdir (human_size virtual_size)
|
||||||
|
(human_size free_space) (human_size extra_needed);
|
||||||
|
true
|
||||||
|
) else false
|
||||||
|
in
|
||||||
|
|
||||||
|
match check_tmpdir with
|
||||||
|
| `Ignore -> ()
|
||||||
|
| `Continue -> ignore (print_warning ())
|
||||||
|
| `Warn ->
|
||||||
|
if print_warning () then (
|
||||||
|
eprintf "Press RETURN to continue or ^C to quit.\n%!";
|
||||||
|
ignore (read_line ())
|
||||||
|
);
|
||||||
|
| `Fail ->
|
||||||
|
if print_warning () then (
|
||||||
|
eprintf "Exiting because --check-tmpdir=fail was set.\n%!";
|
||||||
|
exit 2
|
||||||
|
)
|
||||||
|
|
||||||
|
let () =
|
||||||
|
if not quiet then
|
||||||
|
printf (f_"Create overlay file in %s to protect source disk ...\n%!") tmpdir
|
||||||
|
|
||||||
(* Create the temporary overlay file. *)
|
(* Create the temporary overlay file. *)
|
||||||
let overlaydisk =
|
let overlaydisk =
|
||||||
|
|||||||
47
sparsify/statvfs-c.c
Normal file
47
sparsify/statvfs-c.c
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/* virt-sparsify - interface to statvfs
|
||||||
|
* Copyright (C) 2013 Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/statvfs.h>
|
||||||
|
|
||||||
|
#include <caml/alloc.h>
|
||||||
|
#include <caml/fail.h>
|
||||||
|
#include <caml/memory.h>
|
||||||
|
#include <caml/mlvalues.h>
|
||||||
|
|
||||||
|
value
|
||||||
|
virt_sparsify_statvfs_free_space (value pathv)
|
||||||
|
{
|
||||||
|
CAMLparam1 (pathv);
|
||||||
|
CAMLlocal1 (rv);
|
||||||
|
struct statvfs buf;
|
||||||
|
int64_t free_space;
|
||||||
|
|
||||||
|
if (statvfs (String_val (pathv), &buf) == -1) {
|
||||||
|
perror ("statvfs");
|
||||||
|
caml_failwith ("statvfs");
|
||||||
|
}
|
||||||
|
|
||||||
|
free_space = (int64_t) buf.f_bsize * buf.f_bavail;
|
||||||
|
rv = caml_copy_int64 (free_space);
|
||||||
|
|
||||||
|
CAMLreturn (rv);
|
||||||
|
}
|
||||||
@@ -113,6 +113,40 @@ image.
|
|||||||
|
|
||||||
Display help.
|
Display help.
|
||||||
|
|
||||||
|
=item B<--check-tmpdir=ignore>
|
||||||
|
|
||||||
|
=item B<--check-tmpdir=continue>
|
||||||
|
|
||||||
|
=item B<--check-tmpdir=warn>
|
||||||
|
|
||||||
|
=item B<--check-tmpdir=fail>
|
||||||
|
|
||||||
|
Check if L</TMPDIR> has enough space to complete the operation. This
|
||||||
|
is just an estimate.
|
||||||
|
|
||||||
|
If the check indicates a problem, then you can either:
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
B<ignore> it,
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
print a warning and B<continue>,
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
B<warn> and wait for the user to press the Return key
|
||||||
|
(this is the default), or:
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
B<fail> and exit.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
=item B<--compress>
|
=item B<--compress>
|
||||||
|
|
||||||
Compress the output file. This I<only> works if the output format is
|
Compress the output file. This I<only> works if the output format is
|
||||||
|
|||||||
Reference in New Issue
Block a user