[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 5/8] tools/oxenstored: Keep /dev/xen/evtchn open across live update


  • To: Andrew Cooper <Andrew.Cooper3@xxxxxxxxxx>
  • From: Christian Lindig <christian.lindig@xxxxxxxxxx>
  • Date: Wed, 23 Nov 2022 10:59:51 +0000
  • Accept-language: en-GB, en-US
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=citrix.com; dmarc=pass action=none header.from=citrix.com; dkim=pass header.d=citrix.com; arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=ub3dcPr3NQCpIfBaeMj1CUNdcc6DRr0U3yFB+6Ru9IQ=; b=n/dNBABrGPaU488NsSx3fkZ6MdK2JxAy3bmd0rHkOvynHA31+b8U6hvUgMhoud507nazt6W6Noa3jKZEt+Qx7RPGi5hRf5AVpXgvMeyNtxxTusGe8ME/7ia+LByCtzN8yc6FKY/f3tRoaoqs07C2XvIwKhUW4O+CwQxjyZKQSf9cgl3DGz6MvsZWlaIO52BZ2LtEgVbm0DWEc3hqK3qPoMe9+wwi6c3dFhcdVfjj9p4SkJtVOEXqIl25hhGtTDj63vz490MHMhne1sSwVyeU5SAwiPbQUqMo2E5QAiDqq1eGhUWTBWRaRLyQLwoR6kNdhPqs/ZULU33JBHRgjx77TQ==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=FTfHV7PTbLL+OwQ6S8x0HfOQYUxEG1FRL62FTfJ8eYAjwg3MRgE3z6xwLNgWBIxVEbctovCcRPMIjNl52We6D83mnePvD1LB3if0PBduj4Cd9APJlj5QfVQ59YhRNrQ0YIq+6c1atABKqgX2lA+DV4XRC9qaNYsx1Ibyop3xI+oa/XJYURFunzrPgBOh/VH74UOxhlmf0yosgZ2UwrtOhYFvVt5eW9JysBXeNIsLCFoTpaK/VYOcfGXG0WPaEzElDkHh7ZE5r8QEgiaCkqG7nd7qNTypfIJC09oQGCuhKNukHTK4P7txNwfdOnGukaI51rkvQR9fLWBNxcH0H6hFGg==
  • Authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=citrix.com;
  • Cc: Xen-devel <xen-devel@xxxxxxxxxxxxxxxxxxxx>, Edwin Torok <edvin.torok@xxxxxxxxxx>, David Scott <dave@xxxxxxxxxx>, Rob Hoes <Rob.Hoes@xxxxxxxxxx>
  • Delivery-date: Wed, 23 Nov 2022 11:00:06 +0000
  • Ironport-data: A9a23:sOpwE6MZhWBZSA7vrR27lsFynXyQoLVcMsEvi/4bfWQNrUonhjxRy zMWC26EaKuOY2b1L9l1aY+2pxkPv5WDx9RjSAto+SlhQUwRpJueD7x1DKtS0wC6dZSfER09v 63yTvGacajYm1eF/k/F3oDJ9CU6jufQA+KmU4YoAwgpLSd8UiAtlBl/rOAwh49skLCRDhiE/ Nj/uKUzAnf8s9JPGj9SuvzrRC9H5qyo4mpB5AdmP5ingXeF/5UrJMNHTU2OByOQrrl8RoaSW +vFxbelyWLVlz9F5gSNy+uTnuUiG9Y+DCDW4pZkc/HKbitq/0Te5p0TJvsEAXq7vh3S9zxHJ HehgrTrIeshFvWkdO3wyHC0GQkmVUFN0OevzXRSLaV/ZqAJGpfh66wGMa04AWEX0rlGDE4J9 PkxEQxXTTLbwPiRw5uVUeY506zPLOGzVG8ekldJ6GiBSNoDH9XESaiM4sJE1jAtgMwIBezZe 8cSdTtoalLHfgFLPVAUTpk5mY9EhFGmK2Ee9A3T+PpxujCKpOBy+OGF3N79cdyQRN5Jn0+e4 GbH+Wj4DTkRNcCFyCrD+XWp7gPKtXOmBNhOTefonhJsqHq93DAWVwInbnmisPSrkBW/X8ptA kNBr0LCqoB3riRHVOLVTxC+5XKJoBMYc95RCPEhrhGAzLLO5ASUDXRCSSROAPQqvdE7bSYn3 ViIm5XuHzMHjVGOYXeU97PRoTbsPyEQdDcGfXVdFVJD5MT/qoYuiB6JVsxkDKO+ktzyH3f33 iyOqy89wb4UiKbnypmGwLwOuBr0zrChc+L/zly/sr6Nhu+hWLOYWg==
  • Ironport-hdrordr: A9a23:knL3fa7wrzb3tLI8/gPXweCCI+orL9Y04lQ7vn2ZFiY5TiXIra qTdaogviMc0AxhI03Jmbi7Scq9qeu1z+853WBjB8bZYOCAghrlEGgC1/qp/9SEIUHDH4FmpM BdmsRFaeEYSGIK9foSgzPIXOrIouP3lpxA7N22pxgCcegpUdAY0+4TMHf4LqQCfngjOXNPLu v42iMonVqdUEVSSv7+KmgOXuDFqdGOvJX6YSQeDxpixBiSgSiu4LvaFQHd+hsFSTtAzZor7G CAymXCl+SemsD+7iWZ+37Y7pxQltek4txfBPaUgsxQBiTwhh2ubIFBXaTHmDwuuumg5Hsjjd GJiRY9OMZY7W/XYwiO0FXQ8jil9Axrx27pyFeej3emi9f+XigGB81Igp8cWgfF6mI71esMk5 5j7ia8jd56HBnAlCPy65zjTBdxjHe5pnIkjKo6k2Ffa40Dc7VcxLZvvn+9Ua1wWR4S2rpXV9 WGP/usosq+tmnqNkwxi1MfhOBEmE5DRituDHJy4fB9mAIm4UyRh3FouPD32E1wtK7VAqM0md jsI+BmkqpDQdQRar84DOAdQdGvAmiIWh7UNnmOSG6XXZ3uqxr22uHKCZgOlZaXkaYzve0PsY WEVEkduX85ekroB8HL1JpX8grVSGH4WTj20MlR65Vwp7W5HdPQQGa+YUFrl9Hlr+QUA8XdVf r2MJVKA+X7JW+rHYpSxQXxV5RbNHFbWswIvdQwXU6Iv6vwW8XXn/2edOyWKKvmED4iVG+6Cn wfXCLrLMEF9UyvUm+QummkZ5osQD2LwXtdKtmowwFI8vl9CmRliHlktX2poseWNDZFrqs6OE NjPbKPqNLImVWL
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Thread-index: AQHY/oYKxtNRy0op0U+W6qla123BXq5MWFyA
  • Thread-topic: [PATCH 5/8] tools/oxenstored: Keep /dev/xen/evtchn open across live update


