diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml index 89a6aacc88..d60861ca34 100644 --- a/tools/ocaml/xenstored/define.ml +++ b/tools/ocaml/xenstored/define.ml @@ -27,6 +27,7 @@ let default_config_dir = "/etc/xen" let maxwatch = ref (50) let maxtransaction = ref (20) +let maxrequests = ref (-1) (* maximum requests per transaction *) let domid_self = 0x7FF0 diff --git a/tools/ocaml/xenstored/oxenstored.conf b/tools/ocaml/xenstored/oxenstored.conf index dd20eda140..ac60f49df8 100644 --- a/tools/ocaml/xenstored/oxenstored.conf +++ b/tools/ocaml/xenstored/oxenstored.conf @@ -18,6 +18,7 @@ quota-maxentity = 1000 quota-maxsize = 2048 quota-maxwatch = 100 quota-transaction = 10 +quota-maxrequests = 1024 # Activate filed base backend persistent = false diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml index c92bec7bef..758ade191d 100644 --- a/tools/ocaml/xenstored/process.ml +++ b/tools/ocaml/xenstored/process.ml @@ -155,7 +155,7 @@ let do_transaction_end con t domains cons data = if not success then raise Transaction_again; if commit then - process_watch (List.rev (Transaction.get_ops t)) cons + process_watch (List.rev (Transaction.get_paths t)) cons let do_introduce con t domains cons data = if not (Connection.is_dom0 con) @@ -303,7 +303,7 @@ let reply_ack fct con t doms cons data = fct con t doms cons data; Packet.Ack (fun () -> if Transaction.get_id t = Transaction.none then - process_watch (Transaction.get_ops t) cons + process_watch (Transaction.get_paths t) cons ) let reply_data fct con t doms cons data = @@ -384,6 +384,15 @@ let process_packet ~store ~cons ~doms ~con ~req = in let response = input_handle_error ~cons ~doms ~fct ~con ~t ~req in + let response = try + if tid <> Transaction.none then + (* Remember the request and response for this operation in case we need to replay the transaction *) + Transaction.add_operation ~perm:(Connection.get_perm con) t req response; + response + with Quota.Limit_reached -> + Packet.Error "EQUOTA" + in + (* Put the response on the wire *) send_response ty con t rid response with exn -> diff --git a/tools/ocaml/xenstored/transaction.ml b/tools/ocaml/xenstored/transaction.ml index 77de4e8ac1..6b37fc2ad0 100644 --- a/tools/ocaml/xenstored/transaction.ml +++ b/tools/ocaml/xenstored/transaction.ml @@ -75,7 +75,8 @@ type t = { ty: ty; store: Store.t; quota: Quota.t; - mutable ops: (Xenbus.Xb.Op.operation * Store.Path.t) list; + mutable paths: (Xenbus.Xb.Op.operation * Store.Path.t) list; + mutable operations: (Packet.request * Packet.response) list; mutable read_lowpath: Store.Path.t option; mutable write_lowpath: Store.Path.t option; } @@ -86,16 +87,24 @@ let make id store = ty = ty; store = if id = none then store else Store.copy store; quota = Quota.copy store.Store.quota; - ops = []; + paths = []; + operations = []; read_lowpath = None; write_lowpath = None; } let get_id t = match t.ty with No -> none | Full (id, _, _) -> id let get_store t = t.store -let get_ops t = t.ops +let get_paths t = t.paths -let add_wop t ty path = t.ops <- (ty, path) :: t.ops +let add_wop t ty path = t.paths <- (ty, path) :: t.paths +let add_operation ~perm t request response = + if !Define.maxrequests >= 0 + && not (Perms.Connection.is_dom0 perm) + && List.length t.operations >= !Define.maxrequests + then raise Quota.Limit_reached; + t.operations <- (request, response) :: t.operations +let get_operations t = List.rev t.operations let set_read_lowpath t path = t.read_lowpath <- get_lowest path t.read_lowpath let set_write_lowpath t path = t.write_lowpath <- get_lowest path t.write_lowpath @@ -141,7 +150,7 @@ let getperms t perm path = r let commit ~con t = - let has_write_ops = List.length t.ops > 0 in + let has_write_ops = List.length t.paths > 0 in let has_coalesced = ref false in let has_commited = match t.ty with diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml index 25c126a78e..fc8cc95d2e 100644 --- a/tools/ocaml/xenstored/xenstored.ml +++ b/tools/ocaml/xenstored/xenstored.ml @@ -95,6 +95,7 @@ let parse_config filename = ("quota-transaction", Config.Set_int Define.maxtransaction); ("quota-maxentity", Config.Set_int Quota.maxent); ("quota-maxsize", Config.Set_int Quota.maxsize); + ("quota-maxrequests", Config.Set_int Define.maxrequests); ("test-eagain", Config.Set_bool Transaction.test_eagain); ("persistent", Config.Set_bool Disk.enable); ("xenstored-log-file", Config.String Logging.set_xenstored_log_destination);