> On 22 Nov 2022, at 15:20, Andrew Cooper <andrew.cooper3@xxxxxxxxxx> wrote:
> 
> From: Edwin Török <edvin.torok@xxxxxxxxxx>
> 
> Closing the evtchn handle will unbind and free all local ports.  The new
> xenstored would need to rebind all evtchns, which is work that we don't want
> or need to be doing during the critical handover period.
> 
> However, it turns out that the Windows PV drivers also rebind their local port
> too across suspend/resume, leaving (o)xenstored with a stale idea of the
> remote port to use.  In this case, reusing the established connection is the
> only robust option.
> 
> Therefore:
> * Have oxenstored open /dev/xen/evtchn without CLOEXEC at start of day
> * Extend the handover information with the evtchn fd, and the local port
>   number for each domain connection.
> * Have (the new) oxenstored recover the open handle using Xeneventchn.fdopen,
>   and use the provided local ports rather than trying to rebind them.
> 
> When this new information isn't present (i.e. live updating from an oxenstored
> prior to this change), the best-effort status quo will have to do.
> 
> Signed-off-by: Edwin Török <edvin.torok@xxxxxxxxxx>
> Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
> ---
> CC: Christian Lindig <christian.lindig@xxxxxxxxxx>
> CC: David Scott <dave@xxxxxxxxxx>
> CC: Edwin Torok <edvin.torok@xxxxxxxxxx>
> CC: Rob Hoes <Rob.Hoes@xxxxxxxxxx>
> 

Acked-by: Christian Lindig <christian.lindig@xxxxxxxxxx>

Nothing stands out for me. But this is obviously delicate in support of a 
delicate feature, which is live update. I commented before that the commend 
line gets increasingly crowded.

— C


> Merge two patches to retain bisectability.  Drop changes to the evtchn 
> bindings.
> ---
> tools/ocaml/xenstored/domain.ml    |  6 ++-
> tools/ocaml/xenstored/domains.ml   | 14 +++++--
> tools/ocaml/xenstored/event.ml     |  8 +++-
> tools/ocaml/xenstored/xenstored.ml | 82 ++++++++++++++++++++++++++------------
> 4 files changed, 78 insertions(+), 32 deletions(-)
> 
> diff --git a/tools/ocaml/xenstored/domain.ml b/tools/ocaml/xenstored/domain.ml
> index 81cb59b8f1a2..527035ffdd32 100644
> --- a/tools/ocaml/xenstored/domain.ml
> +++ b/tools/ocaml/xenstored/domain.ml
> @@ -61,7 +61,7 @@ let string_of_port = function
> | Some x -> string_of_int (Xeneventchn.to_int x)
> 
> let dump d chan =
> -     fprintf chan "dom,%d,%nd,%d\n" d.id d.mfn d.remote_port
> +     fprintf chan "dom,%d,%nd,%d,%s\n" d.id d.mfn d.remote_port 
> (string_of_port d.port)
> 
> let notify dom = match dom.port with
> | None ->
> @@ -77,6 +77,10 @@ let bind_interdomain dom =
>       dom.port <- Some (Event.bind_interdomain dom.eventchn dom.id 
> dom.remote_port);
>       debug "bound domain %d remote port %d to local port %s" dom.id 
> dom.remote_port (string_of_port dom.port)
> 
> +let restore_interdomain dom localport =
> +     assert (dom.port = None);
> +     dom.port <- Some (Xeneventchn.of_int localport);
> +     debug "restored interdomain %d remote port %d to local port %s" dom.id 
> dom.remote_port (string_of_port dom.port)
> 
> let close dom =
>       debug "domain %d unbound port %s" dom.id (string_of_port dom.port);
> diff --git a/tools/ocaml/xenstored/domains.ml 
> b/tools/ocaml/xenstored/domains.ml
> index 17fe2fa25772..a91d2afd2a82 100644
> --- a/tools/ocaml/xenstored/domains.ml
> +++ b/tools/ocaml/xenstored/domains.ml
> @@ -56,6 +56,7 @@ let exist doms id = Hashtbl.mem doms.table id
> let find doms id = Hashtbl.find doms.table id
> let number doms = Hashtbl.length doms.table
> let iter doms fct = Hashtbl.iter (fun _ b -> fct b) doms.table
> +let eventchn doms = doms.eventchn
> 
> let rec is_empty_queue q =
>       Queue.is_empty q ||
> @@ -122,17 +123,22 @@ let cleanup doms =
> let resume _doms _domid =
>       ()
> 
> -let create doms domid mfn port =
> +let maybe_bind_interdomain restore_localport dom =
> +     match restore_localport with
> +     | None -> Domain.bind_interdomain dom
> +     | Some p -> Domain.restore_interdomain dom p
> +
> +let create doms domid mfn ?restore_localport port =
>       let interface = Xenctrl.map_foreign_range xc domid 
> (Xenmmap.getpagesize()) mfn in
>       let dom = Domain.make domid mfn port interface doms.eventchn in
>       Hashtbl.add doms.table domid dom;
> -     Domain.bind_interdomain dom;
> +     maybe_bind_interdomain restore_localport dom;
>       dom
> 
> let xenstored_kva = ref ""
> let xenstored_port = ref ""
> 
> -let create0 doms =
> +let create0 ?restore_localport doms =
>       let port, interface =
>               (
>                       let port = Utils.read_file_single_integer 
> !xenstored_port
> @@ -146,7 +152,7 @@ let create0 doms =
>               in
>       let dom = Domain.make 0 Nativeint.zero port interface doms.eventchn in
>       Hashtbl.add doms.table 0 dom;
> -     Domain.bind_interdomain dom;
> +     maybe_bind_interdomain restore_localport dom;
>       Domain.notify dom;
>       dom
> 
> diff --git a/tools/ocaml/xenstored/event.ml b/tools/ocaml/xenstored/event.ml
> index ccca90b6fc4f..0159daac91f4 100644
> --- a/tools/ocaml/xenstored/event.ml
> +++ b/tools/ocaml/xenstored/event.ml
> @@ -20,7 +20,13 @@ type t = {
>       mutable virq_port: Xeneventchn.t option;
> }
> 
> -let init () = { handle = Xeneventchn.init (); virq_port = None; }
> +let init ?fd () =
> +     let handle = match fd with
> +             | None -> Xeneventchn.init ~cloexec:false ()
> +             | Some fd -> Xeneventchn.fdopen fd
> +     in
> +     { handle; virq_port = None }
> +
> let fd eventchn = Xeneventchn.fd eventchn.handle
> let bind_dom_exc_virq eventchn = eventchn.virq_port <- Some 
> (Xeneventchn.bind_dom_exc_virq eventchn.handle)
> let bind_interdomain eventchn domid port = Xeneventchn.bind_interdomain 
> eventchn.handle domid port
> diff --git a/tools/ocaml/xenstored/xenstored.ml 
> b/tools/ocaml/xenstored/xenstored.ml
> index c5dc7a28d082..6ceab02dee1e 100644
> --- a/tools/ocaml/xenstored/xenstored.ml
> +++ b/tools/ocaml/xenstored/xenstored.ml
> @@ -144,7 +144,7 @@ exception Bad_format of string
> 
> let dump_format_header = "$xenstored-dump-format"
> 
> -let from_channel_f chan global_f socket_f domain_f watch_f store_f =
> +let from_channel_f chan global_f event_f socket_f domain_f watch_f store_f =
>       let unhexify s = Utils.unhexify s in
>       let getpath s =
>               let u = Utils.unhexify s in
> @@ -165,12 +165,17 @@ let from_channel_f chan global_f socket_f domain_f 
> watch_f store_f =
>                                       (* there might be more parameters here,
>                                          e.g. a RO socket from a previous 
> version: ignore it *)
>                                       global_f ~rw
> +                             | "eventfd" :: eventfd :: [] ->
> +                                     event_f ~eventfd
>                               | "socket" :: fd :: [] ->
>                                       socket_f ~fd:(int_of_string fd)
> -                             | "dom" :: domid :: mfn :: port :: []->
> +                             | "dom" :: domid :: mfn :: port :: rest ->
>                                       domain_f (int_of_string domid)
>                                                (Nativeint.of_string mfn)
>                                                (int_of_string port)
> +                                              (match rest with
> +                                               | [] -> None (* backward 
> compat: old version didn't have it *)
> +                                               | localport :: _ -> Some 
> (int_of_string localport))
>                               | "watch" :: domid :: path :: token :: [] ->
>                                       watch_f (int_of_string domid)
>                                               (unhexify path) (unhexify token)
> @@ -189,10 +194,27 @@ let from_channel_f chan global_f socket_f domain_f 
> watch_f store_f =
>       done;
>       info "Completed loading xenstore dump"
> 
> -let from_channel store cons doms chan =
> +let from_channel store cons createdoms chan =
>       (* don't let the permission get on our way, full perm ! *)
>       let op = Store.get_ops store Perms.Connection.full_rights in
>       let rwro = ref (None) in
> +     let eventchnfd = ref (None) in

No parenthesis required: "ref None” would be enough. But don’t bother - once we 
use OCamlformat instances like these will be picked up.


> +     let doms = ref (None) in
> +
> +     let require_doms () =
> +             match !doms with
> +             | None ->

Alternative could be:
| None when !eventchnfd = None ->
 ...
| None ->
 ...
| Some d -> d



> +                     let missing_eventchnfd = !eventchnfd = None in
> +                     if missing_eventchnfd then
> +                             warn "No event channel file descriptor 
> available in dump!";
> +                     let eventchn = Event.init ?fd:!eventchnfd () in
> +                     let domains = createdoms eventchn in
> +                     if missing_eventchnfd then
> +                             Event.bind_dom_exc_virq eventchn;
> +                     doms := Some domains;
> +                     domains
> +             | Some d -> d
> +     in
>       let global_f ~rw =
>               let get_listen_sock sockfd =
>                       let fd = sockfd |> int_of_string |> Utils.FD.of_int in
> @@ -201,6 +223,10 @@ let from_channel store cons doms chan =
>               in
>               rwro := get_listen_sock rw
>       in
> +     let event_f ~eventfd =
> +             let fd = eventfd |> int_of_string |> Utils.FD.of_int in
> +             eventchnfd := Some fd
> +     in
>       let socket_f ~fd =
>               let ufd = Utils.FD.of_int fd in
>               let is_valid = try (Unix.fstat ufd).Unix.st_kind = Unix.S_SOCK 
> with _ -> false in
> @@ -209,12 +235,13 @@ let from_channel store cons doms chan =
>               else
>                       warn "Ignoring invalid socket FD %d" fd
>       in
> -     let domain_f domid mfn port =
> +     let domain_f domid mfn port restore_localport =
> +             let doms = require_doms () in
>               let ndom =
>                       if domid > 0 then
> -                             Domains.create doms domid mfn port
> +                             Domains.create doms domid mfn 
> ?restore_localport port
>                       else
> -                             Domains.create0 doms
> +                             Domains.create0 ?restore_localport doms
>                       in
>               Connections.add_domain cons ndom;
>               in
> @@ -229,8 +256,8 @@ let from_channel store cons doms chan =
>               op.Store.write path value;
>               op.Store.setperms path perms
>               in
> -     from_channel_f chan global_f socket_f domain_f watch_f store_f;
> -     !rwro
> +     from_channel_f chan global_f event_f socket_f domain_f watch_f store_f;
> +     !rwro, require_doms ()
> 
> let from_file store cons doms file =
>       info "Loading xenstore dump from %s" file;
> @@ -238,7 +265,7 @@ let from_file store cons doms file =
>       finally (fun () -> from_channel store doms cons channel)
>               (fun () -> close_in channel)
> 
> -let to_channel store cons rw chan =
> +let to_channel store cons (rw, eventchn) chan =
>       let hexify s = Utils.hexify s in
> 
>       fprintf chan "%s\n" dump_format_header;
> @@ -247,6 +274,7 @@ let to_channel store cons rw chan =
>               Unix.clear_close_on_exec fd;
>               Utils.FD.to_int fd in
>       fprintf chan "global,%d\n" (fdopt rw);
> +     fprintf chan "eventchnfd,%d\n" (Utils.FD.to_int @@ Event.fd eventchn);
> 
>       (* dump connections related to domains: domid, mfn, eventchn port/ 
> sockets, and watches *)
>       Connections.iter cons (fun con -> Connection.dump con chan);
> @@ -367,7 +395,6 @@ let _ =
>       | None         -> () end;
> 
>       let store = Store.create () in
> -     let eventchn = Event.init () in
>       let next_frequent_ops = ref 0. in
>       let advance_next_frequent_ops () =
>               next_frequent_ops := (Unix.gettimeofday () +. 
> !Define.conflict_max_history_seconds)
> @@ -375,16 +402,8 @@ let _ =
>       let delay_next_frequent_ops_by duration =
>               next_frequent_ops := !next_frequent_ops +. duration
>       in
> -     let domains = Domains.init eventchn advance_next_frequent_ops in
> +     let domains eventchn = Domains.init eventchn advance_next_frequent_ops 
> in
> 
> -     (* For things that need to be done periodically but more often
> -      * than the periodic_ops function *)
> -     let frequent_ops () =
> -             if Unix.gettimeofday () > !next_frequent_ops then (
> -                     History.trim ();
> -                     Domains.incr_conflict_credit domains;
> -                     advance_next_frequent_ops ()
> -             ) in
>       let cons = Connections.create () in
> 
>       let quit = ref false in
> @@ -393,15 +412,15 @@ let _ =
>       List.iter (fun path ->
>               Store.write store Perms.Connection.full_rights path "") 
> Store.Path.specials;
> 
> -     let rw_sock =
> +     let rw_sock, domains =
>       if cf.restart && Sys.file_exists Disk.xs_daemon_database then (
> -             let rwro = DB.from_file store domains cons 
> Disk.xs_daemon_database in
> +             let rw, domains = DB.from_file store domains cons 
> Disk.xs_daemon_database in
>               info "Live reload: database loaded";
> -             Event.bind_dom_exc_virq eventchn;
>               Process.LiveUpdate.completed ();
> -             rwro
> +             rw, domains
>       ) else (
>               info "No live reload: regular startup";
> +             let domains = domains @@ Event.init () in
>               if !Disk.enable then (
>                       info "reading store from disk";
>                       Disk.read store
> @@ -411,13 +430,23 @@ let _ =
>               if not (Store.path_exists store localpath) then
>                       Store.mkdir store (Perms.Connection.create 0) localpath;
> 
> +             let eventchn = Event.init () in
>               if cf.domain_init then (
>                       Connections.add_domain cons (Domains.create0 domains);
>                       Event.bind_dom_exc_virq eventchn
>               );
> -             rw_sock
> +             rw_sock, domains
>       ) in
> 
> +     (* For things that need to be done periodically but more often
> +      * than the periodic_ops function *)
> +     let frequent_ops () =
> +             if Unix.gettimeofday () > !next_frequent_ops then (
> +                     History.trim ();
> +                     Domains.incr_conflict_credit domains;
> +                     advance_next_frequent_ops ()
> +             ) in
> +
>       (* required for xenstore-control to detect availability of live-update 
> *)
>       let tool_path = Store.Path.of_string "/tool" in
>       if not (Store.path_exists store tool_path) then
> @@ -433,10 +462,11 @@ let _ =
>       Sys.set_signal Sys.sigpipe Sys.Signal_ignore;
> 
>       if cf.activate_access_log then begin
> -             let post_rotate () = DB.to_file store cons (None) 
> Disk.xs_daemon_database in
> +             let post_rotate () = DB.to_file store cons (None, 
> Domains.eventchn domains) Disk.xs_daemon_database in
>               Logging.init_access_log post_rotate
>       end;
> 
> +     let eventchn = Domains.eventchn domains in
>       let spec_fds =
>               (match rw_sock with None -> [] | Some x -> [ x ]) @
>               (if cf.domain_init then [ Event.fd eventchn ] else [])
> @@ -595,7 +625,7 @@ let _ =
>                       live_update := Process.LiveUpdate.should_run cons;
>                       if !live_update || !quit then begin
>                               (* don't initiate live update if saving state 
> fails *)
> -                             DB.to_file store cons (rw_sock) 
> Disk.xs_daemon_database;
> +                             DB.to_file store cons (rw_sock, eventchn) 
> Disk.xs_daemon_database;
>                               quit := true;
>                       end
>               with exc ->
> -- 
> 2.11.0
> 


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.