From patchwork Fri Aug 10 02:14:35 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Gunthorpe X-Patchwork-Id: 10562183 X-Patchwork-Delegate: jgg@ziepe.ca Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id DD1E490E3 for ; Fri, 10 Aug 2018 02:14:56 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CECEE2BB93 for ; Fri, 10 Aug 2018 02:14:56 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C369F2BBAF; Fri, 10 Aug 2018 02:14:56 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 22F042BBA0 for ; Fri, 10 Aug 2018 02:14:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727102AbeHJEme (ORCPT ); Fri, 10 Aug 2018 00:42:34 -0400 Received: from mail-pl0-f65.google.com ([209.85.160.65]:44155 "EHLO mail-pl0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725917AbeHJEme (ORCPT ); Fri, 10 Aug 2018 00:42:34 -0400 Received: by mail-pl0-f65.google.com with SMTP id ba4-v6so3352724plb.11 for ; Thu, 09 Aug 2018 19:14:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ziepe.ca; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=4YZA/2LE/49sZvq0npcoWY5ZU3hlB4PyLfqgjhTIZKw=; b=HktpBAIRflvdgKPsH6PvSCS9M1j8+L/fpXYRGPt2jbcraIaYy9DkNx9C+MsI5fOSAT Y8dfsZJ/xrG5FPTCVBpi9ZzuxE1m3ZniDc6seUkK/lET3TLycQa6U/GQXdMOA/x/IcwC 4k1EdbSk9EHThNpxvcWV5KvDvYi8OJJUH+6XTcMVGG1W/p4YQdr3G4BhoywbLK4CN8Q3 eeLz5YTRlMJvMP9StGMM/NKgES4JrgF5CEk1FlZ9hfmWe0G/n4NCeZjQpnFCKWdvTAmL VVRkF1AVdqMgT+zQaSgM9Ox4ItULnkDd5yzb2gJhQDFTTSiVSl4q28H3KdyUHqvYi6rD jH7A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=4YZA/2LE/49sZvq0npcoWY5ZU3hlB4PyLfqgjhTIZKw=; b=bDZtr+2lP3VyNOVb9gqf6zv2ONsG6BFSK3L2NHF0laIBoUrmJpntZlYGc6278VLXsP 6ixSxGUt3xWIVHLCn208X4u1z12wv2+Aq1l07PoNYBFn4jIll+ACr9SBzAoTDC/6OuNm e5mW4MovCaeL/KWDIb3GNdnvgI/TdjpJvZwYT+zjvEviYDgq++2A3/Bbk/eVk+ZMETSJ i3ypMZ9zLzw0U8W+jQ58uBXKJowYAc6XwxDMM8d5TMyv8FOroC4OcT3suJKQp0d+ILfZ SRiPZaQ1VaET0B2JJBAd8E0RGb+2cqW3yi7kULF4SC9EE43s+p88E7OBRVnOe02y/5ov mhNg== X-Gm-Message-State: AOUpUlGg2mivpGxWeOo80JPjYYCqV0YbEaFbXwzVKhWTl0ARe1stTeFu zah84VoEfqAPkSAurpaq7waoa/vADYg= X-Google-Smtp-Source: AA+uWPzB6UaZ20j2tMp0/QFGm25fNQ/7vwvdlXaXr7AyJ6CgsnNOcKMJr8pxVLFVAsk+uCP6nDlJzA== X-Received: by 2002:a17:902:5481:: with SMTP id e1-v6mr4254502pli.309.1533867293170; Thu, 09 Aug 2018 19:14:53 -0700 (PDT) Received: from ziepe.ca (S010614cc2056d97f.ed.shawcable.net. [174.3.196.123]) by smtp.gmail.com with ESMTPSA id f75-v6sm29679727pfk.85.2018.08.09.19.14.51 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Thu, 09 Aug 2018 19:14:51 -0700 (PDT) Received: from jgg by mlx with local (Exim 4.90_1) (envelope-from ) id 1fnwx1-0003gA-90; Thu, 09 Aug 2018 20:14:51 -0600 From: Jason Gunthorpe To: linux-rdma@vger.kernel.org, Leon Romanovsky , "Guy Levi(SW)" , Yishai Hadas , "Ruhl, Michael J" Cc: Jason Gunthorpe Subject: [PATCH v1 01/10] IB/uverbs: Have the core code create the uverbs_root_spec Date: Thu, 9 Aug 2018 20:14:35 -0600 Message-Id: <20180810021444.14014-2-jgg@ziepe.ca> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180810021444.14014-1-jgg@ziepe.ca> References: <20180810021444.14014-1-jgg@ziepe.ca> Sender: linux-rdma-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-rdma@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Jason Gunthorpe There is no reason for drivers to do this, the core code should take of everything. The drivers will provide their information from rodata to describe their modifications to the core's base uapi specification. The core uses this to build up the runtime uapi for each device. Signed-off-by: Jason Gunthorpe Reviewed-by: Michael J. Ruhl Reviewed-by: Leon Romanovsky --- drivers/infiniband/core/uverbs_ioctl_merge.c | 2 - drivers/infiniband/core/uverbs_main.c | 50 +++++++++++++------- drivers/infiniband/core/uverbs_std_types.c | 1 - drivers/infiniband/hw/mlx5/main.c | 45 +++++++----------- drivers/infiniband/hw/mlx5/mlx5_ib.h | 1 + include/rdma/ib_verbs.h | 2 +- 6 files changed, 51 insertions(+), 50 deletions(-) diff --git a/drivers/infiniband/core/uverbs_ioctl_merge.c b/drivers/infiniband/core/uverbs_ioctl_merge.c index f81aa888ce5c4c..16b57592991581 100644 --- a/drivers/infiniband/core/uverbs_ioctl_merge.c +++ b/drivers/infiniband/core/uverbs_ioctl_merge.c @@ -556,7 +556,6 @@ void uverbs_free_spec_tree(struct uverbs_root_spec *root) kfree(root); } -EXPORT_SYMBOL(uverbs_free_spec_tree); struct uverbs_root_spec *uverbs_alloc_spec_tree(unsigned int num_trees, const struct uverbs_object_tree_def **trees) @@ -661,4 +660,3 @@ struct uverbs_root_spec *uverbs_alloc_spec_tree(unsigned int num_trees, uverbs_free_spec_tree(root_spec); return ERR_PTR(res); } -EXPORT_SYMBOL(uverbs_alloc_spec_tree); diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 6f62146e9738a0..20003594b5d6a7 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -994,6 +994,36 @@ static DEVICE_ATTR(abi_version, S_IRUGO, show_dev_abi_version, NULL); static CLASS_ATTR_STRING(abi_version, S_IRUGO, __stringify(IB_USER_VERBS_ABI_VERSION)); +static int ib_uverbs_create_uapi(struct ib_device *device, + struct ib_uverbs_device *uverbs_dev) +{ + const struct uverbs_object_tree_def **specs; + struct uverbs_root_spec *specs_root; + unsigned int num_specs = 1; + unsigned int i; + + if (device->driver_specs) + for (i = 0; device->driver_specs[i]; i++) + num_specs++; + + specs = kmalloc_array(num_specs, sizeof(*specs), GFP_KERNEL); + if (!specs) + return -ENOMEM; + + specs[0] = uverbs_default_get_objects(); + if (device->driver_specs) + for (i = 0; device->driver_specs[i]; i++) + specs[i+1] = device->driver_specs[i]; + + specs_root = uverbs_alloc_spec_tree(num_specs, specs); + kfree(specs); + if (IS_ERR(specs_root)) + return PTR_ERR(specs_root); + + uverbs_dev->specs_root = specs_root; + return 0; +} + static void ib_uverbs_add_one(struct ib_device *device) { int devnum; @@ -1036,6 +1066,9 @@ static void ib_uverbs_add_one(struct ib_device *device) rcu_assign_pointer(uverbs_dev->ib_dev, device); uverbs_dev->num_comp_vectors = device->num_comp_vectors; + if (ib_uverbs_create_uapi(device, uverbs_dev)) + goto err; + cdev_init(&uverbs_dev->cdev, NULL); uverbs_dev->cdev.owner = THIS_MODULE; uverbs_dev->cdev.ops = device->mmap ? &uverbs_mmap_fops : &uverbs_fops; @@ -1055,23 +1088,6 @@ static void ib_uverbs_add_one(struct ib_device *device) if (device_create_file(uverbs_dev->dev, &dev_attr_abi_version)) goto err_class; - if (!device->driver_specs_root) { - const struct uverbs_object_tree_def *default_root[] = { - uverbs_default_get_objects()}; - - uverbs_dev->specs_root = uverbs_alloc_spec_tree(1, - default_root); - if (IS_ERR(uverbs_dev->specs_root)) - goto err_class; - } else { - uverbs_dev->specs_root = device->driver_specs_root; - /* - * Take responsibility to free the specs allocated by the - * driver. - */ - device->driver_specs_root = NULL; - } - ib_set_client_data(device, &uverbs_client, uverbs_dev); return; diff --git a/drivers/infiniband/core/uverbs_std_types.c b/drivers/infiniband/core/uverbs_std_types.c index 3aa7c7deac749a..7f22b820a21ba0 100644 --- a/drivers/infiniband/core/uverbs_std_types.c +++ b/drivers/infiniband/core/uverbs_std_types.c @@ -316,4 +316,3 @@ const struct uverbs_object_tree_def *uverbs_default_get_objects(void) { return &uverbs_default_objects; } -EXPORT_SYMBOL_GPL(uverbs_default_get_objects); diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 13744b4631b452..f86d831ee27c5d 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -5523,37 +5523,29 @@ ADD_UVERBS_ATTRIBUTES_SIMPLE( UVERBS_ATTR_FLAGS_IN(MLX5_IB_ATTR_CREATE_FLOW_ACTION_FLAGS, enum mlx5_ib_uapi_flow_action_flags)); -#define NUM_TREES 5 static int populate_specs_root(struct mlx5_ib_dev *dev) { - const struct uverbs_object_tree_def *default_root[NUM_TREES + 1] = { - uverbs_default_get_objects()}; - size_t num_trees = 1; + const struct uverbs_object_tree_def **trees = dev->driver_trees; + size_t num_trees = 0; - if (mlx5_accel_ipsec_device_caps(dev->mdev) & MLX5_ACCEL_IPSEC_CAP_DEVICE && - !WARN_ON(num_trees >= ARRAY_SIZE(default_root))) - default_root[num_trees++] = &mlx5_ib_flow_action; + if (mlx5_accel_ipsec_device_caps(dev->mdev) & + MLX5_ACCEL_IPSEC_CAP_DEVICE) + trees[num_trees++] = &mlx5_ib_flow_action; - if (MLX5_CAP_DEV_MEM(dev->mdev, memic) && - !WARN_ON(num_trees >= ARRAY_SIZE(default_root))) - default_root[num_trees++] = &mlx5_ib_dm; + if (MLX5_CAP_DEV_MEM(dev->mdev, memic)) + trees[num_trees++] = &mlx5_ib_dm; if (MLX5_CAP_GEN_64(dev->mdev, general_obj_types) & - MLX5_GENERAL_OBJ_TYPES_CAP_UCTX && - !WARN_ON(num_trees >= ARRAY_SIZE(default_root))) - default_root[num_trees++] = mlx5_ib_get_devx_tree(); + MLX5_GENERAL_OBJ_TYPES_CAP_UCTX) + trees[num_trees++] = mlx5_ib_get_devx_tree(); - num_trees += mlx5_ib_get_flow_trees(default_root + num_trees); + num_trees += mlx5_ib_get_flow_trees(trees + num_trees); - dev->ib_dev.driver_specs_root = - uverbs_alloc_spec_tree(num_trees, default_root); + WARN_ON(num_trees >= ARRAY_SIZE(dev->driver_trees)); + trees[num_trees] = NULL; + dev->ib_dev.driver_specs = trees; - return PTR_ERR_OR_ZERO(dev->ib_dev.driver_specs_root); -} - -static void depopulate_specs_root(struct mlx5_ib_dev *dev) -{ - uverbs_free_spec_tree(dev->ib_dev.driver_specs_root); + return 0; } static int mlx5_ib_read_counters(struct ib_counters *counters, @@ -6092,11 +6084,6 @@ int mlx5_ib_stage_ib_reg_init(struct mlx5_ib_dev *dev) return ib_register_device(&dev->ib_dev, NULL); } -static void mlx5_ib_stage_depopulate_specs(struct mlx5_ib_dev *dev) -{ - depopulate_specs_root(dev); -} - void mlx5_ib_stage_pre_ib_reg_umr_cleanup(struct mlx5_ib_dev *dev) { destroy_umrc_res(dev); @@ -6231,7 +6218,7 @@ static const struct mlx5_ib_profile pf_profile = { mlx5_ib_stage_pre_ib_reg_umr_cleanup), STAGE_CREATE(MLX5_IB_STAGE_SPECS, mlx5_ib_stage_populate_specs, - mlx5_ib_stage_depopulate_specs), + NULL), STAGE_CREATE(MLX5_IB_STAGE_IB_REG, mlx5_ib_stage_ib_reg_init, mlx5_ib_stage_ib_reg_cleanup), @@ -6279,7 +6266,7 @@ static const struct mlx5_ib_profile nic_rep_profile = { mlx5_ib_stage_pre_ib_reg_umr_cleanup), STAGE_CREATE(MLX5_IB_STAGE_SPECS, mlx5_ib_stage_populate_specs, - mlx5_ib_stage_depopulate_specs), + NULL), STAGE_CREATE(MLX5_IB_STAGE_IB_REG, mlx5_ib_stage_ib_reg_init, mlx5_ib_stage_ib_reg_cleanup), diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index b75754efc66309..320d4dfe8c2f41 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -860,6 +860,7 @@ to_mcounters(struct ib_counters *ibcntrs) struct mlx5_ib_dev { struct ib_device ib_dev; + const struct uverbs_object_tree_def *driver_trees[6]; struct mlx5_core_dev *mdev; struct mlx5_roce roce[MLX5_MAX_PORTS]; int num_ports; diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 4ffe3e11e8fb6c..3b07201b9a804e 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -2580,7 +2580,7 @@ struct ib_device { const struct cpumask *(*get_vector_affinity)(struct ib_device *ibdev, int comp_vector); - struct uverbs_root_spec *driver_specs_root; + const struct uverbs_object_tree_def *const *driver_specs; enum rdma_driver_id driver_id; }; From patchwork Fri Aug 10 02:14:36 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Gunthorpe X-Patchwork-Id: 10562199 X-Patchwork-Delegate: jgg@ziepe.ca Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8D0E413BB for ; Fri, 10 Aug 2018 02:15:03 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7B1162BB93 for ; Fri, 10 Aug 2018 02:15:03 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6F41B2BBA4; Fri, 10 Aug 2018 02:15:03 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 738A02BBA0 for ; Fri, 10 Aug 2018 02:14:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727155AbeHJEmh (ORCPT ); Fri, 10 Aug 2018 00:42:37 -0400 Received: from mail-pf1-f194.google.com ([209.85.210.194]:43854 "EHLO mail-pf1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727109AbeHJEmg (ORCPT ); Fri, 10 Aug 2018 00:42:36 -0400 Received: by mail-pf1-f194.google.com with SMTP id j26-v6so3744510pfi.10 for ; Thu, 09 Aug 2018 19:14:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ziepe.ca; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=4ZAYAjkM5YfBUEYJDksijiTwk7rbNwkVRCl1SSHOrBs=; b=R0Al2F/sSYabF9lMTpfmPnD9iWG4I7qmKX/ModMXkDd9iDDFi3n8HJeYABgepAE755 qxLfB3TWISMV7VxDska0C2Javt31UvuITuwYzGBS6jQl64Lm2rstDC0zMN6whxLxl0Zo OhK63uaxbmCyOP9zqOqu5o3JuGTmHLkftU3D8ot3+6r6DSuo6neq4wIF1YUjEVau1PXu g6iFJCyxaARcUF1Y8nwgqeKL+pdQn2Jyn0eZ2QpQNZGieXFYrLCOqUUaQEs3V02DmKaF OQy0BVTaQAveuuNubZ5luHjljjREQIRdbi1Yw4lWw47qWGdlJIj+Wv8G24TtyQpsTuya 625w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=4ZAYAjkM5YfBUEYJDksijiTwk7rbNwkVRCl1SSHOrBs=; b=mdDtDs1SQqqLbUf9fS+N6svDaPUgoY4AA8V1zg0kLEKWIFyUg6FZ2lCz2mYbDmD+3I VHTLuLaq9q6XaRDYvVMkuBliF3hAzKYuHKir5Vxr1G4S0lDWN7DVdJLg31RCEIE/21th j3gLIoElYcfLpU4GFL4OL+oQ/Crgx9rTEZ7VHUcsUYjoGgG4WSwtHws1qMrT5GDyP3YX FhhmUhJ6DK4Vhz6aI9RlyqB5zitlf23UhPImaNqXw3Mc7Au81qcaOth5xE2/yJlY5zAB WZ3a0WQ45gAHyDLFxaM5sTyC3TpgoS2X/KAXcc6BEzH7xRxa7jujhldY7WUP7+Z6CZvu QL6g== X-Gm-Message-State: AOUpUlEoO0+OpcE7+FSPkegysuExKJWso9olcNMRWD2yb/5C6yPxtgT4 C+g35gcYIqN4z+JeppHL0P2aDEOfQQc= X-Google-Smtp-Source: AA+uWPySp8SyKXMGuox/Ni6UN0gfOcrUIPgY/McmUmx6x48P00SLvTt14yfk/wc5oN0wEGs3p5tbxA== X-Received: by 2002:a62:6cc7:: with SMTP id h190-v6mr4907691pfc.113.1533867295273; Thu, 09 Aug 2018 19:14:55 -0700 (PDT) Received: from ziepe.ca (S010614cc2056d97f.ed.shawcable.net. [174.3.196.123]) by smtp.gmail.com with ESMTPSA id s16-v6sm15280987pfd.0.2018.08.09.19.14.51 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Thu, 09 Aug 2018 19:14:52 -0700 (PDT) Received: from jgg by mlx with local (Exim 4.90_1) (envelope-from ) id 1fnwx1-0003gH-A1; Thu, 09 Aug 2018 20:14:51 -0600 From: Jason Gunthorpe To: linux-rdma@vger.kernel.org, Leon Romanovsky , "Guy Levi(SW)" , Yishai Hadas , "Ruhl, Michael J" Cc: Jason Gunthorpe Subject: [PATCH v1 02/10] IB/uverbs: Build the specs into a radix tree at runtime Date: Thu, 9 Aug 2018 20:14:36 -0600 Message-Id: <20180810021444.14014-3-jgg@ziepe.ca> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180810021444.14014-1-jgg@ziepe.ca> References: <20180810021444.14014-1-jgg@ziepe.ca> Sender: linux-rdma-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-rdma@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Jason Gunthorpe This radix tree datastructure is intended to replace the 'hash' structure used today for parsing ioctl methods during system calls. This first commit introduces the structure and builds it from the existing .rodata descriptions. The so-called hash arrangement is actually a 5 level open coded radix tree. This new version uses a 3 level radix tree built using the radix tree library. Overall this is much less code and much easier to build as the radix tree API allows for dynamic modification during the building. There is a small memory penalty to pay for this, but since the radix tree is allocated on a per device basis, a few kb of RAM seems immaterial considering the gained simplicity. The radix tree is similar to the existing tree, but also has a 'attr_bkey' concept, which is a small value'd index for each method attribute. This is used to simplify and improve performance of everything in the next patches. Signed-off-by: Jason Gunthorpe Reviewed-by: Leon Romanovsky Reviewed-by: Michael J. Ruhl --- drivers/infiniband/core/Makefile | 3 +- drivers/infiniband/core/rdma_core.h | 50 ++++ drivers/infiniband/core/uverbs.h | 1 + drivers/infiniband/core/uverbs_main.c | 14 +- drivers/infiniband/core/uverbs_uapi.c | 343 ++++++++++++++++++++++++++ include/rdma/uverbs_ioctl.h | 137 ++++++++++ 6 files changed, 545 insertions(+), 3 deletions(-) create mode 100644 drivers/infiniband/core/uverbs_uapi.c diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile index 61667705d74678..d934cf617841fb 100644 --- a/drivers/infiniband/core/Makefile +++ b/drivers/infiniband/core/Makefile @@ -37,4 +37,5 @@ ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_marshall.o \ rdma_core.o uverbs_std_types.o uverbs_ioctl.o \ uverbs_ioctl_merge.o uverbs_std_types_cq.o \ uverbs_std_types_flow_action.o uverbs_std_types_dm.o \ - uverbs_std_types_mr.o uverbs_std_types_counters.o + uverbs_std_types_mr.o uverbs_std_types_counters.o \ + uverbs_uapi.o diff --git a/drivers/infiniband/core/rdma_core.h b/drivers/infiniband/core/rdma_core.h index b2e85ce65b78cb..55a687285b1daa 100644 --- a/drivers/infiniband/core/rdma_core.h +++ b/drivers/infiniband/core/rdma_core.h @@ -43,6 +43,8 @@ #include #include +struct ib_uverbs_device; + int uverbs_ns_idx(u16 *id, unsigned int ns_count); const struct uverbs_object_spec *uverbs_get_object(struct ib_uverbs_file *ufile, uint16_t object); @@ -113,4 +115,52 @@ int uverbs_finalize_object(struct ib_uobject *uobj, void setup_ufile_idr_uobject(struct ib_uverbs_file *ufile); void release_ufile_idr_uobject(struct ib_uverbs_file *ufile); +/* + * This is the runtime description of the uverbs API, used by the syscall + * machinery to validate and dispatch calls. + */ + +/* + * Depending on ID the slot pointer in the radix tree points at one of these + * structs. + */ +struct uverbs_api_object { + const struct uverbs_obj_type *type_attrs; + const struct uverbs_obj_type_class *type_class; +}; + +struct uverbs_api_ioctl_method { + int (__rcu *handler)(struct ib_uverbs_file *ufile, + struct uverbs_attr_bundle *ctx); + DECLARE_BITMAP(attr_mandatory, UVERBS_API_ATTR_BKEY_LEN); + u8 driver_method:1; + u8 key_bitmap_len; + u8 destroy_bkey; +}; + +struct uverbs_api_attr { + struct uverbs_attr_spec spec; +}; + +struct uverbs_api_object; +struct uverbs_api { + /* radix tree contains struct uverbs_api_* pointers */ + struct radix_tree_root radix; + enum rdma_driver_id driver_id; +}; + +static inline const struct uverbs_api_object * +uapi_get_object(struct uverbs_api *uapi, u16 object_id) +{ + return radix_tree_lookup(&uapi->radix, uapi_key_obj(object_id)); +} + +char *uapi_key_format(char *S, unsigned int key); +struct uverbs_api *uverbs_alloc_api( + const struct uverbs_object_tree_def *const *driver_specs, + enum rdma_driver_id driver_id); +void uverbs_disassociate_api_pre(struct ib_uverbs_device *uverbs_dev); +void uverbs_disassociate_api(struct uverbs_api *uapi); +void uverbs_destroy_api(struct uverbs_api *uapi); + #endif /* RDMA_CORE_H */ diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index 0fa32009908c3d..879be0d1fd99d8 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -112,6 +112,7 @@ struct ib_uverbs_device { struct list_head uverbs_file_list; struct list_head uverbs_events_file_list; struct uverbs_root_spec *specs_root; + struct uverbs_api *uapi; }; struct ib_uverbs_event_queue { diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 20003594b5d6a7..0fab083cafef09 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -174,6 +174,7 @@ static void ib_uverbs_release_dev(struct kobject *kobj) struct ib_uverbs_device *dev = container_of(kobj, struct ib_uverbs_device, kobj); + uverbs_destroy_api(dev->uapi); cleanup_srcu_struct(&dev->disassociate_srcu); uverbs_free_spec_tree(dev->specs_root); kfree(dev); @@ -1000,6 +1001,7 @@ static int ib_uverbs_create_uapi(struct ib_device *device, const struct uverbs_object_tree_def **specs; struct uverbs_root_spec *specs_root; unsigned int num_specs = 1; + struct uverbs_api *uapi; unsigned int i; if (device->driver_specs) @@ -1020,7 +1022,14 @@ static int ib_uverbs_create_uapi(struct ib_device *device, if (IS_ERR(specs_root)) return PTR_ERR(specs_root); + uapi = uverbs_alloc_api(device->driver_specs, device->driver_id); + if (IS_ERR(uapi)) { + uverbs_free_spec_tree(specs_root); + return PTR_ERR(uapi); + } + uverbs_dev->specs_root = specs_root; + uverbs_dev->uapi = uapi; return 0; } @@ -1115,7 +1124,7 @@ static void ib_uverbs_free_hw_resources(struct ib_uverbs_device *uverbs_dev, struct ib_event event; /* Pending running commands to terminate */ - synchronize_srcu(&uverbs_dev->disassociate_srcu); + uverbs_disassociate_api_pre(uverbs_dev); event.event = IB_EVENT_DEVICE_FATAL; event.element.port_num = 0; event.device = ib_dev; @@ -1161,6 +1170,8 @@ static void ib_uverbs_free_hw_resources(struct ib_uverbs_device *uverbs_dev, kill_fasync(&event_file->ev_queue.async_queue, SIGIO, POLL_IN); } mutex_unlock(&uverbs_dev->lists_mutex); + + uverbs_disassociate_api(uverbs_dev->uapi); } static void ib_uverbs_remove_one(struct ib_device *device, void *client_data) @@ -1188,7 +1199,6 @@ static void ib_uverbs_remove_one(struct ib_device *device, void *client_data) * cdev was deleted, however active clients can still issue * commands and close their open files. */ - rcu_assign_pointer(uverbs_dev->ib_dev, NULL); ib_uverbs_free_hw_resources(uverbs_dev, device); wait_clients = 0; } diff --git a/drivers/infiniband/core/uverbs_uapi.c b/drivers/infiniband/core/uverbs_uapi.c new file mode 100644 index 00000000000000..21c0de034511c2 --- /dev/null +++ b/drivers/infiniband/core/uverbs_uapi.c @@ -0,0 +1,343 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* + * Copyright (c) 2017, Mellanox Technologies inc. All rights reserved. + */ +#include +#include +#include +#include "rdma_core.h" +#include "uverbs.h" + +static void *uapi_add_elm(struct uverbs_api *uapi, u32 key, size_t alloc_size) +{ + void *elm; + int rc; + + if (key == UVERBS_API_KEY_ERR) + return ERR_PTR(-EOVERFLOW); + + elm = kzalloc(alloc_size, GFP_KERNEL); + rc = radix_tree_insert(&uapi->radix, key, elm); + if (rc) { + kfree(elm); + return ERR_PTR(rc); + } + + return elm; +} + +static int uapi_merge_method(struct uverbs_api *uapi, + struct uverbs_api_object *obj_elm, u32 obj_key, + const struct uverbs_method_def *method, + bool is_driver) +{ + u32 method_key = obj_key | uapi_key_ioctl_method(method->id); + struct uverbs_api_ioctl_method *method_elm; + unsigned int i; + + if (!method->attrs) + return 0; + + method_elm = uapi_add_elm(uapi, method_key, sizeof(*method_elm)); + if (IS_ERR(method_elm)) { + if (method_elm != ERR_PTR(-EEXIST)) + return PTR_ERR(method_elm); + + /* + * This occurs when a driver uses ADD_UVERBS_ATTRIBUTES_SIMPLE + */ + if (WARN_ON(method->handler)) + return -EINVAL; + method_elm = radix_tree_lookup(&uapi->radix, method_key); + if (WARN_ON(!method_elm)) + return -EINVAL; + } else { + WARN_ON(!method->handler); + rcu_assign_pointer(method_elm->handler, method->handler); + if (method->handler != uverbs_destroy_def_handler) + method_elm->driver_method = is_driver; + } + + for (i = 0; i != method->num_attrs; i++) { + const struct uverbs_attr_def *attr = (*method->attrs)[i]; + struct uverbs_api_attr *attr_slot; + + if (!attr) + continue; + + /* + * ENUM_IN contains the 'ids' pointer to the driver's .rodata, + * so if it is specified by a driver then it always makes this + * into a driver method. + */ + if (attr->attr.type == UVERBS_ATTR_TYPE_ENUM_IN) + method_elm->driver_method |= is_driver; + + attr_slot = + uapi_add_elm(uapi, method_key | uapi_key_attr(attr->id), + sizeof(*attr_slot)); + /* Attributes are not allowed to be modified by drivers */ + if (IS_ERR(attr_slot)) + return PTR_ERR(attr_slot); + + attr_slot->spec = attr->attr; + } + + return 0; +} + +static int uapi_merge_tree(struct uverbs_api *uapi, + const struct uverbs_object_tree_def *tree, + bool is_driver) +{ + unsigned int i, j; + int rc; + + if (!tree->objects) + return 0; + + for (i = 0; i != tree->num_objects; i++) { + const struct uverbs_object_def *obj = (*tree->objects)[i]; + struct uverbs_api_object *obj_elm; + u32 obj_key; + + if (!obj) + continue; + + obj_key = uapi_key_obj(obj->id); + obj_elm = uapi_add_elm(uapi, obj_key, sizeof(*obj_elm)); + if (IS_ERR(obj_elm)) { + if (obj_elm != ERR_PTR(-EEXIST)) + return PTR_ERR(obj_elm); + + /* This occurs when a driver uses ADD_UVERBS_METHODS */ + if (WARN_ON(obj->type_attrs)) + return -EINVAL; + obj_elm = radix_tree_lookup(&uapi->radix, obj_key); + if (WARN_ON(!obj_elm)) + return -EINVAL; + } else { + obj_elm->type_attrs = obj->type_attrs; + if (obj->type_attrs) { + obj_elm->type_class = + obj->type_attrs->type_class; + /* + * Today drivers are only permitted to use + * idr_class types. They cannot use FD types + * because we currently have no way to revoke + * the fops pointer after device + * disassociation. + */ + if (WARN_ON(is_driver && + obj->type_attrs->type_class != + &uverbs_idr_class)) + return -EINVAL; + } + } + + if (!obj->methods) + continue; + + for (j = 0; j != obj->num_methods; j++) { + const struct uverbs_method_def *method = + (*obj->methods)[j]; + if (!method) + continue; + + rc = uapi_merge_method(uapi, obj_elm, obj_key, method, + is_driver); + if (rc) + return rc; + } + } + + return 0; +} + +static int +uapi_finalize_ioctl_method(struct uverbs_api *uapi, + struct uverbs_api_ioctl_method *method_elm, + u32 method_key) +{ + struct radix_tree_iter iter; + unsigned int max_bkey = 0; + bool single_uobj = false; + void __rcu **slot; + + method_elm->destroy_bkey = UVERBS_API_ATTR_BKEY_LEN; + radix_tree_for_each_slot (slot, &uapi->radix, &iter, + uapi_key_attrs_start(method_key)) { + struct uverbs_api_attr *elm = + rcu_dereference_protected(*slot, true); + u32 attr_key = iter.index & UVERBS_API_ATTR_KEY_MASK; + u32 attr_bkey = uapi_bkey_attr(attr_key); + u8 type = elm->spec.type; + + if (uapi_key_attr_to_method(iter.index) != + uapi_key_attr_to_method(method_key)) + break; + + if (elm->spec.mandatory) + __set_bit(attr_bkey, method_elm->attr_mandatory); + + if (type == UVERBS_ATTR_TYPE_IDR || + type == UVERBS_ATTR_TYPE_FD) { + u8 access = elm->spec.u.obj.access; + + /* + * Verbs specs may only have one NEW/DESTROY, we don't + * have the infrastructure to abort multiple NEW's or + * cope with multiple DESTROY failure. + */ + if (access == UVERBS_ACCESS_NEW || + access == UVERBS_ACCESS_DESTROY) { + if (WARN_ON(single_uobj)) + return -EINVAL; + + single_uobj = true; + if (WARN_ON(!elm->spec.mandatory)) + return -EINVAL; + } + + if (access == UVERBS_ACCESS_DESTROY) + method_elm->destroy_bkey = attr_bkey; + } + + max_bkey = max(max_bkey, attr_bkey); + } + + method_elm->key_bitmap_len = max_bkey + 1; + WARN_ON(method_elm->key_bitmap_len > UVERBS_API_ATTR_BKEY_LEN); + + return 0; +} + +static int uapi_finalize(struct uverbs_api *uapi) +{ + struct radix_tree_iter iter; + void __rcu **slot; + int rc; + + radix_tree_for_each_slot (slot, &uapi->radix, &iter, 0) { + struct uverbs_api_ioctl_method *method_elm = + rcu_dereference_protected(*slot, true); + + if (uapi_key_is_ioctl_method(iter.index)) { + rc = uapi_finalize_ioctl_method(uapi, method_elm, + iter.index); + if (rc) + return rc; + } + } + + return 0; +} + +void uverbs_destroy_api(struct uverbs_api *uapi) +{ + struct radix_tree_iter iter; + void __rcu **slot; + + if (!uapi) + return; + + radix_tree_for_each_slot (slot, &uapi->radix, &iter, 0) { + kfree(rcu_dereference_protected(*slot, true)); + radix_tree_iter_delete(&uapi->radix, &iter, slot); + } +} + +struct uverbs_api *uverbs_alloc_api( + const struct uverbs_object_tree_def *const *driver_specs, + enum rdma_driver_id driver_id) +{ + struct uverbs_api *uapi; + int rc; + + uapi = kzalloc(sizeof(*uapi), GFP_KERNEL); + if (!uapi) + return ERR_PTR(-ENOMEM); + + INIT_RADIX_TREE(&uapi->radix, GFP_KERNEL); + uapi->driver_id = driver_id; + + rc = uapi_merge_tree(uapi, uverbs_default_get_objects(), false); + if (rc) + goto err; + + for (; driver_specs && *driver_specs; driver_specs++) { + rc = uapi_merge_tree(uapi, *driver_specs, true); + if (rc) + goto err; + } + + rc = uapi_finalize(uapi); + if (rc) + goto err; + + return uapi; +err: + if (rc != -ENOMEM) + pr_err("Setup of uverbs_api failed, kernel parsing tree description is not valid (%d)??\n", + rc); + + uverbs_destroy_api(uapi); + return ERR_PTR(rc); +} + +/* + * The pre version is done before destroying the HW objects, it only blocks + * off method access. All methods that require the ib_dev or the module data + * must test one of these assignments prior to continuing. + */ +void uverbs_disassociate_api_pre(struct ib_uverbs_device *uverbs_dev) +{ + struct uverbs_api *uapi = uverbs_dev->uapi; + struct radix_tree_iter iter; + void __rcu **slot; + + rcu_assign_pointer(uverbs_dev->ib_dev, NULL); + + radix_tree_for_each_slot (slot, &uapi->radix, &iter, 0) { + if (uapi_key_is_ioctl_method(iter.index)) { + struct uverbs_api_ioctl_method *method_elm = + rcu_dereference_protected(*slot, true); + + if (method_elm->driver_method) + rcu_assign_pointer(method_elm->handler, NULL); + } + } + + synchronize_srcu(&uverbs_dev->disassociate_srcu); +} + +/* + * Called when a driver disassociates from the ib_uverbs_device. The + * assumption is that the driver module will unload after. Replace everything + * related to the driver with NULL as a safety measure. + */ +void uverbs_disassociate_api(struct uverbs_api *uapi) +{ + struct radix_tree_iter iter; + void __rcu **slot; + + radix_tree_for_each_slot (slot, &uapi->radix, &iter, 0) { + if (uapi_key_is_object(iter.index)) { + struct uverbs_api_object *object_elm = + rcu_dereference_protected(*slot, true); + + /* + * Some type_attrs are in the driver module. We don't + * bother to keep track of which since there should be + * no use of this after disassociate. + */ + object_elm->type_attrs = NULL; + } else if (uapi_key_is_attr(iter.index)) { + struct uverbs_api_attr *elm = + rcu_dereference_protected(*slot, true); + + if (elm->spec.type == UVERBS_ATTR_TYPE_ENUM_IN) + elm->spec.u2.enum_def.ids = NULL; + } + } +} diff --git a/include/rdma/uverbs_ioctl.h b/include/rdma/uverbs_ioctl.h index 8d71b7a7f1472a..339996e80c1687 100644 --- a/include/rdma/uverbs_ioctl.h +++ b/include/rdma/uverbs_ioctl.h @@ -154,6 +154,143 @@ struct uverbs_root_spec { struct uverbs_object_spec_hash *object_buckets[0]; }; +/* + * Information about the API is loaded into a radix tree. For IOCTL we start + * with a tuple of: + * object_id, attr_id, method_id + * + * Which is a 48 bit value, with most of the bits guaranteed to be zero. Based + * on the current kernel support this is compressed into 16 bit key for the + * radix tree. Since this compression is entirely internal to the kernel the + * below limits can be revised if the kernel gains additional data. + * + * With 64 leafs per node this is a 3 level radix tree. + * + * The tree encodes multiple types, and uses a scheme where OBJ_ID,0,0 returns + * the object slot, and OBJ_ID,METH_ID,0 and returns the method slot. + */ +enum uapi_radix_data { + UVERBS_API_NS_FLAG = 1U << UVERBS_ID_NS_SHIFT, + + UVERBS_API_ATTR_KEY_BITS = 6, + UVERBS_API_ATTR_KEY_MASK = GENMASK(UVERBS_API_ATTR_KEY_BITS - 1, 0), + UVERBS_API_ATTR_BKEY_LEN = (1 << UVERBS_API_ATTR_KEY_BITS) - 1, + + UVERBS_API_METHOD_KEY_BITS = 5, + UVERBS_API_METHOD_KEY_SHIFT = UVERBS_API_ATTR_KEY_BITS, + UVERBS_API_METHOD_KEY_NUM_CORE = 24, + UVERBS_API_METHOD_KEY_NUM_DRIVER = (1 << UVERBS_API_METHOD_KEY_BITS) - + UVERBS_API_METHOD_KEY_NUM_CORE, + UVERBS_API_METHOD_KEY_MASK = GENMASK( + UVERBS_API_METHOD_KEY_BITS + UVERBS_API_METHOD_KEY_SHIFT - 1, + UVERBS_API_METHOD_KEY_SHIFT), + + UVERBS_API_OBJ_KEY_BITS = 5, + UVERBS_API_OBJ_KEY_SHIFT = + UVERBS_API_METHOD_KEY_BITS + UVERBS_API_METHOD_KEY_SHIFT, + UVERBS_API_OBJ_KEY_NUM_CORE = 24, + UVERBS_API_OBJ_KEY_NUM_DRIVER = + (1 << UVERBS_API_OBJ_KEY_BITS) - UVERBS_API_OBJ_KEY_NUM_CORE, + UVERBS_API_OBJ_KEY_MASK = GENMASK(31, UVERBS_API_OBJ_KEY_SHIFT), + + /* This id guaranteed to not exist in the radix tree */ + UVERBS_API_KEY_ERR = 0xFFFFFFFF, +}; + +static inline __attribute_const__ u32 uapi_key_obj(u32 id) +{ + if (id & UVERBS_API_NS_FLAG) { + id &= ~UVERBS_API_NS_FLAG; + if (id >= UVERBS_API_OBJ_KEY_NUM_DRIVER) + return UVERBS_API_KEY_ERR; + id = id + UVERBS_API_OBJ_KEY_NUM_CORE; + } else { + if (id >= UVERBS_API_OBJ_KEY_NUM_CORE) + return UVERBS_API_KEY_ERR; + } + + return id << UVERBS_API_OBJ_KEY_SHIFT; +} + +static inline __attribute_const__ bool uapi_key_is_object(u32 key) +{ + return (key & ~UVERBS_API_OBJ_KEY_MASK) == 0; +} + +static inline __attribute_const__ u32 uapi_key_ioctl_method(u32 id) +{ + if (id & UVERBS_API_NS_FLAG) { + id &= ~UVERBS_API_NS_FLAG; + if (id >= UVERBS_API_METHOD_KEY_NUM_DRIVER) + return UVERBS_API_KEY_ERR; + id = id + UVERBS_API_METHOD_KEY_NUM_CORE; + } else { + id++; + if (id >= UVERBS_API_METHOD_KEY_NUM_CORE) + return UVERBS_API_KEY_ERR; + } + + return id << UVERBS_API_METHOD_KEY_SHIFT; +} + +static inline __attribute_const__ u32 uapi_key_attr_to_method(u32 attr_key) +{ + return attr_key & + (UVERBS_API_OBJ_KEY_MASK | UVERBS_API_METHOD_KEY_MASK); +} + +static inline __attribute_const__ bool uapi_key_is_ioctl_method(u32 key) +{ + return (key & UVERBS_API_METHOD_KEY_MASK) != 0 && + (key & UVERBS_API_ATTR_KEY_MASK) == 0; +} + +static inline __attribute_const__ u32 uapi_key_attrs_start(u32 ioctl_method_key) +{ + /* 0 is the method slot itself */ + return ioctl_method_key + 1; +} + +static inline __attribute_const__ u32 uapi_key_attr(u32 id) +{ + /* + * The attr is designed to fit in the typical single radix tree node + * of 64 entries. Since allmost all methods have driver attributes we + * organize things so that the driver and core attributes interleave to + * reduce the length of the attributes array in typical cases. + */ + if (id & UVERBS_API_NS_FLAG) { + id &= ~UVERBS_API_NS_FLAG; + id++; + if (id >= 1 << (UVERBS_API_ATTR_KEY_BITS - 1)) + return UVERBS_API_KEY_ERR; + id = (id << 1) | 0; + } else { + if (id >= 1 << (UVERBS_API_ATTR_KEY_BITS - 1)) + return UVERBS_API_KEY_ERR; + id = (id << 1) | 1; + } + + return id; +} + +static inline __attribute_const__ bool uapi_key_is_attr(u32 key) +{ + return (key & UVERBS_API_METHOD_KEY_MASK) != 0 && + (key & UVERBS_API_ATTR_KEY_MASK) != 0; +} + +/* + * This returns a value in the range [0 to UVERBS_API_ATTR_BKEY_LEN), + * basically it undoes the reservation of 0 in the ID numbering. attr_key + * must already be masked with UVERBS_API_ATTR_KEY_MASK, or be the output of + * uapi_key_attr(). + */ +static inline __attribute_const__ u32 uapi_bkey_attr(u32 attr_key) +{ + return attr_key - 1; +} + /* * ======================================= * Verbs definitions From patchwork Fri Aug 10 02:14:37 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Gunthorpe X-Patchwork-Id: 10562185 X-Patchwork-Delegate: jgg@ziepe.ca Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id F0AB31057 for ; Fri, 10 Aug 2018 02:14:57 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E01F92BBA0 for ; Fri, 10 Aug 2018 02:14:57 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D44CA2BBB0; Fri, 10 Aug 2018 02:14:57 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A36542BBA4 for ; Fri, 10 Aug 2018 02:14:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727087AbeHJEmf (ORCPT ); Fri, 10 Aug 2018 00:42:35 -0400 Received: from mail-pl0-f68.google.com ([209.85.160.68]:45622 "EHLO mail-pl0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725198AbeHJEmf (ORCPT ); Fri, 10 Aug 2018 00:42:35 -0400 Received: by mail-pl0-f68.google.com with SMTP id j8-v6so3350991pll.12 for ; Thu, 09 Aug 2018 19:14:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ziepe.ca; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=sYmu/7ICGNk+L4XYw4oxuOeHGPmGCGB92PHYGA6FM1o=; b=lSehcSxJSfUoyRGcDDszeyY6plrsapFZq/ykHJ+gYqeF0v8T3uvZoue5Sebtbim+sD wYJWuwTRKqTalpahA4kUB0Ec/QfLkf6o4zzWBpTQ5j1UUs5PnS0VRfsTilaYoThMtZkC nptzeL5Aw5R7ngARpeViaC8y9P9FfaekphsA+YC7ghPSJP0tU1QhXdW1apNpuCWv1F56 1LwVvU8tPqO1GbhB060oOkFNE54WdvNCpZhvE7WmzgDZLtO+pD2+BPvNqqWEjmeYfd9E FJGTRPWos2Gw+mzi0hhgLUA83QKNxPW1LpnA2F0NPNyjYPMnGPRXTC1MUtyc6edsv3OA +7aQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=sYmu/7ICGNk+L4XYw4oxuOeHGPmGCGB92PHYGA6FM1o=; b=h/Phbd76htNH/UV1qhhbJ5Z0t0/PZcNhtuHk9bcixPcmGgUvSdYtKV0zym9+yAq1tk 2G5Rf8uXjcN3mgrCz3/IGY79T+Ut6TpG+t7Y0mq9cI7CF/CnUWZ/0lYm+IgQYGq4KCes bBP2/z+SwAglkEdS3r1gujKgHxJ9ncG4Syd1tCChHPXhuBEVBTywHwp+6fV5FcK7RGgu 2PebLS9gY8dR8rCuIve3o5SmESlj++f6ZdbN3yaViOkggNt4kE0MydnY78hjokegjMAi AfkDaZ3ARYDi9PXenaVhqgIiyojwnxRNX9jSGCJ4J5vO9hh4ShQpnUrdcMgDMJF3bPSV WKzw== X-Gm-Message-State: AOUpUlE0SnaqdNcx54KkQT/5UVndgjsDje2XmQQFgfzg6RbVCRrbsIeK Md/JMZ5qUZCJQuWxxf69D89TEk5zOkM= X-Google-Smtp-Source: AA+uWPxBIEJGj8S1b1tjAM7+fSNatKS8FpnxA2LCx9VVWcMB1Lr2888Y2sEF69PcrIOkhJgYpsy/zw== X-Received: by 2002:a17:902:e28b:: with SMTP id cf11-v6mr4293344plb.86.1533867293644; Thu, 09 Aug 2018 19:14:53 -0700 (PDT) Received: from ziepe.ca (S010614cc2056d97f.ed.shawcable.net. [174.3.196.123]) by smtp.gmail.com with ESMTPSA id d13-v6sm7648023pgq.42.2018.08.09.19.14.51 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Thu, 09 Aug 2018 19:14:52 -0700 (PDT) Received: from jgg by mlx with local (Exim 4.90_1) (envelope-from ) id 1fnwx1-0003gN-B4; Thu, 09 Aug 2018 20:14:51 -0600 From: Jason Gunthorpe To: linux-rdma@vger.kernel.org, Leon Romanovsky , "Guy Levi(SW)" , Yishai Hadas , "Ruhl, Michael J" Cc: Jason Gunthorpe Subject: [PATCH v1 03/10] IB/uverbs: Use uverbs_api to manage the object type inside the uobject Date: Thu, 9 Aug 2018 20:14:37 -0600 Message-Id: <20180810021444.14014-4-jgg@ziepe.ca> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180810021444.14014-1-jgg@ziepe.ca> References: <20180810021444.14014-1-jgg@ziepe.ca> Sender: linux-rdma-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-rdma@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Jason Gunthorpe Currently the struct uverbs_obj_type stored in the ib_uobject is part of the .rodata segment of the module that defines the object. This is a problem if drivers define new uapi objects as we will be left with a dangling pointer after device disassociation. Switch the uverbs_obj_type for struct uverbs_api_object, which is allocated memory that is part of the uverbs_api and is guaranteed to always exist. Further this moves the 'type_class' into this memory which means access to the IDR/FD function pointers is also guaranteed. Drivers cannot define new types. This makes it safe to continue to use all uobjects, including driver defined ones, after disassociation. Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/rdma_core.c | 100 ++++++++++++++----------- drivers/infiniband/core/rdma_core.h | 2 +- drivers/infiniband/core/uverbs_ioctl.c | 6 +- include/rdma/ib_verbs.h | 2 +- include/rdma/uverbs_std_types.h | 30 ++++---- include/rdma/uverbs_types.h | 9 ++- 6 files changed, 79 insertions(+), 70 deletions(-) diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c index 4235b9ddc2adaf..2814228ead39f0 100644 --- a/drivers/infiniband/core/rdma_core.c +++ b/drivers/infiniband/core/rdma_core.c @@ -97,7 +97,7 @@ static void uverbs_uobject_free(struct kref *ref) struct ib_uobject *uobj = container_of(ref, struct ib_uobject, ref); - if (uobj->type->type_class->needs_kfree_rcu) + if (uobj->uapi_object->type_class->needs_kfree_rcu) kfree_rcu(uobj, rcu); else kfree(uobj); @@ -180,7 +180,7 @@ static int uverbs_destroy_uobject(struct ib_uobject *uobj, assert_uverbs_usecnt(uobj, UVERBS_LOOKUP_WRITE); if (uobj->object) { - ret = uobj->type->type_class->destroy_hw(uobj, reason); + ret = uobj->uapi_object->type_class->destroy_hw(uobj, reason); if (ret) { if (ib_is_destroy_retryable(ret, reason, uobj)) return ret; @@ -197,7 +197,7 @@ static int uverbs_destroy_uobject(struct ib_uobject *uobj, if (reason == RDMA_REMOVE_ABORT) { WARN_ON(!list_empty(&uobj->list)); WARN_ON(!uobj->context); - uobj->type->type_class->alloc_abort(uobj); + uobj->uapi_object->type_class->alloc_abort(uobj); } uobj->context = NULL; @@ -210,7 +210,7 @@ static int uverbs_destroy_uobject(struct ib_uobject *uobj, if (reason != RDMA_REMOVE_DESTROY) atomic_set(&uobj->usecnt, 0); else - uobj->type->type_class->remove_handle(uobj); + uobj->uapi_object->type_class->remove_handle(uobj); if (!list_empty(&uobj->list)) { spin_lock_irqsave(&ufile->uobjects_lock, flags); @@ -268,13 +268,13 @@ int uobj_destroy(struct ib_uobject *uobj) * with a NULL object pointer. The caller must pair this with * uverbs_put_destroy. */ -struct ib_uobject *__uobj_get_destroy(const struct uverbs_obj_type *type, +struct ib_uobject *__uobj_get_destroy(const struct uverbs_api_object *obj, u32 id, struct ib_uverbs_file *ufile) { struct ib_uobject *uobj; int ret; - uobj = rdma_lookup_get_uobject(type, ufile, id, UVERBS_LOOKUP_DESTROY); + uobj = rdma_lookup_get_uobject(obj, ufile, id, UVERBS_LOOKUP_DESTROY); if (IS_ERR(uobj)) return uobj; @@ -292,27 +292,22 @@ struct ib_uobject *__uobj_get_destroy(const struct uverbs_obj_type *type, * on success (negative errno on failure). For use by callers that do not need * the uobj. */ -int __uobj_perform_destroy(const struct uverbs_obj_type *type, u32 id, +int __uobj_perform_destroy(const struct uverbs_api_object *obj, u32 id, struct ib_uverbs_file *ufile, int success_res) { struct ib_uobject *uobj; - uobj = __uobj_get_destroy(type, id, ufile); + uobj = __uobj_get_destroy(obj, id, ufile); if (IS_ERR(uobj)) return PTR_ERR(uobj); - /* - * FIXME: After destroy this is not safe. We no longer hold the rwsem - * so disassociation could have completed and unloaded the module that - * backs the uobj->type pointer. - */ rdma_lookup_put_uobject(uobj, UVERBS_LOOKUP_WRITE); return success_res; } /* alloc_uobj must be undone by uverbs_destroy_uobject() */ static struct ib_uobject *alloc_uobj(struct ib_uverbs_file *ufile, - const struct uverbs_obj_type *type) + const struct uverbs_api_object *obj) { struct ib_uobject *uobj; struct ib_ucontext *ucontext; @@ -321,7 +316,7 @@ static struct ib_uobject *alloc_uobj(struct ib_uverbs_file *ufile, if (IS_ERR(ucontext)) return ERR_CAST(ucontext); - uobj = kzalloc(type->obj_size, GFP_KERNEL); + uobj = kzalloc(obj->type_attrs->obj_size, GFP_KERNEL); if (!uobj) return ERR_PTR(-ENOMEM); /* @@ -331,7 +326,7 @@ static struct ib_uobject *alloc_uobj(struct ib_uverbs_file *ufile, uobj->ufile = ufile; uobj->context = ucontext; INIT_LIST_HEAD(&uobj->list); - uobj->type = type; + uobj->uapi_object = obj; /* * Allocated objects start out as write locked to deny any other * syscalls from accessing them until they are committed. See @@ -368,7 +363,7 @@ static int idr_add_uobj(struct ib_uobject *uobj) /* Returns the ib_uobject or an error. The caller should check for IS_ERR. */ static struct ib_uobject * -lookup_get_idr_uobject(const struct uverbs_obj_type *type, +lookup_get_idr_uobject(const struct uverbs_api_object *obj, struct ib_uverbs_file *ufile, s64 id, enum rdma_lookup_mode mode) { @@ -401,15 +396,14 @@ lookup_get_idr_uobject(const struct uverbs_obj_type *type, } static struct ib_uobject * -lookup_get_fd_uobject(const struct uverbs_obj_type *type, +lookup_get_fd_uobject(const struct uverbs_api_object *obj, struct ib_uverbs_file *ufile, s64 id, enum rdma_lookup_mode mode) { + const struct uverbs_obj_fd_type *fd_type; struct file *f; struct ib_uobject *uobject; int fdno = id; - const struct uverbs_obj_fd_type *fd_type = - container_of(type, struct uverbs_obj_fd_type, type); if (fdno != id) return ERR_PTR(-EINVAL); @@ -417,6 +411,11 @@ lookup_get_fd_uobject(const struct uverbs_obj_type *type, if (mode != UVERBS_LOOKUP_READ) return ERR_PTR(-EOPNOTSUPP); + if (!obj->type_attrs) + return ERR_PTR(-EIO); + fd_type = + container_of(obj->type_attrs, struct uverbs_obj_fd_type, type); + f = fget(fdno); if (!f) return ERR_PTR(-EBADF); @@ -436,18 +435,21 @@ lookup_get_fd_uobject(const struct uverbs_obj_type *type, return uobject; } -struct ib_uobject *rdma_lookup_get_uobject(const struct uverbs_obj_type *type, +struct ib_uobject *rdma_lookup_get_uobject(const struct uverbs_api_object *obj, struct ib_uverbs_file *ufile, s64 id, enum rdma_lookup_mode mode) { struct ib_uobject *uobj; int ret; - uobj = type->type_class->lookup_get(type, ufile, id, mode); + if (!obj) + return ERR_PTR(-EINVAL); + + uobj = obj->type_class->lookup_get(obj, ufile, id, mode); if (IS_ERR(uobj)) return uobj; - if (uobj->type != type) { + if (uobj->uapi_object != obj) { ret = -EINVAL; goto free; } @@ -469,18 +471,19 @@ struct ib_uobject *rdma_lookup_get_uobject(const struct uverbs_obj_type *type, return uobj; free: - uobj->type->type_class->lookup_put(uobj, mode); + obj->type_class->lookup_put(uobj, mode); uverbs_uobject_put(uobj); return ERR_PTR(ret); } -static struct ib_uobject *alloc_begin_idr_uobject(const struct uverbs_obj_type *type, - struct ib_uverbs_file *ufile) +static struct ib_uobject * +alloc_begin_idr_uobject(const struct uverbs_api_object *obj, + struct ib_uverbs_file *ufile) { int ret; struct ib_uobject *uobj; - uobj = alloc_uobj(ufile, type); + uobj = alloc_uobj(ufile, obj); if (IS_ERR(uobj)) return uobj; @@ -504,8 +507,9 @@ static struct ib_uobject *alloc_begin_idr_uobject(const struct uverbs_obj_type * return ERR_PTR(ret); } -static struct ib_uobject *alloc_begin_fd_uobject(const struct uverbs_obj_type *type, - struct ib_uverbs_file *ufile) +static struct ib_uobject * +alloc_begin_fd_uobject(const struct uverbs_api_object *obj, + struct ib_uverbs_file *ufile) { int new_fd; struct ib_uobject *uobj; @@ -514,7 +518,7 @@ static struct ib_uobject *alloc_begin_fd_uobject(const struct uverbs_obj_type *t if (new_fd < 0) return ERR_PTR(new_fd); - uobj = alloc_uobj(ufile, type); + uobj = alloc_uobj(ufile, obj); if (IS_ERR(uobj)) { put_unused_fd(new_fd); return uobj; @@ -526,11 +530,14 @@ static struct ib_uobject *alloc_begin_fd_uobject(const struct uverbs_obj_type *t return uobj; } -struct ib_uobject *rdma_alloc_begin_uobject(const struct uverbs_obj_type *type, +struct ib_uobject *rdma_alloc_begin_uobject(const struct uverbs_api_object *obj, struct ib_uverbs_file *ufile) { struct ib_uobject *ret; + if (!obj) + return ERR_PTR(-EINVAL); + /* * The hw_destroy_rwsem is held across the entire object creation and * released during rdma_alloc_commit_uobject or @@ -539,7 +546,7 @@ struct ib_uobject *rdma_alloc_begin_uobject(const struct uverbs_obj_type *type, if (!down_read_trylock(&ufile->hw_destroy_rwsem)) return ERR_PTR(-EIO); - ret = type->type_class->alloc_begin(type, ufile); + ret = obj->type_class->alloc_begin(obj, ufile); if (IS_ERR(ret)) { up_read(&ufile->hw_destroy_rwsem); return ret; @@ -561,8 +568,8 @@ static int __must_check destroy_hw_idr_uobject(struct ib_uobject *uobj, enum rdma_remove_reason why) { const struct uverbs_obj_idr_type *idr_type = - container_of(uobj->type, struct uverbs_obj_idr_type, - type); + container_of(uobj->uapi_object->type_attrs, + struct uverbs_obj_idr_type, type); int ret = idr_type->destroy_object(uobj, why); /* @@ -599,8 +606,8 @@ static void alloc_abort_fd_uobject(struct ib_uobject *uobj) static int __must_check destroy_hw_fd_uobject(struct ib_uobject *uobj, enum rdma_remove_reason why) { - const struct uverbs_obj_fd_type *fd_type = - container_of(uobj->type, struct uverbs_obj_fd_type, type); + const struct uverbs_obj_fd_type *fd_type = container_of( + uobj->uapi_object->type_attrs, struct uverbs_obj_fd_type, type); int ret = fd_type->context_closed(uobj, why); if (ib_is_destroy_retryable(ret, why, uobj)) @@ -633,8 +640,8 @@ static int alloc_commit_idr_uobject(struct ib_uobject *uobj) static int alloc_commit_fd_uobject(struct ib_uobject *uobj) { - const struct uverbs_obj_fd_type *fd_type = - container_of(uobj->type, struct uverbs_obj_fd_type, type); + const struct uverbs_obj_fd_type *fd_type = container_of( + uobj->uapi_object->type_attrs, struct uverbs_obj_fd_type, type); int fd = uobj->id; struct file *filp; @@ -679,7 +686,7 @@ int __must_check rdma_alloc_commit_uobject(struct ib_uobject *uobj) int ret; /* alloc_commit consumes the uobj kref */ - ret = uobj->type->type_class->alloc_commit(uobj); + ret = uobj->uapi_object->type_class->alloc_commit(uobj); if (ret) { uverbs_destroy_uobject(uobj, RDMA_REMOVE_ABORT); up_read(&ufile->hw_destroy_rwsem); @@ -735,7 +742,7 @@ void rdma_lookup_put_uobject(struct ib_uobject *uobj, enum rdma_lookup_mode mode) { assert_uverbs_usecnt(uobj, mode); - uobj->type->type_class->lookup_put(uobj, mode); + uobj->uapi_object->type_class->lookup_put(uobj, mode); /* * In order to unlock an object, either decrease its usecnt for * read access or zero it in case of exclusive access. See @@ -995,23 +1002,26 @@ const struct uverbs_obj_type_class uverbs_fd_class = { EXPORT_SYMBOL(uverbs_fd_class); struct ib_uobject * -uverbs_get_uobject_from_file(const struct uverbs_obj_type *type_attrs, +uverbs_get_uobject_from_file(u16 object_id, struct ib_uverbs_file *ufile, enum uverbs_obj_access access, s64 id) { + const struct uverbs_api_object *obj = + uapi_get_object(ufile->device->uapi, object_id); + switch (access) { case UVERBS_ACCESS_READ: - return rdma_lookup_get_uobject(type_attrs, ufile, id, + return rdma_lookup_get_uobject(obj, ufile, id, UVERBS_LOOKUP_READ); case UVERBS_ACCESS_DESTROY: /* Actual destruction is done inside uverbs_handle_method */ - return rdma_lookup_get_uobject(type_attrs, ufile, id, + return rdma_lookup_get_uobject(obj, ufile, id, UVERBS_LOOKUP_DESTROY); case UVERBS_ACCESS_WRITE: - return rdma_lookup_get_uobject(type_attrs, ufile, id, + return rdma_lookup_get_uobject(obj, ufile, id, UVERBS_LOOKUP_WRITE); case UVERBS_ACCESS_NEW: - return rdma_alloc_begin_uobject(type_attrs, ufile); + return rdma_alloc_begin_uobject(obj, ufile); default: WARN_ON(true); return ERR_PTR(-EOPNOTSUPP); diff --git a/drivers/infiniband/core/rdma_core.h b/drivers/infiniband/core/rdma_core.h index 55a687285b1daa..d89569d87b1cff 100644 --- a/drivers/infiniband/core/rdma_core.h +++ b/drivers/infiniband/core/rdma_core.h @@ -89,7 +89,7 @@ void uverbs_close_fd(struct file *f); * uverbs_finalize_objects are called. */ struct ib_uobject * -uverbs_get_uobject_from_file(const struct uverbs_obj_type *type_attrs, +uverbs_get_uobject_from_file(u16 object_id, struct ib_uverbs_file *ufile, enum uverbs_obj_access access, s64 id); diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c index f0655a84f9d9c9..8fd64f2b147a56 100644 --- a/drivers/infiniband/core/uverbs_ioctl.c +++ b/drivers/infiniband/core/uverbs_ioctl.c @@ -57,7 +57,6 @@ static int uverbs_process_attr(struct ib_uverbs_file *ufile, const struct uverbs_attr_spec *spec; const struct uverbs_attr_spec *val_spec; struct uverbs_attr *e; - const struct uverbs_object_spec *object; struct uverbs_obj_attr *o_attr; struct uverbs_attr *elements = attr_bundle_h->attrs; @@ -145,9 +144,6 @@ static int uverbs_process_attr(struct ib_uverbs_file *ufile, return -EINVAL; o_attr = &e->obj_attr; - object = uverbs_get_object(ufile, spec->u.obj.obj_type); - if (!object) - return -EINVAL; /* specs are allowed to have only one destroy attribute */ WARN_ON(spec->u.obj.access == UVERBS_ACCESS_DESTROY && @@ -162,7 +158,7 @@ static int uverbs_process_attr(struct ib_uverbs_file *ufile, * IDR implementation today rejects negative IDs */ o_attr->uobject = uverbs_get_uobject_from_file( - object->type_attrs, + spec->u.obj.obj_type, ufile, spec->u.obj.access, uattr->data_s64); diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 3b07201b9a804e..5d404c20b49f27 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -1524,7 +1524,7 @@ struct ib_uobject { atomic_t usecnt; /* protects exclusive access */ struct rcu_head rcu; /* kfree_rcu() overhead */ - const struct uverbs_obj_type *type; + const struct uverbs_api_object *uapi_object; }; struct ib_udata { diff --git a/include/rdma/uverbs_std_types.h b/include/rdma/uverbs_std_types.h index 64ee2545dd3db3..3b00231cc084d7 100644 --- a/include/rdma/uverbs_std_types.h +++ b/include/rdma/uverbs_std_types.h @@ -54,14 +54,15 @@ static inline const struct uverbs_object_tree_def *uverbs_default_get_objects(vo */ #define _uobj_check_id(_id) ((_id) * typecheck(u32, _id)) -#define uobj_get_type(_object) UVERBS_OBJECT(_object).type_attrs +#define uobj_get_type(_ufile, _object) \ + uapi_get_object((_ufile)->device->uapi, _object) #define uobj_get_read(_type, _id, _ufile) \ - rdma_lookup_get_uobject(uobj_get_type(_type), _ufile, \ + rdma_lookup_get_uobject(uobj_get_type(_ufile, _type), _ufile, \ _uobj_check_id(_id), UVERBS_LOOKUP_READ) #define ufd_get_read(_type, _fdnum, _ufile) \ - rdma_lookup_get_uobject(uobj_get_type(_type), _ufile, \ + rdma_lookup_get_uobject(uobj_get_type(_ufile, _type), _ufile, \ (_fdnum)*typecheck(s32, _fdnum), \ UVERBS_LOOKUP_READ) @@ -76,20 +77,21 @@ static inline void *_uobj_get_obj_read(struct ib_uobject *uobj) uobj_get_read(_type, _id, _ufile))) #define uobj_get_write(_type, _id, _ufile) \ - rdma_lookup_get_uobject(uobj_get_type(_type), _ufile, \ + rdma_lookup_get_uobject(uobj_get_type(_ufile, _type), _ufile, \ _uobj_check_id(_id), UVERBS_LOOKUP_WRITE) -int __uobj_perform_destroy(const struct uverbs_obj_type *type, u32 id, +int __uobj_perform_destroy(const struct uverbs_api_object *obj, u32 id, struct ib_uverbs_file *ufile, int success_res); #define uobj_perform_destroy(_type, _id, _ufile, _success_res) \ - __uobj_perform_destroy(uobj_get_type(_type), _uobj_check_id(_id), \ - _ufile, _success_res) + __uobj_perform_destroy(uobj_get_type(_ufile, _type), \ + _uobj_check_id(_id), _ufile, _success_res) -struct ib_uobject *__uobj_get_destroy(const struct uverbs_obj_type *type, +struct ib_uobject *__uobj_get_destroy(const struct uverbs_api_object *obj, u32 id, struct ib_uverbs_file *ufile); #define uobj_get_destroy(_type, _id, _ufile) \ - __uobj_get_destroy(uobj_get_type(_type), _uobj_check_id(_id), _ufile) + __uobj_get_destroy(uobj_get_type(_ufile, _type), _uobj_check_id(_id), \ + _ufile) static inline void uobj_put_destroy(struct ib_uobject *uobj) { @@ -124,11 +126,11 @@ static inline void uobj_alloc_abort(struct ib_uobject *uobj) rdma_alloc_abort_uobject(uobj); } -static inline struct ib_uobject *__uobj_alloc(const struct uverbs_obj_type *type, - struct ib_uverbs_file *ufile, - struct ib_device **ib_dev) +static inline struct ib_uobject * +__uobj_alloc(const struct uverbs_api_object *obj, struct ib_uverbs_file *ufile, + struct ib_device **ib_dev) { - struct ib_uobject *uobj = rdma_alloc_begin_uobject(type, ufile); + struct ib_uobject *uobj = rdma_alloc_begin_uobject(obj, ufile); if (!IS_ERR(uobj)) *ib_dev = uobj->context->device; @@ -136,7 +138,7 @@ static inline struct ib_uobject *__uobj_alloc(const struct uverbs_obj_type *type } #define uobj_alloc(_type, _ufile, _ib_dev) \ - __uobj_alloc(uobj_get_type(_type), _ufile, _ib_dev) + __uobj_alloc(uobj_get_type(_ufile, _type), _ufile, _ib_dev) #endif diff --git a/include/rdma/uverbs_types.h b/include/rdma/uverbs_types.h index 1ab9a85eebd9f2..acb1bfa3cc99a5 100644 --- a/include/rdma/uverbs_types.h +++ b/include/rdma/uverbs_types.h @@ -37,6 +37,7 @@ #include struct uverbs_obj_type; +struct uverbs_api_object; enum rdma_lookup_mode { UVERBS_LOOKUP_READ, @@ -81,14 +82,14 @@ enum rdma_lookup_mode { * alloc_abort returns. */ struct uverbs_obj_type_class { - struct ib_uobject *(*alloc_begin)(const struct uverbs_obj_type *type, + struct ib_uobject *(*alloc_begin)(const struct uverbs_api_object *obj, struct ib_uverbs_file *ufile); /* This consumes the kref on uobj */ int (*alloc_commit)(struct ib_uobject *uobj); /* This does not consume the kref on uobj */ void (*alloc_abort)(struct ib_uobject *uobj); - struct ib_uobject *(*lookup_get)(const struct uverbs_obj_type *type, + struct ib_uobject *(*lookup_get)(const struct uverbs_api_object *obj, struct ib_uverbs_file *ufile, s64 id, enum rdma_lookup_mode mode); void (*lookup_put)(struct ib_uobject *uobj, enum rdma_lookup_mode mode); @@ -128,12 +129,12 @@ struct uverbs_obj_idr_type { enum rdma_remove_reason why); }; -struct ib_uobject *rdma_lookup_get_uobject(const struct uverbs_obj_type *type, +struct ib_uobject *rdma_lookup_get_uobject(const struct uverbs_api_object *obj, struct ib_uverbs_file *ufile, s64 id, enum rdma_lookup_mode mode); void rdma_lookup_put_uobject(struct ib_uobject *uobj, enum rdma_lookup_mode mode); -struct ib_uobject *rdma_alloc_begin_uobject(const struct uverbs_obj_type *type, +struct ib_uobject *rdma_alloc_begin_uobject(const struct uverbs_api_object *obj, struct ib_uverbs_file *ufile); void rdma_alloc_abort_uobject(struct ib_uobject *uobj); int __must_check rdma_alloc_commit_uobject(struct ib_uobject *uobj); From patchwork Fri Aug 10 02:14:38 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Gunthorpe X-Patchwork-Id: 10562191 X-Patchwork-Delegate: jgg@ziepe.ca Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 023D996FA for ; Fri, 10 Aug 2018 02:15:01 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E5ACF2BB93 for ; Fri, 10 Aug 2018 02:15:00 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id DA2032BBD6; Fri, 10 Aug 2018 02:15:00 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 762852BB93 for ; Fri, 10 Aug 2018 02:14:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727146AbeHJEmg (ORCPT ); Fri, 10 Aug 2018 00:42:36 -0400 Received: from mail-pf1-f194.google.com ([209.85.210.194]:33415 "EHLO mail-pf1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725198AbeHJEmg (ORCPT ); Fri, 10 Aug 2018 00:42:36 -0400 Received: by mail-pf1-f194.google.com with SMTP id d4-v6so3769202pfn.0 for ; Thu, 09 Aug 2018 19:14:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ziepe.ca; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=pWyqWxAADKBKOatkdSJlrd/YeeS2R6ZzF5sLxtzTLbo=; b=kxwa7hsa4Y7WPaiBH0HGaQ+pQ7q/jwfIsvHQj1gHYbeD30s+xl7q2SA3ErbdckAyxN xlSIJhiTGEhDkBlFAerwybd9dLGpoFvIM6cptrtMcMxIBWQyKwxgaovgoeygGjiuhXuT tgEfnpKBIshXMzyCk5dXTKDoV70JvmvHx8/8J6dm1yUCbtj8HnUATob8+1V3QORB3mcI 4flmSxn+f8kZ9R82T6GrZ5wV8TjxOsHnMDeJwr94nWb9FjWRIZKNTEX9JV+CvDWmyTy1 CD5T4e+KyHvQP52E9KCrqOYIIBkGZgc4kkJ/JF4VMCEhYSkvX93sjfLqptx7QbD/ZrMk qJQA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=pWyqWxAADKBKOatkdSJlrd/YeeS2R6ZzF5sLxtzTLbo=; b=Ct13r7Q7PQMQCAVkk17Pxe2HdLLGguVapMjYFNiv9L3hIDpq56dwK00SjguULy1Uui a0ea/KtxKb66dqsGz4aZ15Lm1U7dVdQ1xD+n5ZwUEh73aBB3dxehyEdeVQ0hrYZU0bSl 9FmmGRGWh6vAuBbvyaBd6fIhmgzJoff50SRVAjhGQldmA7nodXpesmgD266NWVdPwbi5 PETyyLBRD/+o1SF/sZMVsU/V/ARGBAUL0529U177zuQjxG1zqacyHbMMfL31uPOs0s5e GglRwD/Ho+jYpSPTK3KoB8QhGr6kdouInhD/b3T6RHr1aI12OgoevehvtMZUtvhEPHZd Q1qQ== X-Gm-Message-State: AOUpUlHTdpkPbUAJPrROE2jr/1b51v/tVoxWGtLWbzbyOqGlYxu0UVxL NQ1/RMtRjHzUXteo0RL5Xxp0yP+UWLE= X-Google-Smtp-Source: AA+uWPx/IeInNDK5D7fibk5wJszRJ84ix1jqJwGLBPUXRY3AuXZBJP9d0SiAXelgy/tWNyO8WRhjQQ== X-Received: by 2002:a62:c90a:: with SMTP id k10-v6mr4807566pfg.180.1533867294857; Thu, 09 Aug 2018 19:14:54 -0700 (PDT) Received: from ziepe.ca (S010614cc2056d97f.ed.shawcable.net. [174.3.196.123]) by smtp.gmail.com with ESMTPSA id n80-v6sm21901447pfb.95.2018.08.09.19.14.51 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Thu, 09 Aug 2018 19:14:52 -0700 (PDT) Received: from jgg by mlx with local (Exim 4.90_1) (envelope-from ) id 1fnwx1-0003gT-D5; Thu, 09 Aug 2018 20:14:51 -0600 From: Jason Gunthorpe To: linux-rdma@vger.kernel.org, Leon Romanovsky , "Guy Levi(SW)" , Yishai Hadas , "Ruhl, Michael J" Cc: Jason Gunthorpe Subject: [PATCH v1 04/10] IB/uverbs: Provide implementation private memory for the uverbs_attr_bundle Date: Thu, 9 Aug 2018 20:14:38 -0600 Message-Id: <20180810021444.14014-5-jgg@ziepe.ca> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180810021444.14014-1-jgg@ziepe.ca> References: <20180810021444.14014-1-jgg@ziepe.ca> Sender: linux-rdma-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-rdma@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Jason Gunthorpe This already existed as the anonymous 'ctx' structure, but this was not really a useful form. Hoist this struct into bundle_priv and rework the internal things to use it instead. Move a bunch of the processing internal state into the priv and reduce the excessive use of function arguments. Signed-off-by: Jason Gunthorpe Reviewed-by: Leon Romanovsky --- drivers/infiniband/core/uverbs_ioctl.c | 112 +++++++++++++------------ include/rdma/uverbs_ioctl.h | 1 + 2 files changed, 58 insertions(+), 55 deletions(-) diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c index 8fd64f2b147a56..74b0a40aaa36ea 100644 --- a/drivers/infiniband/core/uverbs_ioctl.c +++ b/drivers/infiniband/core/uverbs_ioctl.c @@ -35,6 +35,18 @@ #include "rdma_core.h" #include "uverbs.h" +struct bundle_priv { + struct ib_uverbs_attr __user *user_attrs; + struct ib_uverbs_attr *uattrs; + struct uverbs_obj_attr *destroy_attr; + + /* + * Must be last. bundle ends in a flex array which overlaps + * internal_buffer. + */ + struct uverbs_attr_bundle bundle; +}; + static bool uverbs_is_attr_cleared(const struct ib_uverbs_attr *uattr, u16 len) { @@ -46,12 +58,11 @@ static bool uverbs_is_attr_cleared(const struct ib_uverbs_attr *uattr, 0, uattr->len - len); } -static int uverbs_process_attr(struct ib_uverbs_file *ufile, +static int uverbs_process_attr(struct bundle_priv *pbundle, const struct ib_uverbs_attr *uattr, u16 attr_id, const struct uverbs_attr_spec_hash *attr_spec_bucket, struct uverbs_attr_bundle_hash *attr_bundle_h, - struct uverbs_obj_attr **destroy_attr, struct ib_uverbs_attr __user *uattr_ptr) { const struct uverbs_attr_spec *spec; @@ -147,9 +158,9 @@ static int uverbs_process_attr(struct ib_uverbs_file *ufile, /* specs are allowed to have only one destroy attribute */ WARN_ON(spec->u.obj.access == UVERBS_ACCESS_DESTROY && - *destroy_attr); + pbundle->destroy_attr); if (spec->u.obj.access == UVERBS_ACCESS_DESTROY) - *destroy_attr = o_attr; + pbundle->destroy_attr = o_attr; /* * The type of uattr->data is u64 for UVERBS_ATTR_TYPE_IDR and @@ -159,7 +170,7 @@ static int uverbs_process_attr(struct ib_uverbs_file *ufile, */ o_attr->uobject = uverbs_get_uobject_from_file( spec->u.obj.obj_type, - ufile, + pbundle->bundle.ufile, spec->u.obj.access, uattr->data_s64); @@ -187,10 +198,11 @@ static int uverbs_process_attr(struct ib_uverbs_file *ufile, return 0; } -static int uverbs_finalize_attrs(struct uverbs_attr_bundle *attrs_bundle, +static int uverbs_finalize_attrs(struct bundle_priv *pbundle, struct uverbs_attr_spec_hash *const *spec_hash, size_t num, bool commit) { + struct uverbs_attr_bundle *attrs_bundle = &pbundle->bundle; unsigned int i; int ret = 0; @@ -233,27 +245,25 @@ static int uverbs_finalize_attrs(struct uverbs_attr_bundle *attrs_bundle, return ret; } -static int uverbs_uattrs_process(struct ib_uverbs_file *ufile, - const struct ib_uverbs_attr *uattrs, - size_t num_uattrs, +static int uverbs_uattrs_process(size_t num_uattrs, const struct uverbs_method_spec *method, - struct uverbs_attr_bundle *attr_bundle, - struct uverbs_obj_attr **destroy_attr, - struct ib_uverbs_attr __user *uattr_ptr) + struct bundle_priv *pbundle) { + struct uverbs_attr_bundle *attr_bundle = &pbundle->bundle; + struct ib_uverbs_attr __user *uattr_ptr = pbundle->user_attrs; size_t i; int ret = 0; int num_given_buckets = 0; for (i = 0; i < num_uattrs; i++) { - const struct ib_uverbs_attr *uattr = &uattrs[i]; + const struct ib_uverbs_attr *uattr = &pbundle->uattrs[i]; u16 attr_id = uattr->attr_id; struct uverbs_attr_spec_hash *attr_spec_bucket; ret = uverbs_ns_idx(&attr_id, method->num_buckets); if (ret < 0 || !method->attr_buckets[ret]) { if (uattr->flags & UVERBS_ATTR_F_MANDATORY) { - uverbs_finalize_attrs(attr_bundle, + uverbs_finalize_attrs(pbundle, method->attr_buckets, num_given_buckets, false); @@ -270,12 +280,13 @@ static int uverbs_uattrs_process(struct ib_uverbs_file *ufile, num_given_buckets = ret + 1; attr_spec_bucket = method->attr_buckets[ret]; - ret = uverbs_process_attr(ufile, uattr, attr_id, + ret = uverbs_process_attr(pbundle, + uattr, attr_id, attr_spec_bucket, - &attr_bundle->hash[ret], destroy_attr, + &attr_bundle->hash[ret], uattr_ptr++); if (ret) { - uverbs_finalize_attrs(attr_bundle, + uverbs_finalize_attrs(pbundle, method->attr_buckets, num_given_buckets, false); @@ -287,8 +298,9 @@ static int uverbs_uattrs_process(struct ib_uverbs_file *ufile, } static int uverbs_validate_kernel_mandatory(const struct uverbs_method_spec *method_spec, - struct uverbs_attr_bundle *attr_bundle) + struct bundle_priv *pbundle) { + struct uverbs_attr_bundle *attr_bundle = &pbundle->bundle; unsigned int i; for (i = 0; i < attr_bundle->num_buckets; i++) { @@ -316,27 +328,22 @@ static int uverbs_validate_kernel_mandatory(const struct uverbs_method_spec *met return 0; } -static int uverbs_handle_method(struct ib_uverbs_attr __user *uattr_ptr, - const struct ib_uverbs_attr *uattrs, - size_t num_uattrs, - struct ib_device *ibdev, - struct ib_uverbs_file *ufile, +static int uverbs_handle_method(size_t num_uattrs, const struct uverbs_method_spec *method_spec, - struct uverbs_attr_bundle *attr_bundle) + struct bundle_priv *pbundle) { + struct uverbs_attr_bundle *attr_bundle = &pbundle->bundle; int ret; int finalize_ret; int num_given_buckets; - struct uverbs_obj_attr *destroy_attr = NULL; num_given_buckets = - uverbs_uattrs_process(ufile, uattrs, num_uattrs, method_spec, - attr_bundle, &destroy_attr, uattr_ptr); + uverbs_uattrs_process(num_uattrs, method_spec, pbundle); if (num_given_buckets <= 0) return -EINVAL; attr_bundle->num_buckets = num_given_buckets; - ret = uverbs_validate_kernel_mandatory(method_spec, attr_bundle); + ret = uverbs_validate_kernel_mandatory(method_spec, pbundle); if (ret) goto cleanup; @@ -344,21 +351,21 @@ static int uverbs_handle_method(struct ib_uverbs_attr __user *uattr_ptr, * We destroy the HW object before invoking the handler, handlers do * not get to manipulate the HW objects. */ - if (destroy_attr) { - ret = uobj_destroy(destroy_attr->uobject); + if (pbundle->destroy_attr) { + ret = uobj_destroy(pbundle->destroy_attr->uobject); if (ret) goto cleanup; } - ret = method_spec->handler(ufile, attr_bundle); + ret = method_spec->handler(pbundle->bundle.ufile, attr_bundle); - if (destroy_attr) { - uobj_put_destroy(destroy_attr->uobject); - destroy_attr->uobject = NULL; + if (pbundle->destroy_attr) { + uobj_put_destroy(pbundle->destroy_attr->uobject); + pbundle->destroy_attr->uobject = NULL; } cleanup: - finalize_ret = uverbs_finalize_attrs(attr_bundle, + finalize_ret = uverbs_finalize_attrs(pbundle, method_spec->attr_buckets, attr_bundle->num_buckets, !ret); @@ -370,16 +377,13 @@ static int uverbs_handle_method(struct ib_uverbs_attr __user *uattr_ptr, static long ib_uverbs_cmd_verbs(struct ib_device *ib_dev, struct ib_uverbs_file *file, struct ib_uverbs_ioctl_hdr *hdr, - void __user *buf) + struct ib_uverbs_attr __user *user_attrs) { const struct uverbs_object_spec *object_spec; const struct uverbs_method_spec *method_spec; long err = 0; unsigned int i; - struct { - struct ib_uverbs_attr *uattrs; - struct uverbs_attr_bundle *uverbs_attr_bundle; - } *ctx = NULL; + struct bundle_priv *ctx; struct uverbs_attr *curr_attr; unsigned long *curr_bitmap; size_t ctx_size; @@ -397,12 +401,11 @@ static long ib_uverbs_cmd_verbs(struct ib_device *ib_dev, return -EPROTONOSUPPORT; ctx_size = sizeof(*ctx) + - sizeof(struct uverbs_attr_bundle) + sizeof(struct uverbs_attr_bundle_hash) * method_spec->num_buckets + sizeof(*ctx->uattrs) * hdr->num_attrs + - sizeof(*ctx->uverbs_attr_bundle->hash[0].attrs) * + sizeof(*ctx->bundle.hash[0].attrs) * method_spec->num_child_attrs + - sizeof(*ctx->uverbs_attr_bundle->hash[0].valid_bitmap) * + sizeof(*ctx->bundle.hash[0].valid_bitmap) * (method_spec->num_child_attrs / BITS_PER_LONG + method_spec->num_buckets); @@ -413,10 +416,8 @@ static long ib_uverbs_cmd_verbs(struct ib_device *ib_dev, if (!ctx) return -ENOMEM; - ctx->uverbs_attr_bundle = (void *)ctx + sizeof(*ctx); - ctx->uattrs = (void *)(ctx->uverbs_attr_bundle + 1) + - (sizeof(ctx->uverbs_attr_bundle->hash[0]) * - method_spec->num_buckets); + ctx->uattrs = (void *)(ctx + 1) + + (sizeof(ctx->bundle.hash[0]) * method_spec->num_buckets); curr_attr = (void *)(ctx->uattrs + hdr->num_attrs); curr_bitmap = (void *)(curr_attr + method_spec->num_child_attrs); @@ -432,23 +433,25 @@ static long ib_uverbs_cmd_verbs(struct ib_device *ib_dev, curr_num_attrs = method_spec->attr_buckets[i]->num_attrs; - ctx->uverbs_attr_bundle->hash[i].attrs = curr_attr; + ctx->bundle.hash[i].attrs = curr_attr; curr_attr += curr_num_attrs; - ctx->uverbs_attr_bundle->hash[i].num_attrs = curr_num_attrs; - ctx->uverbs_attr_bundle->hash[i].valid_bitmap = curr_bitmap; + ctx->bundle.hash[i].num_attrs = curr_num_attrs; + ctx->bundle.hash[i].valid_bitmap = curr_bitmap; bitmap_zero(curr_bitmap, curr_num_attrs); curr_bitmap += BITS_TO_LONGS(curr_num_attrs); } - err = copy_from_user(ctx->uattrs, buf, + err = copy_from_user(ctx->uattrs, user_attrs, sizeof(*ctx->uattrs) * hdr->num_attrs); if (err) { err = -EFAULT; goto out; } - err = uverbs_handle_method(buf, ctx->uattrs, hdr->num_attrs, ib_dev, - file, method_spec, ctx->uverbs_attr_bundle); + ctx->destroy_attr = NULL; + ctx->bundle.ufile = file; + ctx->user_attrs = user_attrs; + err = uverbs_handle_method(hdr->num_attrs, method_spec, ctx); /* * EPROTONOSUPPORT is ONLY to be returned if the ioctl framework can @@ -499,8 +502,7 @@ long ib_uverbs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) goto out; } - err = ib_uverbs_cmd_verbs(ib_dev, file, &hdr, - (__user void *)arg + sizeof(hdr)); + err = ib_uverbs_cmd_verbs(ib_dev, file, &hdr, user_hdr->attrs); } else { err = -ENOIOCTLCMD; } diff --git a/include/rdma/uverbs_ioctl.h b/include/rdma/uverbs_ioctl.h index 339996e80c1687..3b497d9ed39592 100644 --- a/include/rdma/uverbs_ioctl.h +++ b/include/rdma/uverbs_ioctl.h @@ -494,6 +494,7 @@ struct uverbs_attr_bundle_hash { }; struct uverbs_attr_bundle { + struct ib_uverbs_file *ufile; size_t num_buckets; struct uverbs_attr_bundle_hash hash[]; }; From patchwork Fri Aug 10 02:14:39 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Gunthorpe X-Patchwork-Id: 10562181 X-Patchwork-Delegate: jgg@ziepe.ca Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A11D51057 for ; Fri, 10 Aug 2018 02:14:56 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 913EF2BB93 for ; Fri, 10 Aug 2018 02:14:56 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 851E62BBAF; Fri, 10 Aug 2018 02:14:56 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D8BBF2BB93 for ; Fri, 10 Aug 2018 02:14:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725917AbeHJEmf (ORCPT ); Fri, 10 Aug 2018 00:42:35 -0400 Received: from mail-pl0-f65.google.com ([209.85.160.65]:39365 "EHLO mail-pl0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727087AbeHJEme (ORCPT ); Fri, 10 Aug 2018 00:42:34 -0400 Received: by mail-pl0-f65.google.com with SMTP id w14-v6so3361305plp.6 for ; Thu, 09 Aug 2018 19:14:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ziepe.ca; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=xFom53/xfiAGgTrlrijS1PZFRbE74GFo0tpmjlnUaOU=; b=I5CuSUEQ3Wd4SatJgx0hoW9vZxIdTS4EGE6qpEqVn+c82UYNZv5mDkicNvrLyiX4wo tNgyx4gvUUwvXnjbWD31qRjId2yiQN4kimtLWxMHZ2lekPbWuit65CkP4Wxz/EQmNPH0 18CnBBR/MxQcT+IOHsP+MQta0phFHEQLZbj7lv0t4DAS5Iy3gnhzoFt4DYo9wHn5rFLa t6XuWVcFhy/qml43JEiTRO5NIW7YyqJE9pLEnihdX7RAcikxzoWNaVU/nx7Eh011/uO/ cr/kmJw2x+VLL+1dNk04Wr8ambqmxijwVuKjCagmoZWLNLFN8uzG+zlgHEarieMPq/wC /nUg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=xFom53/xfiAGgTrlrijS1PZFRbE74GFo0tpmjlnUaOU=; b=UM2WJyCIFpe6xkqB4zYJRSbXf2UeudHxbzXI/EV1TXA8FyDpcax/74DkxTUQN64hTo VKvmbAU7JK1FO0O2TDdjFymdk+o3y1ttLdNbcdT550odwqXC7CDN3kRk2C3IntqraQor yEbB/cFv/Qrha+fa10HBR/AmUxQC5sh2prPu/rQSs/Bl7CCC+NX2qe1zyo4jzVsv/0ZG YwmQgsMcpq1rarDJIaDHU3T0lsXB6w73/R6YUiWp2kHz516ET36MACCZjHYvu9B4rh+i KYFUQqmcltXluLLMazk/LRCBiTMTLIoREss+85utrwz0Asot2RWkg9F8JORGtUdym+eK WZhw== X-Gm-Message-State: AOUpUlHHL8y5rTrJ8DYtYNgj0pzlubPoEnUny0vBiD9GjLoE1fwfzkSp Y1vCfjveTCcoSP6b9vOf1ee2GSOigwI= X-Google-Smtp-Source: AA+uWPxfqQ9Lq65HH2tpE0iTISyFij6reo8WSpL1f8vgigTb2z3E/vCMd3AyDORLldcXpf2nhXLMHQ== X-Received: by 2002:a17:902:9f90:: with SMTP id g16-v6mr4223303plq.304.1533867294069; Thu, 09 Aug 2018 19:14:54 -0700 (PDT) Received: from ziepe.ca (S010614cc2056d97f.ed.shawcable.net. [174.3.196.123]) by smtp.gmail.com with ESMTPSA id b20-v6sm18562768pfc.178.2018.08.09.19.14.51 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Thu, 09 Aug 2018 19:14:52 -0700 (PDT) Received: from jgg by mlx with local (Exim 4.90_1) (envelope-from ) id 1fnwx1-0003gZ-EA; Thu, 09 Aug 2018 20:14:51 -0600 From: Jason Gunthorpe To: linux-rdma@vger.kernel.org, Leon Romanovsky , "Guy Levi(SW)" , Yishai Hadas , "Ruhl, Michael J" Cc: Jason Gunthorpe Subject: [PATCH v1 05/10] IB/uverbs: Remove the ib_uverbs_attr pointer from each attr Date: Thu, 9 Aug 2018 20:14:39 -0600 Message-Id: <20180810021444.14014-6-jgg@ziepe.ca> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180810021444.14014-1-jgg@ziepe.ca> References: <20180810021444.14014-1-jgg@ziepe.ca> Sender: linux-rdma-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-rdma@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Jason Gunthorpe Memory in the bundle is valuable, do not waste it holding an 8 byte pointer for the rare case of writing to a PTR_OUT. We can compute the pointer by storing a small 1 byte array offset and the base address of the uattr memory in the bundle private memory. This also means we can access the kernel's copy of the ib_uverbs_attr, so drop the copy of flags as well. Since the uattr base should be private bundle information this also de-inlines the already too big uverbs_copy_to inline and moves create_udata into uverbs_ioctl.c so they can see the private struct definition. Signed-off-by: Jason Gunthorpe Reviewed-by: Leon Romanovsky --- drivers/infiniband/core/uverbs_ioctl.c | 67 +++++++++++++++++++++- drivers/infiniband/core/uverbs_std_types.c | 32 ----------- include/rdma/uverbs_ioctl.h | 36 +++--------- 3 files changed, 72 insertions(+), 63 deletions(-) diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c index 74b0a40aaa36ea..c5aa64ee099efe 100644 --- a/drivers/infiniband/core/uverbs_ioctl.c +++ b/drivers/infiniband/core/uverbs_ioctl.c @@ -84,7 +84,6 @@ static int uverbs_process_attr(struct bundle_priv *pbundle, spec = &attr_spec_bucket->attrs[attr_id]; val_spec = spec; e = &elements[attr_id]; - e->uattr = uattr_ptr; switch (spec->type) { case UVERBS_ATTR_TYPE_ENUM_IN: @@ -124,8 +123,8 @@ static int uverbs_process_attr(struct bundle_priv *pbundle, uattr->attr_data.reserved) return -EINVAL; + e->ptr_attr.uattr_idx = uattr - pbundle->uattrs; e->ptr_attr.len = uattr->len; - e->ptr_attr.flags = uattr->flags; if (val_spec->alloc_and_copy && !uverbs_attr_ptr_is_inline(e)) { void *p; @@ -181,7 +180,7 @@ static int uverbs_process_attr(struct bundle_priv *pbundle, s64 id = o_attr->uobject->id; /* Copy the allocated id to the user-space */ - if (put_user(id, &e->uattr->data)) { + if (put_user(id, &uattr_ptr->data)) { uverbs_finalize_object(o_attr->uobject, UVERBS_ACCESS_NEW, false); @@ -562,3 +561,65 @@ int uverbs_get_flags32(u32 *to, const struct uverbs_attr_bundle *attrs_bundle, return 0; } EXPORT_SYMBOL(uverbs_get_flags32); + +/* + * This is for ease of conversion. The purpose is to convert all drivers to + * use uverbs_attr_bundle instead of ib_udata. Assume attr == 0 is input and + * attr == 1 is output. + */ +void create_udata(struct uverbs_attr_bundle *bundle, struct ib_udata *udata) +{ + struct bundle_priv *pbundle = + container_of(bundle, struct bundle_priv, bundle); + const struct uverbs_attr *uhw_in = + uverbs_attr_get(bundle, UVERBS_ATTR_UHW_IN); + const struct uverbs_attr *uhw_out = + uverbs_attr_get(bundle, UVERBS_ATTR_UHW_OUT); + + if (!IS_ERR(uhw_in)) { + udata->inlen = uhw_in->ptr_attr.len; + if (uverbs_attr_ptr_is_inline(uhw_in)) + udata->inbuf = + &pbundle->user_attrs[uhw_in->ptr_attr.uattr_idx] + .data; + else + udata->inbuf = u64_to_user_ptr(uhw_in->ptr_attr.data); + } else { + udata->inbuf = NULL; + udata->inlen = 0; + } + + if (!IS_ERR(uhw_out)) { + udata->outbuf = u64_to_user_ptr(uhw_out->ptr_attr.data); + udata->outlen = uhw_out->ptr_attr.len; + } else { + udata->outbuf = NULL; + udata->outlen = 0; + } +} + +int uverbs_copy_to(const struct uverbs_attr_bundle *bundle, size_t idx, + const void *from, size_t size) +{ + struct bundle_priv *pbundle = + container_of(bundle, struct bundle_priv, bundle); + const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx); + u16 flags; + size_t min_size; + + if (IS_ERR(attr)) + return PTR_ERR(attr); + + min_size = min_t(size_t, attr->ptr_attr.len, size); + if (copy_to_user(u64_to_user_ptr(attr->ptr_attr.data), from, min_size)) + return -EFAULT; + + flags = pbundle->uattrs[attr->ptr_attr.uattr_idx].flags | + UVERBS_ATTR_F_VALID_OUTPUT; + if (put_user(flags, + &pbundle->user_attrs[attr->ptr_attr.uattr_idx].flags)) + return -EFAULT; + + return 0; +} +EXPORT_SYMBOL(uverbs_copy_to); diff --git a/drivers/infiniband/core/uverbs_std_types.c b/drivers/infiniband/core/uverbs_std_types.c index 7f22b820a21ba0..203cc96ac6f508 100644 --- a/drivers/infiniband/core/uverbs_std_types.c +++ b/drivers/infiniband/core/uverbs_std_types.c @@ -217,38 +217,6 @@ int uverbs_destroy_def_handler(struct ib_uverbs_file *file, } EXPORT_SYMBOL(uverbs_destroy_def_handler); -void create_udata(struct uverbs_attr_bundle *ctx, struct ib_udata *udata) -{ - /* - * This is for ease of conversion. The purpose is to convert all drivers - * to use uverbs_attr_bundle instead of ib_udata. - * Assume attr == 0 is input and attr == 1 is output. - */ - const struct uverbs_attr *uhw_in = - uverbs_attr_get(ctx, UVERBS_ATTR_UHW_IN); - const struct uverbs_attr *uhw_out = - uverbs_attr_get(ctx, UVERBS_ATTR_UHW_OUT); - - if (!IS_ERR(uhw_in)) { - udata->inlen = uhw_in->ptr_attr.len; - if (uverbs_attr_ptr_is_inline(uhw_in)) - udata->inbuf = &uhw_in->uattr->data; - else - udata->inbuf = u64_to_user_ptr(uhw_in->ptr_attr.data); - } else { - udata->inbuf = NULL; - udata->inlen = 0; - } - - if (!IS_ERR(uhw_out)) { - udata->outbuf = u64_to_user_ptr(uhw_out->ptr_attr.data); - udata->outlen = uhw_out->ptr_attr.len; - } else { - udata->outbuf = NULL; - udata->outlen = 0; - } -} - DECLARE_UVERBS_NAMED_OBJECT( UVERBS_OBJECT_COMP_CHANNEL, UVERBS_TYPE_ALLOC_FD(sizeof(struct ib_uverbs_completion_event_file), diff --git a/include/rdma/uverbs_ioctl.h b/include/rdma/uverbs_ioctl.h index 3b497d9ed39592..ecf028446cdf53 100644 --- a/include/rdma/uverbs_ioctl.h +++ b/include/rdma/uverbs_ioctl.h @@ -461,8 +461,7 @@ struct uverbs_ptr_attr { u64 data; }; u16 len; - /* Combination of bits from enum UVERBS_ATTR_F_XXXX */ - u16 flags; + u16 uattr_idx; u8 enum_id; }; @@ -471,11 +470,6 @@ struct uverbs_obj_attr { }; struct uverbs_attr { - /* - * pointer to the user-space given attribute, in order to write the - * new uobject's id or update flags. - */ - struct ib_uverbs_attr __user *uattr; union { struct uverbs_ptr_attr ptr_attr; struct uverbs_obj_attr obj_attr; @@ -575,27 +569,6 @@ uverbs_attr_get_len(const struct uverbs_attr_bundle *attrs_bundle, u16 idx) return attr->ptr_attr.len; } -static inline int uverbs_copy_to(const struct uverbs_attr_bundle *attrs_bundle, - size_t idx, const void *from, size_t size) -{ - const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx); - u16 flags; - size_t min_size; - - if (IS_ERR(attr)) - return PTR_ERR(attr); - - min_size = min_t(size_t, attr->ptr_attr.len, size); - if (copy_to_user(u64_to_user_ptr(attr->ptr_attr.data), from, min_size)) - return -EFAULT; - - flags = attr->ptr_attr.flags | UVERBS_ATTR_F_VALID_OUTPUT; - if (put_user(flags, &attr->uattr->flags)) - return -EFAULT; - - return 0; -} - static inline bool uverbs_attr_ptr_is_inline(const struct uverbs_attr *attr) { return attr->ptr_attr.len <= sizeof(attr->ptr_attr.data); @@ -676,6 +649,8 @@ int uverbs_get_flags64(u64 *to, const struct uverbs_attr_bundle *attrs_bundle, size_t idx, u64 allowed_bits); int uverbs_get_flags32(u32 *to, const struct uverbs_attr_bundle *attrs_bundle, size_t idx, u64 allowed_bits); +int uverbs_copy_to(const struct uverbs_attr_bundle *attrs_bundle, size_t idx, + const void *from, size_t size); #else static inline int uverbs_get_flags64(u64 *to, const struct uverbs_attr_bundle *attrs_bundle, @@ -689,6 +664,11 @@ uverbs_get_flags32(u32 *to, const struct uverbs_attr_bundle *attrs_bundle, { return -EINVAL; } +static inline int uverbs_copy_to(const struct uverbs_attr_bundle *attrs_bundle, + size_t idx, const void *from, size_t size) +{ + return -EINVAL; +} #endif /* ================================================= From patchwork Fri Aug 10 02:14:40 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Gunthorpe X-Patchwork-Id: 10562187 X-Patchwork-Delegate: jgg@ziepe.ca Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7001F1057 for ; Fri, 10 Aug 2018 02:15:00 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 623532BBBA for ; Fri, 10 Aug 2018 02:15:00 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 568A42BBD7; Fri, 10 Aug 2018 02:15:00 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B79F12BBAF for ; Fri, 10 Aug 2018 02:14:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725198AbeHJEmg (ORCPT ); Fri, 10 Aug 2018 00:42:36 -0400 Received: from mail-pf1-f194.google.com ([209.85.210.194]:44482 "EHLO mail-pf1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727143AbeHJEmg (ORCPT ); Fri, 10 Aug 2018 00:42:36 -0400 Received: by mail-pf1-f194.google.com with SMTP id k21-v6so3742846pff.11 for ; Thu, 09 Aug 2018 19:14:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ziepe.ca; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=1cW+QbGnpJp4x6th2sj+CnM5URXVJOPmFY0wziUhEY4=; b=a/NMTnX9caKwzbkJJCXl8FXJ30vyHazUG1i/X5qlrdgFYQ3xQ4HeZHOJBLBed36tAl lDbc+6jadsQYQRdoNw6d9H4gjeWB5UF9nm0YLQ4neC823ImetIdqyYx5GspX/TJXo0/p hQM0LPUXfeUiELU9dPqonXhbzWOIUpYNP4T0X9bEOsiAYa+CKHYVofXuEhuc0CtVwPs1 PWVGxu1OoAG00B3ORxzXS16ktkWnMnRxv9Rk7a2UIdd7od5k9UTw2FsTP25QgwHGwCWr A3QY3GNvG86mVYlMVtDV9dTuy8nh9XAg2HCtA/D/UtWiyin7+QpPWUD9Q3EpxaVhDMeq xRHA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=1cW+QbGnpJp4x6th2sj+CnM5URXVJOPmFY0wziUhEY4=; b=uEm1xKzNJT6wYvF7FjTRTJxRPHQteNzCRLfekU55KVV6Of5PWQqv4GMCV+DEc9hk5g WUqdICvWyFl/4CP63K2xalWUSnmeTq9GJVulLP3SUvExwzHsHtWx1xPFc84imkOtXHGu GjMwO89kx3/+dy+7OKHn5ohuD9mYGYWU1sW9L+E+nbVkMgvpI64/Ta9sNsZVjscTjeGb jUou55sKDCbv2M9hLdiLbzBsq/hWhpmSS+0QcY697MOlZmQMDioqYAXx0pwR/gxg/iNo 1lQr7O5YonBB7l9zlzi2qk72JYKmWGSX0l1RPK3dRvhLTfIOpa2YIjPvbeuzih3taron g22w== X-Gm-Message-State: AOUpUlEw39LZb72f2RynIs0vcH7N2klyf11obHuIgi2By7HuFNnwQn8J 9mAEg2WXIYFIck98UnuRHGxdYIRG8q0= X-Google-Smtp-Source: AA+uWPzhT8BVgCG0fsKsGL7VRdKe20vWmj+kf9eyEQ6r50+EoypiuJIIWdU77HR27o+POBSQOoxq+w== X-Received: by 2002:a62:cd82:: with SMTP id o124-v6mr4864972pfg.206.1533867295728; Thu, 09 Aug 2018 19:14:55 -0700 (PDT) Received: from ziepe.ca (S010614cc2056d97f.ed.shawcable.net. [174.3.196.123]) by smtp.gmail.com with ESMTPSA id j1-v6sm15287943pfk.125.2018.08.09.19.14.51 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Thu, 09 Aug 2018 19:14:52 -0700 (PDT) Received: from jgg by mlx with local (Exim 4.90_1) (envelope-from ) id 1fnwx1-0003gf-FJ; Thu, 09 Aug 2018 20:14:51 -0600 From: Jason Gunthorpe To: linux-rdma@vger.kernel.org, Leon Romanovsky , "Guy Levi(SW)" , Yishai Hadas , "Ruhl, Michael J" Cc: Jason Gunthorpe Subject: [PATCH v1 06/10] IB/uverbs: Add a simple allocator to uverbs_attr_bundle Date: Thu, 9 Aug 2018 20:14:40 -0600 Message-Id: <20180810021444.14014-7-jgg@ziepe.ca> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180810021444.14014-1-jgg@ziepe.ca> References: <20180810021444.14014-1-jgg@ziepe.ca> Sender: linux-rdma-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-rdma@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Jason Gunthorpe This is similar in spirit to devm, it keeps track of any allocations linked to this method call and ensures they are all freed when the method exits. Further, if there is space in the internal/onstack buffer then the allocator will hand out that memory and avoid an expensive call to kalloc/kfree in the syscall path. Signed-off-by: Jason Gunthorpe Reviewed-by: Leon Romanovsky --- drivers/infiniband/core/uverbs_ioctl.c | 106 ++++++++++++++++++++----- include/rdma/uverbs_ioctl.h | 24 ++++++ 2 files changed, 110 insertions(+), 20 deletions(-) diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c index c5aa64ee099efe..820e7ff3066751 100644 --- a/drivers/infiniband/core/uverbs_ioctl.c +++ b/drivers/infiniband/core/uverbs_ioctl.c @@ -35,7 +35,18 @@ #include "rdma_core.h" #include "uverbs.h" +struct bundle_alloc_head { + struct bundle_alloc_head *next; + u8 data[]; +}; + struct bundle_priv { + /* Must be first */ + struct bundle_alloc_head alloc_head; + struct bundle_alloc_head *allocated_mem; + size_t internal_avail; + size_t internal_used; + struct ib_uverbs_attr __user *user_attrs; struct ib_uverbs_attr *uattrs; struct uverbs_obj_attr *destroy_attr; @@ -45,8 +56,53 @@ struct bundle_priv { * internal_buffer. */ struct uverbs_attr_bundle bundle; + u64 internal_buffer[32]; }; +/** + * uverbs_alloc() - Quickly allocate memory for use with a bundle + * @bundle: The bundle + * @size: Number of bytes to allocate + * @flags: Allocator flags + * + * The bundle allocator is intended for allocations that are connected with + * processing the system call related to the bundle. The allocated memory is + * always freed once the system call completes, and cannot be freed any other + * way. + * + * This tries to use a small pool of pre-allocated memory for performance. + */ +__malloc void *_uverbs_alloc(struct uverbs_attr_bundle *bundle, size_t size, + gfp_t flags) +{ + struct bundle_priv *pbundle = + container_of(bundle, struct bundle_priv, bundle); + size_t new_used; + void *res; + + if (check_add_overflow(size, pbundle->internal_used, &new_used)) + return ERR_PTR(-EINVAL); + + if (new_used > pbundle->internal_avail) { + struct bundle_alloc_head *buf; + + buf = kvmalloc(struct_size(buf, data, size), flags); + if (!buf) + return ERR_PTR(-ENOMEM); + buf->next = pbundle->allocated_mem; + pbundle->allocated_mem = buf; + return buf->data; + } + + res = (void *)pbundle->internal_buffer + pbundle->internal_used; + pbundle->internal_used = + ALIGN(new_used, sizeof(*pbundle->internal_buffer)); + if (flags & __GFP_ZERO) + memset(res, 0, size); + return res; +} +EXPORT_SYMBOL(_uverbs_alloc); + static bool uverbs_is_attr_cleared(const struct ib_uverbs_attr *uattr, u16 len) { @@ -129,17 +185,15 @@ static int uverbs_process_attr(struct bundle_priv *pbundle, if (val_spec->alloc_and_copy && !uverbs_attr_ptr_is_inline(e)) { void *p; - p = kvmalloc(uattr->len, GFP_KERNEL); - if (!p) - return -ENOMEM; + p = uverbs_alloc(&pbundle->bundle, uattr->len); + if (IS_ERR(p)) + return PTR_ERR(p); e->ptr_attr.ptr = p; if (copy_from_user(p, u64_to_user_ptr(uattr->data), - uattr->len)) { - kvfree(p); + uattr->len)) return -EFAULT; - } } else { e->ptr_attr.data = uattr->data; } @@ -234,10 +288,6 @@ static int uverbs_finalize_attrs(struct bundle_priv *pbundle, spec->u.obj.access, commit); if (!ret) ret = current_ret; - } else if (spec->type == UVERBS_ATTR_TYPE_PTR_IN && - spec->alloc_and_copy && - !uverbs_attr_ptr_is_inline(attr)) { - kvfree(attr->ptr_attr.ptr); } } } @@ -372,7 +422,15 @@ static int uverbs_handle_method(size_t num_uattrs, return ret ? ret : finalize_ret; } -#define UVERBS_OPTIMIZE_USING_STACK_SZ 256 +static void bundle_destroy(struct bundle_priv *pbundle) +{ + struct bundle_alloc_head *memblock; + + for (memblock = pbundle->allocated_mem; memblock; + memblock = memblock->next) + kvfree(memblock); +} + static long ib_uverbs_cmd_verbs(struct ib_device *ib_dev, struct ib_uverbs_file *file, struct ib_uverbs_ioctl_hdr *hdr, @@ -382,11 +440,11 @@ static long ib_uverbs_cmd_verbs(struct ib_device *ib_dev, const struct uverbs_method_spec *method_spec; long err = 0; unsigned int i; + struct bundle_priv onstack_pbundle; struct bundle_priv *ctx; struct uverbs_attr *curr_attr; unsigned long *curr_bitmap; size_t ctx_size; - uintptr_t data[UVERBS_OPTIMIZE_USING_STACK_SZ / sizeof(uintptr_t)]; if (hdr->driver_id != ib_dev->driver_id) return -EINVAL; @@ -399,7 +457,7 @@ static long ib_uverbs_cmd_verbs(struct ib_device *ib_dev, if (!method_spec) return -EPROTONOSUPPORT; - ctx_size = sizeof(*ctx) + + ctx_size = sizeof(*ctx) - sizeof(ctx->internal_buffer) + sizeof(struct uverbs_attr_bundle_hash) * method_spec->num_buckets + sizeof(*ctx->uattrs) * hdr->num_attrs + sizeof(*ctx->bundle.hash[0].attrs) * @@ -408,17 +466,26 @@ static long ib_uverbs_cmd_verbs(struct ib_device *ib_dev, (method_spec->num_child_attrs / BITS_PER_LONG + method_spec->num_buckets); - if (ctx_size <= UVERBS_OPTIMIZE_USING_STACK_SZ) - ctx = (void *)data; - if (!ctx) + if (ctx_size <= sizeof(onstack_pbundle)) { + ctx = &onstack_pbundle; + ctx->internal_avail = + sizeof(onstack_pbundle) - + offsetof(struct bundle_priv, internal_buffer); + ctx->allocated_mem = NULL; + } else { ctx = kmalloc(ctx_size, GFP_KERNEL); - if (!ctx) - return -ENOMEM; + if (!ctx) + return -ENOMEM; + ctx->internal_avail = 0; + ctx->alloc_head.next = NULL; + ctx->allocated_mem = &ctx->alloc_head; + } ctx->uattrs = (void *)(ctx + 1) + (sizeof(ctx->bundle.hash[0]) * method_spec->num_buckets); curr_attr = (void *)(ctx->uattrs + hdr->num_attrs); curr_bitmap = (void *)(curr_attr + method_spec->num_child_attrs); + ctx->internal_used = ALIGN(ctx_size, sizeof(*ctx->internal_buffer)); /* * We just fill the pointers and num_attrs here. The data itself will be @@ -462,8 +529,7 @@ static long ib_uverbs_cmd_verbs(struct ib_device *ib_dev, err = -EINVAL; } out: - if (ctx != (void *)data) - kfree(ctx); + bundle_destroy(ctx); return err; } diff --git a/include/rdma/uverbs_ioctl.h b/include/rdma/uverbs_ioctl.h index ecf028446cdf53..1dbf663f7f436a 100644 --- a/include/rdma/uverbs_ioctl.h +++ b/include/rdma/uverbs_ioctl.h @@ -651,6 +651,20 @@ int uverbs_get_flags32(u32 *to, const struct uverbs_attr_bundle *attrs_bundle, size_t idx, u64 allowed_bits); int uverbs_copy_to(const struct uverbs_attr_bundle *attrs_bundle, size_t idx, const void *from, size_t size); +__malloc void *_uverbs_alloc(struct uverbs_attr_bundle *bundle, size_t size, + gfp_t flags); + +static inline __malloc void *uverbs_alloc(struct uverbs_attr_bundle *bundle, + size_t size) +{ + return _uverbs_alloc(bundle, size, GFP_KERNEL); +} + +static inline __malloc void *uverbs_zalloc(struct uverbs_attr_bundle *bundle, + size_t size) +{ + return _uverbs_alloc(bundle, size, GFP_KERNEL | __GFP_ZERO); +} #else static inline int uverbs_get_flags64(u64 *to, const struct uverbs_attr_bundle *attrs_bundle, @@ -669,6 +683,16 @@ static inline int uverbs_copy_to(const struct uverbs_attr_bundle *attrs_bundle, { return -EINVAL; } +static inline __malloc void *uverbs_alloc(struct uverbs_attr_bundle *bundle, + size_t size) +{ + return ERR_PTR(-EINVAL); +} +static inline __malloc void *uverbs_zalloc(struct uverbs_attr_bundle *bundle, + size_t size) +{ + return ERR_PTR(-EINVAL); +} #endif /* ================================================= From patchwork Fri Aug 10 02:14:41 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Gunthorpe X-Patchwork-Id: 10562193 X-Patchwork-Delegate: jgg@ziepe.ca Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1250213BB for ; Fri, 10 Aug 2018 02:15:01 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 040F32BBA4 for ; Fri, 10 Aug 2018 02:15:01 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id ECF032BBD7; Fri, 10 Aug 2018 02:15:00 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C3CE82BBA4 for ; Fri, 10 Aug 2018 02:14:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727168AbeHJEmh (ORCPT ); Fri, 10 Aug 2018 00:42:37 -0400 Received: from mail-pl0-f42.google.com ([209.85.160.42]:45228 "EHLO mail-pl0-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727143AbeHJEmh (ORCPT ); Fri, 10 Aug 2018 00:42:37 -0400 Received: by mail-pl0-f42.google.com with SMTP id j8-v6so3351022pll.12 for ; Thu, 09 Aug 2018 19:14:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ziepe.ca; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=D5NMclI/YYCdUEi5/ekehboTQYcDa0rppQtaewSe9sM=; b=nvKgLXzuNxV4K245TN1SyuXQK4hdezX3AR4G6uTyFbjVFvWjnEgi2Nn4K3jMXsHByx DDvabqp1lfn7c7pY4J+3u16znI9rtnjxr6t0o61PhLdiXO2nmYOUt03hPft1HBAXgPuO qlpJpADHGx7nbGG4NrO+aEW5Pa7VuB6rPI5UwZPh4F+MkC32PXTazMIuzvyoTBUJNpDg sHCy17y9cGOsTtYp1X5OtVNKY6mNL6J4wQOyUTmuHOBTP3RXoUA2Lzmyr6vwxitCxPnh iNpR/4SQrXJgfJCJk1cJNmdc6ku3F3iMg+WdrKsri5lLZDk/THHZH6W5YF5e5kGoH9sj RHXQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=D5NMclI/YYCdUEi5/ekehboTQYcDa0rppQtaewSe9sM=; b=OK8l1BZU6ILpTXftvhCYX2VKXt43h+OylPzkNLoj3fXpTjvl9Tnh16BwPP4lrlLQ9n 5gu36YcLtdQ+aZkGqI+9+s7AvgkLcIRfECxjSvYLqtwPhebOmsGkAlglVWNIOxcagciz UrMp08QrDR5yBZIHgUEFl4gzepefOoXr0BIUp8sDKMIEyrtuMbEzfPU7+fneafAHMfCI qLGeXllaJam+YW5mzfjjoxRmiKcrtTRiQjluaeUSNi5tc/11mobU7pweuRhw8SR78xzy DuUHWUf8yZRPlf8Bg8E9d5eS9GfQj+ybJjnDeWYabyzJ4xhgo/BCmGJr8XiPyG5d0+O3 rS7w== X-Gm-Message-State: AOUpUlExuDMfmR4rcgiu+FLi9IW96lE3HTvIxIL/M0G7nOa86u8ZIPKN mcCe+rO9sX2kELLMmZYoFL/9TyfpxtY= X-Google-Smtp-Source: AA+uWPxZM3LV4Gyc05fXrHL87i6GMt0Gi3IPHyWkL/zkjJYI9BQG18ah2U0l5Ne9LrkbAL6nvTRzoA== X-Received: by 2002:a17:902:1121:: with SMTP id d30-v6mr4322008pla.247.1533867296416; Thu, 09 Aug 2018 19:14:56 -0700 (PDT) Received: from ziepe.ca (S010614cc2056d97f.ed.shawcable.net. [174.3.196.123]) by smtp.gmail.com with ESMTPSA id v23-v6sm9764796pfm.80.2018.08.09.19.14.52 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Thu, 09 Aug 2018 19:14:53 -0700 (PDT) Received: from jgg by mlx with local (Exim 4.90_1) (envelope-from ) id 1fnwx1-0003gl-HZ; Thu, 09 Aug 2018 20:14:51 -0600 From: Jason Gunthorpe To: linux-rdma@vger.kernel.org, Leon Romanovsky , "Guy Levi(SW)" , Yishai Hadas , "Ruhl, Michael J" Cc: Jason Gunthorpe Subject: [PATCH v1 07/10] IB/uverbs: Use uverbs_alloc for allocations Date: Thu, 9 Aug 2018 20:14:41 -0600 Message-Id: <20180810021444.14014-8-jgg@ziepe.ca> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180810021444.14014-1-jgg@ziepe.ca> References: <20180810021444.14014-1-jgg@ziepe.ca> Sender: linux-rdma-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-rdma@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Jason Gunthorpe Several handlers need temporary allocations for the life of the method, switch them to use the uverbs_alloc allocator. Signed-off-by: Jason Gunthorpe Reviewed-by: Leon Romanovsky --- .../core/uverbs_std_types_counters.c | 20 ++--- drivers/infiniband/hw/mlx5/devx.c | 83 +++++++------------ 2 files changed, 38 insertions(+), 65 deletions(-) diff --git a/drivers/infiniband/core/uverbs_std_types_counters.c b/drivers/infiniband/core/uverbs_std_types_counters.c index dfacc9e833995d..a0ffdcf9a51cd1 100644 --- a/drivers/infiniband/core/uverbs_std_types_counters.c +++ b/drivers/infiniband/core/uverbs_std_types_counters.c @@ -104,22 +104,18 @@ static int UVERBS_HANDLER(UVERBS_METHOD_COUNTERS_READ)( uattr = uverbs_attr_get(attrs, UVERBS_ATTR_READ_COUNTERS_BUFF); read_attr.ncounters = uattr->ptr_attr.len / sizeof(u64); - read_attr.counters_buff = kcalloc(read_attr.ncounters, - sizeof(u64), GFP_KERNEL); - if (!read_attr.counters_buff) - return -ENOMEM; + read_attr.counters_buff = uverbs_zalloc( + attrs, array_size(read_attr.ncounters, sizeof(u64))); + if (IS_ERR(read_attr.counters_buff)) + return PTR_ERR(read_attr.counters_buff); ret = counters->device->read_counters(counters, &read_attr, attrs); if (ret) - goto err_read; - - ret = uverbs_copy_to(attrs, UVERBS_ATTR_READ_COUNTERS_BUFF, - read_attr.counters_buff, - read_attr.ncounters * sizeof(u64)); + return ret; -err_read: - kfree(read_attr.counters_buff); - return ret; + return uverbs_copy_to(attrs, UVERBS_ATTR_READ_COUNTERS_BUFF, + read_attr.counters_buff, + read_attr.ncounters * sizeof(u64)); } DECLARE_UVERBS_NAMED_METHOD( diff --git a/drivers/infiniband/hw/mlx5/devx.c b/drivers/infiniband/hw/mlx5/devx.c index 29c6883723902c..ac116d63e4661a 100644 --- a/drivers/infiniband/hw/mlx5/devx.c +++ b/drivers/infiniband/hw/mlx5/devx.c @@ -511,22 +511,19 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OTHER)( if (!devx_is_general_cmd(cmd_in)) return -EINVAL; - cmd_out = kvzalloc(cmd_out_len, GFP_KERNEL); - if (!cmd_out) - return -ENOMEM; + cmd_out = uverbs_zalloc(attrs, cmd_out_len); + if (IS_ERR(cmd_out)) + return PTR_ERR(cmd_out); MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, c->devx_uid); err = mlx5_cmd_exec(dev->mdev, cmd_in, uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OTHER_CMD_IN), cmd_out, cmd_out_len); if (err) - goto other_cmd_free; - - err = uverbs_copy_to(attrs, MLX5_IB_ATTR_DEVX_OTHER_CMD_OUT, cmd_out, cmd_out_len); + return err; -other_cmd_free: - kvfree(cmd_out); - return err; + return uverbs_copy_to(attrs, MLX5_IB_ATTR_DEVX_OTHER_CMD_OUT, cmd_out, + cmd_out_len); } static void devx_obj_build_destroy_cmd(void *in, void *out, void *din, @@ -735,22 +732,20 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)( if (!devx_is_obj_create_cmd(cmd_in)) return -EINVAL; + cmd_out = uverbs_zalloc(attrs, cmd_out_len); + if (IS_ERR(cmd_out)) + return PTR_ERR(cmd_out); + obj = kzalloc(sizeof(struct devx_obj), GFP_KERNEL); if (!obj) return -ENOMEM; - cmd_out = kvzalloc(cmd_out_len, GFP_KERNEL); - if (!cmd_out) { - err = -ENOMEM; - goto obj_free; - } - MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, c->devx_uid); err = mlx5_cmd_exec(dev->mdev, cmd_in, uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OBJ_CREATE_CMD_IN), cmd_out, cmd_out_len); if (err) - goto cmd_free; + goto obj_free; uobj->object = obj; obj->mdev = dev->mdev; @@ -759,13 +754,10 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)( err = uverbs_copy_to(attrs, MLX5_IB_ATTR_DEVX_OBJ_CREATE_CMD_OUT, cmd_out, cmd_out_len); if (err) - goto cmd_free; + goto obj_free; - kvfree(cmd_out); return 0; -cmd_free: - kvfree(cmd_out); obj_free: kfree(obj); return err; @@ -793,23 +785,19 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_MODIFY)( if (!devx_is_valid_obj_id(obj, cmd_in)) return -EINVAL; - cmd_out = kvzalloc(cmd_out_len, GFP_KERNEL); - if (!cmd_out) - return -ENOMEM; + cmd_out = uverbs_zalloc(attrs, cmd_out_len); + if (IS_ERR(cmd_out)) + return PTR_ERR(cmd_out); MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, c->devx_uid); err = mlx5_cmd_exec(obj->mdev, cmd_in, uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_IN), cmd_out, cmd_out_len); if (err) - goto other_cmd_free; - - err = uverbs_copy_to(attrs, MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_OUT, - cmd_out, cmd_out_len); + return err; -other_cmd_free: - kvfree(cmd_out); - return err; + return uverbs_copy_to(attrs, MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_OUT, + cmd_out, cmd_out_len); } static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_QUERY)( @@ -834,22 +822,19 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_QUERY)( if (!devx_is_valid_obj_id(obj, cmd_in)) return -EINVAL; - cmd_out = kvzalloc(cmd_out_len, GFP_KERNEL); - if (!cmd_out) - return -ENOMEM; + cmd_out = uverbs_zalloc(attrs, cmd_out_len); + if (IS_ERR(cmd_out)) + return PTR_ERR(cmd_out); MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, c->devx_uid); err = mlx5_cmd_exec(obj->mdev, cmd_in, uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_IN), cmd_out, cmd_out_len); if (err) - goto other_cmd_free; - - err = uverbs_copy_to(attrs, MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_OUT, cmd_out, cmd_out_len); + return err; -other_cmd_free: - kvfree(cmd_out); - return err; + return uverbs_copy_to(attrs, MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_OUT, + cmd_out, cmd_out_len); } static int devx_umem_get(struct mlx5_ib_dev *dev, struct ib_ucontext *ucontext, @@ -896,18 +881,14 @@ static int devx_umem_get(struct mlx5_ib_dev *dev, struct ib_ucontext *ucontext, return 0; } -static int devx_umem_reg_cmd_alloc(struct devx_umem *obj, +static int devx_umem_reg_cmd_alloc(struct uverbs_attr_bundle *attrs, + struct devx_umem *obj, struct devx_umem_reg_cmd *cmd) { cmd->inlen = MLX5_ST_SZ_BYTES(create_umem_in) + (MLX5_ST_SZ_BYTES(mtt) * obj->ncont); - cmd->in = kvzalloc(cmd->inlen, GFP_KERNEL); - return cmd->in ? 0 : -ENOMEM; -} - -static void devx_umem_reg_cmd_free(struct devx_umem_reg_cmd *cmd) -{ - kvfree(cmd->in); + cmd->in = uverbs_zalloc(attrs, cmd->inlen); + return PTR_ERR_OR_ZERO(cmd->in); } static void devx_umem_reg_cmd_build(struct mlx5_ib_dev *dev, @@ -954,7 +935,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_UMEM_REG)( if (err) goto err_obj_free; - err = devx_umem_reg_cmd_alloc(obj, &cmd); + err = devx_umem_reg_cmd_alloc(attrs, obj, &cmd); if (err) goto err_umem_release; @@ -964,7 +945,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_UMEM_REG)( err = mlx5_cmd_exec(dev->mdev, cmd.in, cmd.inlen, cmd.out, sizeof(cmd.out)); if (err) - goto err_umem_reg_cmd_free; + goto err_umem_release; obj->mdev = dev->mdev; uobj->object = obj; @@ -973,14 +954,10 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_UMEM_REG)( if (err) goto err_umem_destroy; - devx_umem_reg_cmd_free(&cmd); - return 0; err_umem_destroy: mlx5_cmd_exec(obj->mdev, obj->dinbox, obj->dinlen, cmd.out, sizeof(cmd.out)); -err_umem_reg_cmd_free: - devx_umem_reg_cmd_free(&cmd); err_umem_release: ib_umem_release(obj->umem); err_obj_free: From patchwork Fri Aug 10 02:14:42 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Gunthorpe X-Patchwork-Id: 10562195 X-Patchwork-Delegate: jgg@ziepe.ca Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C098390E3 for ; Fri, 10 Aug 2018 02:15:01 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AF7002BB93 for ; Fri, 10 Aug 2018 02:15:01 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A28EF2BBA4; Fri, 10 Aug 2018 02:15:01 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D1BBE2BBB5 for ; Fri, 10 Aug 2018 02:14:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727123AbeHJEmi (ORCPT ); Fri, 10 Aug 2018 00:42:38 -0400 Received: from mail-pf1-f195.google.com ([209.85.210.195]:40192 "EHLO mail-pf1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727109AbeHJEmi (ORCPT ); Fri, 10 Aug 2018 00:42:38 -0400 Received: by mail-pf1-f195.google.com with SMTP id e13-v6so3748747pff.7 for ; Thu, 09 Aug 2018 19:14:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ziepe.ca; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=HG00qNi3gvBD++JbO8bYV328VIblcyIsWN5h1vlTG6M=; b=XydVDW0MOI6yGg/5GW+YP1E6F/8jSjSx4BR4ddD37jrqNc/sPfwYQbCHwihCSTB1yK gas6dmQNXyc+hWYUkzGFSfATc5APN/VDeB74wMiYULKXAeUmVisUAWBZDhMySHuPsOCj 6z4+Dd51dTd7zJXjN6BYFWODvwp0UC/pc2A2ARFJe6EMGqVqqOjLGBuQe4+t6pc4PIN+ 5EeXxTrFKfYCWsqgD7G5AA6SZm9ozu6xslZ7ZwbY0UKbYSf5IOekumDmUqPIc1i7Ymun qRyTnKE7UWe7tEfSS/vKCTZ3Eztv3s3En/t1ZD21QkftDNZi3qg93CHyPeTRLrc38DID J60A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=HG00qNi3gvBD++JbO8bYV328VIblcyIsWN5h1vlTG6M=; b=PKDhnGUTYkc4swKb8eS8EiFsT3fra503eUeav8jyCHSOuKCTSDsa7IFiHpyNGXSel3 5HTqneZKhmqRx0ymXaDX4/TAGG1XcHQU80JIOacbgSU8z49OG5dyvnYsks+FQekcblhk eWQ0XLH1qunb3SFz6Ai6a/EYe0dyNEhpKb3v0oT7JcOAJaYHNUY1y434QVdEZfMcZMYS Yvs6FCmaJbp+q93jCo4ABBZGYUXADc6qPO2pxCgBdgD6+Tdhec4hS99i38lmZQzS2AKX LiwQXbzQ7UNMAMj76FYzpi6sJQRJw0HXQoYH5iF6typyiwec+/JAlikS+CvOJJ095xdV 7V6w== X-Gm-Message-State: AOUpUlGhLnEXdLZvrkccOSLCzlYkE+i7P7C1U37tJVQclqTdOi0GjAGS g+iPUfg+wcFTM81SOeGntpM+wjDuQNQ= X-Google-Smtp-Source: AA+uWPxrHSY5miqlJohemQYtWcZCT+SZvDpO0qWfCuc+lZXAAmwTD6mCnko1zR/JgSUHwTa0rHtOpQ== X-Received: by 2002:a63:4106:: with SMTP id o6-v6mr4473284pga.453.1533867296928; Thu, 09 Aug 2018 19:14:56 -0700 (PDT) Received: from ziepe.ca (S010614cc2056d97f.ed.shawcable.net. [174.3.196.123]) by smtp.gmail.com with ESMTPSA id m15-v6sm21538721pfj.171.2018.08.09.19.14.52 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Thu, 09 Aug 2018 19:14:55 -0700 (PDT) Received: from jgg by mlx with local (Exim 4.90_1) (envelope-from ) id 1fnwx1-0003gr-JS; Thu, 09 Aug 2018 20:14:51 -0600 From: Jason Gunthorpe To: linux-rdma@vger.kernel.org, Leon Romanovsky , "Guy Levi(SW)" , Yishai Hadas , "Ruhl, Michael J" Cc: Jason Gunthorpe Subject: [PATCH v1 08/10] IB/uverbs: Use uverbs_api to unmarshal ioctl commands Date: Thu, 9 Aug 2018 20:14:42 -0600 Message-Id: <20180810021444.14014-9-jgg@ziepe.ca> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180810021444.14014-1-jgg@ziepe.ca> References: <20180810021444.14014-1-jgg@ziepe.ca> Sender: linux-rdma-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-rdma@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Jason Gunthorpe Convert the ioctl method syscall path to use the uverbs_api data structures. The new uapi structure includes all the same information, just in a different and more optimal way. - Use attr_bkey instead of 2 level radix trees for everything related to attributes. This includes the attribute storage, presence, and detection of missing mandatory attributes. - Avoid iterating over all attribute storage at finish, instead use find_first_bit with the attr_bkey to locate only those attrs that need cleanup. - Organize things to always run, and always rely on, cleanup. This avoids a bunch of tricky error unwind cases. - Locate the method using the radix tree, and locate the attributes using a very efficient incremental radix tree lookup - Use the precomputed destroy_bkey to handle uobject destruction - Use the precomputed allocation sizes and precomputed 'need_stack' to avoid maths in the fast path. This is optimal if userspace does not pass (many) unsupported attributes. Overall this results in much better codegen for the attribute accessors, everything is now stored in bitmaps or linear arrays indexed by attr_bkey. The compiler can compute attr_bkey values at compile time for all method attributes, meaning things like uverbs_attr_is_valid() now compile into single instruction bit tests. Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/rdma_core.h | 4 + drivers/infiniband/core/uverbs_ioctl.c | 482 +++++++++++-------------- drivers/infiniband/core/uverbs_uapi.c | 3 + include/rdma/uverbs_ioctl.h | 36 +- 4 files changed, 224 insertions(+), 301 deletions(-) diff --git a/drivers/infiniband/core/rdma_core.h b/drivers/infiniband/core/rdma_core.h index d89569d87b1cff..aca279bfef0831 100644 --- a/drivers/infiniband/core/rdma_core.h +++ b/drivers/infiniband/core/rdma_core.h @@ -133,6 +133,8 @@ struct uverbs_api_ioctl_method { int (__rcu *handler)(struct ib_uverbs_file *ufile, struct uverbs_attr_bundle *ctx); DECLARE_BITMAP(attr_mandatory, UVERBS_API_ATTR_BKEY_LEN); + u16 bundle_size; + u8 use_stack:1; u8 driver_method:1; u8 key_bitmap_len; u8 destroy_bkey; @@ -162,5 +164,7 @@ struct uverbs_api *uverbs_alloc_api( void uverbs_disassociate_api_pre(struct ib_uverbs_device *uverbs_dev); void uverbs_disassociate_api(struct uverbs_api *uapi); void uverbs_destroy_api(struct uverbs_api *uapi); +void uapi_compute_bundle_size(struct uverbs_api_ioctl_method *method_elm, + unsigned int num_attrs); #endif /* RDMA_CORE_H */ diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c index 820e7ff3066751..e98dad4ca89826 100644 --- a/drivers/infiniband/core/uverbs_ioctl.c +++ b/drivers/infiniband/core/uverbs_ioctl.c @@ -47,9 +47,16 @@ struct bundle_priv { size_t internal_avail; size_t internal_used; + struct radix_tree_root *radix; + const struct uverbs_api_ioctl_method *method_elm; + void __rcu **radix_slots; + unsigned long radix_slots_len; + u32 method_key; + struct ib_uverbs_attr __user *user_attrs; struct ib_uverbs_attr *uattrs; - struct uverbs_obj_attr *destroy_attr; + + DECLARE_BITMAP(uobj_finalize, UVERBS_API_ATTR_BKEY_LEN); /* * Must be last. bundle ends in a flex array which overlaps @@ -59,6 +66,28 @@ struct bundle_priv { u64 internal_buffer[32]; }; +/* + * Each method has an absolute minimum amount of memory it needs to allocate, + * precompute that amount and determine if the onstack memory can be used or + * if allocation is need. + */ +void uapi_compute_bundle_size(struct uverbs_api_ioctl_method *method_elm, + unsigned int num_attrs) +{ + struct bundle_priv *pbundle; + size_t bundle_size = + offsetof(struct bundle_priv, internal_buffer) + + sizeof(*pbundle->bundle.attrs) * method_elm->key_bitmap_len + + sizeof(*pbundle->uattrs) * num_attrs; + + method_elm->use_stack = bundle_size <= sizeof(*pbundle); + method_elm->bundle_size = + ALIGN(bundle_size + 256, sizeof(*pbundle->internal_buffer)); + + /* Do not want order-2 allocations for this. */ + WARN_ON_ONCE(method_elm->bundle_size > PAGE_SIZE); +} + /** * uverbs_alloc() - Quickly allocate memory for use with a bundle * @bundle: The bundle @@ -81,7 +110,7 @@ __malloc void *_uverbs_alloc(struct uverbs_attr_bundle *bundle, size_t size, void *res; if (check_add_overflow(size, pbundle->internal_used, &new_used)) - return ERR_PTR(-EINVAL); + return ERR_PTR(-EOVERFLOW); if (new_used > pbundle->internal_avail) { struct bundle_alloc_head *buf; @@ -115,31 +144,13 @@ static bool uverbs_is_attr_cleared(const struct ib_uverbs_attr *uattr, } static int uverbs_process_attr(struct bundle_priv *pbundle, - const struct ib_uverbs_attr *uattr, - u16 attr_id, - const struct uverbs_attr_spec_hash *attr_spec_bucket, - struct uverbs_attr_bundle_hash *attr_bundle_h, - struct ib_uverbs_attr __user *uattr_ptr) + const struct uverbs_api_attr *attr_uapi, + struct ib_uverbs_attr *uattr, u32 attr_bkey) { - const struct uverbs_attr_spec *spec; - const struct uverbs_attr_spec *val_spec; - struct uverbs_attr *e; + const struct uverbs_attr_spec *spec = &attr_uapi->spec; + struct uverbs_attr *e = &pbundle->bundle.attrs[attr_bkey]; + const struct uverbs_attr_spec *val_spec = spec; struct uverbs_obj_attr *o_attr; - struct uverbs_attr *elements = attr_bundle_h->attrs; - - if (attr_id >= attr_spec_bucket->num_attrs) { - if (uattr->flags & UVERBS_ATTR_F_MANDATORY) - return -EINVAL; - else - return 0; - } - - if (test_bit(attr_id, attr_bundle_h->valid_bitmap)) - return -EINVAL; - - spec = &attr_spec_bucket->attrs[attr_id]; - val_spec = spec; - e = &elements[attr_id]; switch (spec->type) { case UVERBS_ATTR_TYPE_ENUM_IN: @@ -208,12 +219,7 @@ static int uverbs_process_attr(struct bundle_priv *pbundle, return -EINVAL; o_attr = &e->obj_attr; - - /* specs are allowed to have only one destroy attribute */ - WARN_ON(spec->u.obj.access == UVERBS_ACCESS_DESTROY && - pbundle->destroy_attr); - if (spec->u.obj.access == UVERBS_ACCESS_DESTROY) - pbundle->destroy_attr = o_attr; + o_attr->attr_elm = attr_uapi; /* * The type of uattr->data is u64 for UVERBS_ATTR_TYPE_IDR and @@ -226,20 +232,17 @@ static int uverbs_process_attr(struct bundle_priv *pbundle, pbundle->bundle.ufile, spec->u.obj.access, uattr->data_s64); - if (IS_ERR(o_attr->uobject)) return PTR_ERR(o_attr->uobject); + __set_bit(attr_bkey, pbundle->uobj_finalize); if (spec->u.obj.access == UVERBS_ACCESS_NEW) { + unsigned int uattr_idx = uattr - pbundle->uattrs; s64 id = o_attr->uobject->id; /* Copy the allocated id to the user-space */ - if (put_user(id, &uattr_ptr->data)) { - uverbs_finalize_object(o_attr->uobject, - UVERBS_ACCESS_NEW, - false); + if (put_user(id, &pbundle->user_attrs[uattr_idx].data)) return -EFAULT; - } } break; @@ -247,290 +250,225 @@ static int uverbs_process_attr(struct bundle_priv *pbundle, return -EOPNOTSUPP; } - set_bit(attr_id, attr_bundle_h->valid_bitmap); return 0; } -static int uverbs_finalize_attrs(struct bundle_priv *pbundle, - struct uverbs_attr_spec_hash *const *spec_hash, - size_t num, bool commit) +/* + * We search the radix tree with the method prefix and now we want to fast + * search the suffix bits to get a particular attribute pointer. It is not + * totally clear to me if this breaks the radix tree encasulation or not, but + * it uses the iter data to determine if the method iter points at the same + * chunk that will store the attribute, if so it just derefs it directly. By + * construction in most kernel configs the method and attrs will all fit in a + * single radix chunk, so in most cases this will have no search. Other cases + * this falls back to a full search. + */ +static void __rcu **uapi_get_attr_for_method(struct bundle_priv *pbundle, + u32 attr_key) { - struct uverbs_attr_bundle *attrs_bundle = &pbundle->bundle; - unsigned int i; - int ret = 0; - - for (i = 0; i < num; i++) { - struct uverbs_attr_bundle_hash *curr_bundle = - &attrs_bundle->hash[i]; - const struct uverbs_attr_spec_hash *curr_spec_bucket = - spec_hash[i]; - unsigned int j; - - if (!curr_spec_bucket) - continue; - - for (j = 0; j < curr_bundle->num_attrs; j++) { - struct uverbs_attr *attr; - const struct uverbs_attr_spec *spec; - - if (!uverbs_attr_is_valid_in_hash(curr_bundle, j)) - continue; - - attr = &curr_bundle->attrs[j]; - spec = &curr_spec_bucket->attrs[j]; + void __rcu **slot; - if (spec->type == UVERBS_ATTR_TYPE_IDR || - spec->type == UVERBS_ATTR_TYPE_FD) { - int current_ret; + if (likely(attr_key < pbundle->radix_slots_len)) { + void *entry; - current_ret = uverbs_finalize_object( - attr->obj_attr.uobject, - spec->u.obj.access, commit); - if (!ret) - ret = current_ret; - } - } + slot = pbundle->radix_slots + attr_key; + entry = rcu_dereference_raw(*slot); + if (likely(!radix_tree_is_internal_node(entry) && entry)) + return slot; } - return ret; + + return radix_tree_lookup_slot(pbundle->radix, + pbundle->method_key | attr_key); } -static int uverbs_uattrs_process(size_t num_uattrs, - const struct uverbs_method_spec *method, - struct bundle_priv *pbundle) +static int uverbs_set_attr(struct bundle_priv *pbundle, + struct ib_uverbs_attr *uattr) { - struct uverbs_attr_bundle *attr_bundle = &pbundle->bundle; - struct ib_uverbs_attr __user *uattr_ptr = pbundle->user_attrs; - size_t i; - int ret = 0; - int num_given_buckets = 0; - - for (i = 0; i < num_uattrs; i++) { - const struct ib_uverbs_attr *uattr = &pbundle->uattrs[i]; - u16 attr_id = uattr->attr_id; - struct uverbs_attr_spec_hash *attr_spec_bucket; - - ret = uverbs_ns_idx(&attr_id, method->num_buckets); - if (ret < 0 || !method->attr_buckets[ret]) { - if (uattr->flags & UVERBS_ATTR_F_MANDATORY) { - uverbs_finalize_attrs(pbundle, - method->attr_buckets, - num_given_buckets, - false); - return ret; - } - continue; - } + u32 attr_key = uapi_key_attr(uattr->attr_id); + u32 attr_bkey = uapi_bkey_attr(attr_key); + const struct uverbs_api_attr *attr; + void __rcu **slot; + int ret; + slot = uapi_get_attr_for_method(pbundle, attr_key); + if (!slot) { /* - * ret is the found ns, so increase num_given_buckets if - * necessary. + * Kernel does not support the attribute but user-space says it + * is mandatory */ - if (ret >= num_given_buckets) - num_given_buckets = ret + 1; - - attr_spec_bucket = method->attr_buckets[ret]; - ret = uverbs_process_attr(pbundle, - uattr, attr_id, - attr_spec_bucket, - &attr_bundle->hash[ret], - uattr_ptr++); - if (ret) { - uverbs_finalize_attrs(pbundle, - method->attr_buckets, - num_given_buckets, - false); - return ret; - } + if (uattr->flags & UVERBS_ATTR_F_MANDATORY) + return -EPROTONOSUPPORT; + return 0; } + attr = srcu_dereference( + *slot, &pbundle->bundle.ufile->device->disassociate_srcu); - return num_given_buckets; -} - -static int uverbs_validate_kernel_mandatory(const struct uverbs_method_spec *method_spec, - struct bundle_priv *pbundle) -{ - struct uverbs_attr_bundle *attr_bundle = &pbundle->bundle; - unsigned int i; - - for (i = 0; i < attr_bundle->num_buckets; i++) { - struct uverbs_attr_spec_hash *attr_spec_bucket = - method_spec->attr_buckets[i]; - - if (!attr_spec_bucket) - continue; - - if (!bitmap_subset(attr_spec_bucket->mandatory_attrs_bitmask, - attr_bundle->hash[i].valid_bitmap, - attr_spec_bucket->num_attrs)) - return -EINVAL; - } + /* Reject duplicate attributes from user-space */ + if (test_bit(attr_bkey, pbundle->bundle.attr_present)) + return -EINVAL; - for (; i < method_spec->num_buckets; i++) { - struct uverbs_attr_spec_hash *attr_spec_bucket = - method_spec->attr_buckets[i]; + ret = uverbs_process_attr(pbundle, attr, uattr, attr_bkey); + if (ret) + return ret; - if (!bitmap_empty(attr_spec_bucket->mandatory_attrs_bitmask, - attr_spec_bucket->num_attrs)) - return -EINVAL; - } + __set_bit(attr_bkey, pbundle->bundle.attr_present); return 0; } -static int uverbs_handle_method(size_t num_uattrs, - const struct uverbs_method_spec *method_spec, - struct bundle_priv *pbundle) +static int ib_uverbs_run_method(struct bundle_priv *pbundle, + unsigned int num_attrs) { - struct uverbs_attr_bundle *attr_bundle = &pbundle->bundle; + int (*handler)(struct ib_uverbs_file *ufile, + struct uverbs_attr_bundle *ctx); + size_t uattrs_size = array_size(sizeof(*pbundle->uattrs), num_attrs); + unsigned int destroy_bkey = pbundle->method_elm->destroy_bkey; + unsigned int i; int ret; - int finalize_ret; - int num_given_buckets; - num_given_buckets = - uverbs_uattrs_process(num_uattrs, method_spec, pbundle); - if (num_given_buckets <= 0) + /* See uverbs_disassociate_api() */ + handler = srcu_dereference( + pbundle->method_elm->handler, + &pbundle->bundle.ufile->device->disassociate_srcu); + if (!handler) + return -EIO; + + pbundle->uattrs = uverbs_alloc(&pbundle->bundle, uattrs_size); + if (IS_ERR(pbundle->uattrs)) + return PTR_ERR(pbundle->uattrs); + if (copy_from_user(pbundle->uattrs, pbundle->user_attrs, uattrs_size)) + return -EFAULT; + + for (i = 0; i != num_attrs; i++) { + ret = uverbs_set_attr(pbundle, &pbundle->uattrs[i]); + if (unlikely(ret)) + return ret; + } + + /* User space did not provide all the mandatory attributes */ + if (unlikely(!bitmap_subset(pbundle->method_elm->attr_mandatory, + pbundle->bundle.attr_present, + pbundle->method_elm->key_bitmap_len))) return -EINVAL; - attr_bundle->num_buckets = num_given_buckets; - ret = uverbs_validate_kernel_mandatory(method_spec, pbundle); - if (ret) - goto cleanup; + if (destroy_bkey != UVERBS_API_ATTR_BKEY_LEN) { + struct uverbs_obj_attr *destroy_attr = + &pbundle->bundle.attrs[destroy_bkey].obj_attr; - /* - * We destroy the HW object before invoking the handler, handlers do - * not get to manipulate the HW objects. - */ - if (pbundle->destroy_attr) { - ret = uobj_destroy(pbundle->destroy_attr->uobject); + ret = uobj_destroy(destroy_attr->uobject); if (ret) - goto cleanup; - } - - ret = method_spec->handler(pbundle->bundle.ufile, attr_bundle); + return ret; + __clear_bit(destroy_bkey, pbundle->uobj_finalize); - if (pbundle->destroy_attr) { - uobj_put_destroy(pbundle->destroy_attr->uobject); - pbundle->destroy_attr->uobject = NULL; + ret = handler(pbundle->bundle.ufile, &pbundle->bundle); + uobj_put_destroy(destroy_attr->uobject); + } else { + ret = handler(pbundle->bundle.ufile, &pbundle->bundle); } -cleanup: - finalize_ret = uverbs_finalize_attrs(pbundle, - method_spec->attr_buckets, - attr_bundle->num_buckets, - !ret); + /* + * EPROTONOSUPPORT is ONLY to be returned if the ioctl framework can + * not invoke the method because the request is not supported. No + * other cases should return this code. + */ + if (WARN_ON_ONCE(ret == -EPROTONOSUPPORT)) + return -EINVAL; - return ret ? ret : finalize_ret; + return ret; } -static void bundle_destroy(struct bundle_priv *pbundle) +static int bundle_destroy(struct bundle_priv *pbundle, bool commit) { + unsigned int key_bitmap_len = pbundle->method_elm->key_bitmap_len; struct bundle_alloc_head *memblock; - - for (memblock = pbundle->allocated_mem; memblock; - memblock = memblock->next) - kvfree(memblock); -} - -static long ib_uverbs_cmd_verbs(struct ib_device *ib_dev, - struct ib_uverbs_file *file, - struct ib_uverbs_ioctl_hdr *hdr, - struct ib_uverbs_attr __user *user_attrs) -{ - const struct uverbs_object_spec *object_spec; - const struct uverbs_method_spec *method_spec; - long err = 0; unsigned int i; - struct bundle_priv onstack_pbundle; - struct bundle_priv *ctx; - struct uverbs_attr *curr_attr; - unsigned long *curr_bitmap; - size_t ctx_size; - - if (hdr->driver_id != ib_dev->driver_id) - return -EINVAL; + int ret = 0; - object_spec = uverbs_get_object(file, hdr->object_id); - if (!object_spec) - return -EPROTONOSUPPORT; + i = -1; + while ((i = find_next_bit(pbundle->uobj_finalize, key_bitmap_len, + i + 1)) < key_bitmap_len) { + struct uverbs_attr *attr = &pbundle->bundle.attrs[i]; + int current_ret; + + current_ret = uverbs_finalize_object( + attr->obj_attr.uobject, + attr->obj_attr.attr_elm->spec.u.obj.access, commit); + if (!ret) + ret = current_ret; + } - method_spec = uverbs_get_method(object_spec, hdr->method_id); - if (!method_spec) - return -EPROTONOSUPPORT; + for (memblock = pbundle->allocated_mem; memblock;) { + struct bundle_alloc_head *tmp = memblock; - ctx_size = sizeof(*ctx) - sizeof(ctx->internal_buffer) + - sizeof(struct uverbs_attr_bundle_hash) * method_spec->num_buckets + - sizeof(*ctx->uattrs) * hdr->num_attrs + - sizeof(*ctx->bundle.hash[0].attrs) * - method_spec->num_child_attrs + - sizeof(*ctx->bundle.hash[0].valid_bitmap) * - (method_spec->num_child_attrs / BITS_PER_LONG + - method_spec->num_buckets); - - if (ctx_size <= sizeof(onstack_pbundle)) { - ctx = &onstack_pbundle; - ctx->internal_avail = - sizeof(onstack_pbundle) - - offsetof(struct bundle_priv, internal_buffer); - ctx->allocated_mem = NULL; - } else { - ctx = kmalloc(ctx_size, GFP_KERNEL); - if (!ctx) - return -ENOMEM; - ctx->internal_avail = 0; - ctx->alloc_head.next = NULL; - ctx->allocated_mem = &ctx->alloc_head; + memblock = memblock->next; + kvfree(tmp); } - ctx->uattrs = (void *)(ctx + 1) + - (sizeof(ctx->bundle.hash[0]) * method_spec->num_buckets); - curr_attr = (void *)(ctx->uattrs + hdr->num_attrs); - curr_bitmap = (void *)(curr_attr + method_spec->num_child_attrs); - ctx->internal_used = ALIGN(ctx_size, sizeof(*ctx->internal_buffer)); - /* - * We just fill the pointers and num_attrs here. The data itself will be - * filled at a later stage (uverbs_process_attr) - */ - for (i = 0; i < method_spec->num_buckets; i++) { - unsigned int curr_num_attrs; + return ret; +} - if (!method_spec->attr_buckets[i]) - continue; +static int ib_uverbs_cmd_verbs(struct ib_uverbs_file *ufile, + struct ib_uverbs_ioctl_hdr *hdr, + struct ib_uverbs_attr __user *user_attrs) +{ + const struct uverbs_api_ioctl_method *method_elm; + struct uverbs_api *uapi = ufile->device->uapi; + struct radix_tree_iter attrs_iter; + struct bundle_priv *pbundle; + struct bundle_priv onstack; + void __rcu **slot; + int destroy_ret; + int ret; - curr_num_attrs = method_spec->attr_buckets[i]->num_attrs; + if (unlikely(hdr->driver_id != uapi->driver_id)) + return -EINVAL; - ctx->bundle.hash[i].attrs = curr_attr; - curr_attr += curr_num_attrs; - ctx->bundle.hash[i].num_attrs = curr_num_attrs; - ctx->bundle.hash[i].valid_bitmap = curr_bitmap; - bitmap_zero(curr_bitmap, curr_num_attrs); - curr_bitmap += BITS_TO_LONGS(curr_num_attrs); - } + slot = radix_tree_iter_lookup( + &uapi->radix, &attrs_iter, + uapi_key_obj(hdr->object_id) | + uapi_key_ioctl_method(hdr->method_id)); + if (unlikely(!slot)) + return -EPROTONOSUPPORT; + method_elm = srcu_dereference(*slot, &ufile->device->disassociate_srcu); - err = copy_from_user(ctx->uattrs, user_attrs, - sizeof(*ctx->uattrs) * hdr->num_attrs); - if (err) { - err = -EFAULT; - goto out; + if (!method_elm->use_stack) { + pbundle = kmalloc(method_elm->bundle_size, GFP_KERNEL); + if (!pbundle) + return -ENOMEM; + pbundle->internal_avail = + method_elm->bundle_size - + offsetof(struct bundle_priv, internal_buffer); + pbundle->alloc_head.next = NULL; + pbundle->allocated_mem = &pbundle->alloc_head; + } else { + pbundle = &onstack; + pbundle->internal_avail = sizeof(pbundle->internal_buffer); + pbundle->allocated_mem = NULL; } - ctx->destroy_attr = NULL; - ctx->bundle.ufile = file; - ctx->user_attrs = user_attrs; - err = uverbs_handle_method(hdr->num_attrs, method_spec, ctx); + /* Space for the pbundle->bundle.attrs flex array */ + pbundle->method_elm = method_elm; + pbundle->method_key = attrs_iter.index; + pbundle->bundle.ufile = ufile; + pbundle->radix = &uapi->radix; + pbundle->radix_slots = slot; + pbundle->radix_slots_len = radix_tree_chunk_size(&attrs_iter); + pbundle->user_attrs = user_attrs; + + pbundle->internal_used = ALIGN(pbundle->method_elm->key_bitmap_len * + sizeof(*pbundle->bundle.attrs), + sizeof(*pbundle->internal_buffer)); + memset(pbundle->bundle.attr_present, 0, + sizeof(pbundle->bundle.attr_present)); + memset(pbundle->uobj_finalize, 0, sizeof(pbundle->uobj_finalize)); + + ret = ib_uverbs_run_method(pbundle, hdr->num_attrs); + destroy_ret = bundle_destroy(pbundle, ret == 0); + if (unlikely(destroy_ret && !ret)) + return destroy_ret; - /* - * EPROTONOSUPPORT is ONLY to be returned if the ioctl framework can - * not invoke the method because the request is not supported. No - * other cases should return this code. - */ - if (unlikely(err == -EPROTONOSUPPORT)) { - WARN_ON_ONCE(err == -EPROTONOSUPPORT); - err = -EINVAL; - } -out: - bundle_destroy(ctx); - return err; + return ret; } #define IB_UVERBS_MAX_CMD_SZ 4096 @@ -567,7 +505,7 @@ long ib_uverbs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) goto out; } - err = ib_uverbs_cmd_verbs(ib_dev, file, &hdr, user_hdr->attrs); + err = ib_uverbs_cmd_verbs(file, &hdr, user_hdr->attrs); } else { err = -ENOIOCTLCMD; } diff --git a/drivers/infiniband/core/uverbs_uapi.c b/drivers/infiniband/core/uverbs_uapi.c index 21c0de034511c2..73ea6f0db88fb5 100644 --- a/drivers/infiniband/core/uverbs_uapi.c +++ b/drivers/infiniband/core/uverbs_uapi.c @@ -160,6 +160,7 @@ uapi_finalize_ioctl_method(struct uverbs_api *uapi, u32 method_key) { struct radix_tree_iter iter; + unsigned int num_attrs = 0; unsigned int max_bkey = 0; bool single_uobj = false; void __rcu **slot; @@ -204,11 +205,13 @@ uapi_finalize_ioctl_method(struct uverbs_api *uapi, } max_bkey = max(max_bkey, attr_bkey); + num_attrs++; } method_elm->key_bitmap_len = max_bkey + 1; WARN_ON(method_elm->key_bitmap_len > UVERBS_API_ATTR_BKEY_LEN); + uapi_compute_bundle_size(method_elm, num_attrs); return 0; } diff --git a/include/rdma/uverbs_ioctl.h b/include/rdma/uverbs_ioctl.h index 1dbf663f7f436a..24ef8d9ac6314e 100644 --- a/include/rdma/uverbs_ioctl.h +++ b/include/rdma/uverbs_ioctl.h @@ -451,6 +451,7 @@ struct uverbs_object_tree_def { * ================================================= */ + struct uverbs_ptr_attr { /* * If UVERBS_ATTR_SPEC_F_ALLOC_AND_COPY is set then the 'ptr' is @@ -467,6 +468,7 @@ struct uverbs_ptr_attr { struct uverbs_obj_attr { struct ib_uobject *uobject; + const struct uverbs_api_attr *attr_elm; }; struct uverbs_attr { @@ -476,39 +478,17 @@ struct uverbs_attr { }; }; -struct uverbs_attr_bundle_hash { - /* if bit i is set, it means attrs[i] contains valid information */ - unsigned long *valid_bitmap; - size_t num_attrs; - /* - * arrays of attributes, each element corresponds to the specification - * of the attribute in the same index. - */ - struct uverbs_attr *attrs; -}; - struct uverbs_attr_bundle { struct ib_uverbs_file *ufile; - size_t num_buckets; - struct uverbs_attr_bundle_hash hash[]; + DECLARE_BITMAP(attr_present, UVERBS_API_ATTR_BKEY_LEN); + struct uverbs_attr attrs[]; }; -static inline bool uverbs_attr_is_valid_in_hash(const struct uverbs_attr_bundle_hash *attrs_hash, - unsigned int idx) -{ - return test_bit(idx, attrs_hash->valid_bitmap); -} - static inline bool uverbs_attr_is_valid(const struct uverbs_attr_bundle *attrs_bundle, unsigned int idx) { - u16 idx_bucket = idx >> UVERBS_ID_NS_SHIFT; - - if (attrs_bundle->num_buckets <= idx_bucket) - return false; - - return uverbs_attr_is_valid_in_hash(&attrs_bundle->hash[idx_bucket], - idx & ~UVERBS_ID_NS_MASK); + return test_bit(uapi_bkey_attr(uapi_key_attr(idx)), + attrs_bundle->attr_present); } #define IS_UVERBS_COPY_ERR(_ret) ((_ret) && (_ret) != -ENOENT) @@ -516,12 +496,10 @@ static inline bool uverbs_attr_is_valid(const struct uverbs_attr_bundle *attrs_b static inline const struct uverbs_attr *uverbs_attr_get(const struct uverbs_attr_bundle *attrs_bundle, u16 idx) { - u16 idx_bucket = idx >> UVERBS_ID_NS_SHIFT; - if (!uverbs_attr_is_valid(attrs_bundle, idx)) return ERR_PTR(-ENOENT); - return &attrs_bundle->hash[idx_bucket].attrs[idx & ~UVERBS_ID_NS_MASK]; + return &attrs_bundle->attrs[uapi_bkey_attr(uapi_key_attr(idx))]; } static inline int uverbs_attr_get_enum_id(const struct uverbs_attr_bundle *attrs_bundle, From patchwork Fri Aug 10 02:14:43 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Gunthorpe X-Patchwork-Id: 10562197 X-Patchwork-Delegate: jgg@ziepe.ca Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7865C15A6 for ; Fri, 10 Aug 2018 02:15:02 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 63E322BB93 for ; Fri, 10 Aug 2018 02:15:02 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 573192BBA4; Fri, 10 Aug 2018 02:15:02 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 93CC92BBAF for ; Fri, 10 Aug 2018 02:15:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725784AbeHJEmj (ORCPT ); Fri, 10 Aug 2018 00:42:39 -0400 Received: from mail-pl0-f68.google.com ([209.85.160.68]:45626 "EHLO mail-pl0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725877AbeHJEmi (ORCPT ); Fri, 10 Aug 2018 00:42:38 -0400 Received: by mail-pl0-f68.google.com with SMTP id j8-v6so3351045pll.12 for ; Thu, 09 Aug 2018 19:14:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ziepe.ca; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=IZ0ttfvN113yExL5rua5mNxZBIULX61bduTnEAbTpRY=; b=Dc6HasVXYZ0UijJDVTpbEnfqHHxh5TLR6J6HxaYxclhOs6V3r3M4dvIjI55iFaez8p 8/nHhdmazSxOpLW8WYbAqbfzWZ0uXhSRjMaU577O9POG/YH6WpMr/BzgefaIOlEXWKqa kZAEmzwADMfuz7KsQNvkiqxOOLktzolih/LGgil5AaL5JOSMxDhdBtE18dHkfZnLXX14 xkNDDnviJQ+uW6mcbtujxfPB6i1g8cK3Xfa8PYeUNcjcJA9zm2u+cTTxWCQSLR7LPhB3 7UQaJGbnzg874tdi41eZOg6p7lRd1o4zbV1mTAtAGn59Hnk+Ox48B7vGY8sPFIxJNk80 166g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=IZ0ttfvN113yExL5rua5mNxZBIULX61bduTnEAbTpRY=; b=pOvesLpz4JflPYR/srovFJzKuvtCF1g1j6Qy9CYQP/oCdPI1npU9xw7/opJs/71q3M crgaM1iq9BDoc1KWdNsbSgZQAPz96GWo/QW/cT3ePvFZpKDGH04thlpLWrhAPSOQrEVp hify8aCRjuuhxqoEzqJmk70c+h89DBvVbSWh10olgJis8CNlm6hMRAOC1q1w99g9t42V pm8bPj0Ux5R2RV0/t1YPYHyNcZtg/9SGgZajXwVqFyyW2o9z1fXFM0LgZzjeXlf5KJOz vmOLlc5PzHOGvdOEMODT40sHy+/Xju2O5NohfKiActwtoMrSn53R59vaf9GL86LewYVQ jeow== X-Gm-Message-State: AOUpUlG4uJfqUxK1FilyR9MzYHKXhjcaoT8byoVPXiy9zlFsudr3LXRj TX5TbDY5K9fS12E7xPExTv0EnwlAZoo= X-Google-Smtp-Source: AA+uWPymXmHzHN3I7nml9lG+IIdH+z9Au+DDMMyaU9t4eNu0nzHxvB8Q54INQixPo+aJpXWA0uLlkw== X-Received: by 2002:a17:902:5a08:: with SMTP id q8-v6mr4162866pli.300.1533867297670; Thu, 09 Aug 2018 19:14:57 -0700 (PDT) Received: from ziepe.ca (S010614cc2056d97f.ed.shawcable.net. [174.3.196.123]) by smtp.gmail.com with ESMTPSA id 203-v6sm12339076pgb.14.2018.08.09.19.14.52 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Thu, 09 Aug 2018 19:14:55 -0700 (PDT) Received: from jgg by mlx with local (Exim 4.90_1) (envelope-from ) id 1fnwx1-0003gx-Kg; Thu, 09 Aug 2018 20:14:51 -0600 From: Jason Gunthorpe To: linux-rdma@vger.kernel.org, Leon Romanovsky , "Guy Levi(SW)" , Yishai Hadas , "Ruhl, Michael J" Cc: Jason Gunthorpe Subject: [PATCH v1 09/10] IB/uverbs: Remove struct uverbs_root_spec and all supporting code Date: Thu, 9 Aug 2018 20:14:43 -0600 Message-Id: <20180810021444.14014-10-jgg@ziepe.ca> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180810021444.14014-1-jgg@ziepe.ca> References: <20180810021444.14014-1-jgg@ziepe.ca> Sender: linux-rdma-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-rdma@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Jason Gunthorpe Everything now uses the uverbs_uapi data structure. Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/Makefile | 2 +- drivers/infiniband/core/rdma_core.c | 45 -- drivers/infiniband/core/rdma_core.h | 6 - drivers/infiniband/core/uverbs.h | 1 - drivers/infiniband/core/uverbs_ioctl_merge.c | 662 ------------------- drivers/infiniband/core/uverbs_main.c | 28 +- include/rdma/uverbs_ioctl.h | 91 --- 7 files changed, 2 insertions(+), 833 deletions(-) delete mode 100644 drivers/infiniband/core/uverbs_ioctl_merge.c diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile index d934cf617841fb..867cee5e27b222 100644 --- a/drivers/infiniband/core/Makefile +++ b/drivers/infiniband/core/Makefile @@ -35,7 +35,7 @@ ib_ucm-y := ucm.o ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_marshall.o \ rdma_core.o uverbs_std_types.o uverbs_ioctl.o \ - uverbs_ioctl_merge.o uverbs_std_types_cq.o \ + uverbs_std_types_cq.o \ uverbs_std_types_flow_action.o uverbs_std_types_dm.o \ uverbs_std_types_mr.o uverbs_std_types_counters.o \ uverbs_uapi.o diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c index 2814228ead39f0..12e7c6c102c136 100644 --- a/drivers/infiniband/core/rdma_core.c +++ b/drivers/infiniband/core/rdma_core.c @@ -42,51 +42,6 @@ #include "core_priv.h" #include "rdma_core.h" -int uverbs_ns_idx(u16 *id, unsigned int ns_count) -{ - int ret = (*id & UVERBS_ID_NS_MASK) >> UVERBS_ID_NS_SHIFT; - - if (ret >= ns_count) - return -EINVAL; - - *id &= ~UVERBS_ID_NS_MASK; - return ret; -} - -const struct uverbs_object_spec *uverbs_get_object(struct ib_uverbs_file *ufile, - uint16_t object) -{ - const struct uverbs_root_spec *object_hash = ufile->device->specs_root; - const struct uverbs_object_spec_hash *objects; - int ret = uverbs_ns_idx(&object, object_hash->num_buckets); - - if (ret < 0) - return NULL; - - objects = object_hash->object_buckets[ret]; - - if (object >= objects->num_objects) - return NULL; - - return objects->objects[object]; -} - -const struct uverbs_method_spec *uverbs_get_method(const struct uverbs_object_spec *object, - uint16_t method) -{ - const struct uverbs_method_spec_hash *methods; - int ret = uverbs_ns_idx(&method, object->num_buckets); - - if (ret < 0) - return NULL; - - methods = object->method_buckets[ret]; - if (method >= methods->num_methods) - return NULL; - - return methods->methods[method]; -} - void uverbs_uobject_get(struct ib_uobject *uobject) { kref_get(&uobject->ref); diff --git a/drivers/infiniband/core/rdma_core.h b/drivers/infiniband/core/rdma_core.h index aca279bfef0831..f962f2a593bafc 100644 --- a/drivers/infiniband/core/rdma_core.h +++ b/drivers/infiniband/core/rdma_core.h @@ -45,12 +45,6 @@ struct ib_uverbs_device; -int uverbs_ns_idx(u16 *id, unsigned int ns_count); -const struct uverbs_object_spec *uverbs_get_object(struct ib_uverbs_file *ufile, - uint16_t object); -const struct uverbs_method_spec *uverbs_get_method(const struct uverbs_object_spec *object, - uint16_t method); - void uverbs_destroy_ufile_hw(struct ib_uverbs_file *ufile, enum rdma_remove_reason reason); diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index 879be0d1fd99d8..5df8e548cc1460 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -111,7 +111,6 @@ struct ib_uverbs_device { struct mutex lists_mutex; /* protect lists */ struct list_head uverbs_file_list; struct list_head uverbs_events_file_list; - struct uverbs_root_spec *specs_root; struct uverbs_api *uapi; }; diff --git a/drivers/infiniband/core/uverbs_ioctl_merge.c b/drivers/infiniband/core/uverbs_ioctl_merge.c deleted file mode 100644 index 16b57592991581..00000000000000 --- a/drivers/infiniband/core/uverbs_ioctl_merge.c +++ /dev/null @@ -1,662 +0,0 @@ -/* - * Copyright (c) 2017, Mellanox Technologies inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include "uverbs.h" - -#define UVERBS_NUM_NS (UVERBS_ID_NS_MASK >> UVERBS_ID_NS_SHIFT) -#define GET_NS_ID(idx) (((idx) & UVERBS_ID_NS_MASK) >> UVERBS_ID_NS_SHIFT) -#define GET_ID(idx) ((idx) & ~UVERBS_ID_NS_MASK) - -#define _for_each_element(elem, tmpi, tmpj, hashes, num_buckets_offset, \ - buckets_offset) \ - for (tmpj = 0, \ - elem = (*(const void ***)((hashes)[tmpi] + \ - (buckets_offset)))[0]; \ - tmpj < *(size_t *)((hashes)[tmpi] + (num_buckets_offset)); \ - tmpj++) \ - if ((elem = ((*(const void ***)(hashes[tmpi] + \ - (buckets_offset)))[tmpj]))) - -/* - * Iterate all elements of a few @hashes. The number of given hashes is - * indicated by @num_hashes. The offset of the number of buckets in the hash is - * represented by @num_buckets_offset, while the offset of the buckets array in - * the hash structure is represented by @buckets_offset. tmpi and tmpj are two - * short (or int) based indices that are given by the user. tmpi iterates over - * the different hashes. @elem points the current element in the hashes[tmpi] - * bucket we are looping on. To be honest, @hashes representation isn't exactly - * a hash, but more a collection of elements. These elements' ids are treated - * in a hash like manner, where the first upper bits are the bucket number. - * These elements are later mapped into a perfect-hash. - */ -#define for_each_element(elem, tmpi, tmpj, hashes, num_hashes, \ - num_buckets_offset, buckets_offset) \ - for (tmpi = 0; tmpi < (num_hashes); tmpi++) \ - _for_each_element(elem, tmpi, tmpj, hashes, num_buckets_offset,\ - buckets_offset) - -#define get_elements_iterators_entry_above(iters, num_elements, elements, \ - num_objects_fld, objects_fld, bucket,\ - min_id) \ - get_elements_above_id((const void **)iters, num_elements, \ - (const void **)(elements), \ - offsetof(typeof(**elements), \ - num_objects_fld), \ - offsetof(typeof(**elements), objects_fld),\ - offsetof(typeof(***(*elements)->objects_fld), id),\ - bucket, min_id) - -#define get_objects_above_id(iters, num_trees, trees, bucket, min_id) \ - get_elements_iterators_entry_above(iters, num_trees, trees, \ - num_objects, objects, bucket, min_id) - -#define get_methods_above_id(method_iters, num_iters, iters, bucket, min_id)\ - get_elements_iterators_entry_above(method_iters, num_iters, iters, \ - num_methods, methods, bucket, min_id) - -#define get_attrs_above_id(attrs_iters, num_iters, iters, bucket, min_id)\ - get_elements_iterators_entry_above(attrs_iters, num_iters, iters, \ - num_attrs, attrs, bucket, min_id) - -/* - * get_elements_above_id get a few hashes represented by @elements and - * @num_elements. The hashes fields are described by @num_offset, @data_offset - * and @id_offset in the same way as required by for_each_element. The function - * returns an array of @iters, represents an array of elements in the hashes - * buckets, which their ids are the smallest ids in all hashes but are all - * larger than the id given by min_id. Elements are only added to the iters - * array if their id belongs to the bucket @bucket. The number of elements in - * the returned array is returned by the function. @min_id is also updated to - * reflect the new min_id of all elements in iters. - */ -static size_t get_elements_above_id(const void **iters, - unsigned int num_elements, - const void **elements, - size_t num_offset, - size_t data_offset, - size_t id_offset, - u16 bucket, - short *min_id) -{ - size_t num_iters = 0; - short min = SHRT_MAX; - const void *elem; - int i, j, last_stored = -1; - unsigned int equal_min = 0; - - for_each_element(elem, i, j, elements, num_elements, num_offset, - data_offset) { - u16 id = *(u16 *)(elem + id_offset); - - if (GET_NS_ID(id) != bucket) - continue; - - if (GET_ID(id) < *min_id || - (min != SHRT_MAX && GET_ID(id) > min)) - continue; - - /* - * We first iterate all hashes represented by @elements. When - * we do, we try to find an element @elem in the bucket @bucket - * which its id is min. Since we can't ensure the user sorted - * the elements in increasing order, we override this hash's - * minimal id element we found, if a new element with a smaller - * id was just found. - */ - iters[last_stored == i ? num_iters - 1 : num_iters++] = elem; - last_stored = i; - if (min == GET_ID(id)) - equal_min++; - else - equal_min = 1; - min = GET_ID(id); - } - - /* - * We only insert to our iters array an element, if its id is smaller - * than all previous ids. Therefore, the final iters array is sorted so - * that smaller ids are in the end of the array. - * Therefore, we need to clean the beginning of the array to make sure - * all ids of final elements are equal to min. - */ - memmove(iters, iters + num_iters - equal_min, sizeof(*iters) * equal_min); - - *min_id = min; - return equal_min; -} - -#define find_max_element_entry_id(num_elements, elements, num_objects_fld, \ - objects_fld, bucket) \ - find_max_element_id(num_elements, (const void **)(elements), \ - offsetof(typeof(**elements), num_objects_fld), \ - offsetof(typeof(**elements), objects_fld), \ - offsetof(typeof(***(*elements)->objects_fld), id),\ - bucket) - -static short find_max_element_ns_id(unsigned int num_elements, - const void **elements, - size_t num_offset, - size_t data_offset, - size_t id_offset) -{ - short max_ns = SHRT_MIN; - const void *elem; - int i, j; - - for_each_element(elem, i, j, elements, num_elements, num_offset, - data_offset) { - u16 id = *(u16 *)(elem + id_offset); - - if (GET_NS_ID(id) > max_ns) - max_ns = GET_NS_ID(id); - } - - return max_ns; -} - -static short find_max_element_id(unsigned int num_elements, - const void **elements, - size_t num_offset, - size_t data_offset, - size_t id_offset, - u16 bucket) -{ - short max_id = SHRT_MIN; - const void *elem; - int i, j; - - for_each_element(elem, i, j, elements, num_elements, num_offset, - data_offset) { - u16 id = *(u16 *)(elem + id_offset); - - if (GET_NS_ID(id) == bucket && - GET_ID(id) > max_id) - max_id = GET_ID(id); - } - return max_id; -} - -#define find_max_element_entry_id(num_elements, elements, num_objects_fld, \ - objects_fld, bucket) \ - find_max_element_id(num_elements, (const void **)(elements), \ - offsetof(typeof(**elements), num_objects_fld), \ - offsetof(typeof(**elements), objects_fld), \ - offsetof(typeof(***(*elements)->objects_fld), id),\ - bucket) - -#define find_max_element_ns_entry_id(num_elements, elements, \ - num_objects_fld, objects_fld) \ - find_max_element_ns_id(num_elements, (const void **)(elements), \ - offsetof(typeof(**elements), num_objects_fld),\ - offsetof(typeof(**elements), objects_fld), \ - offsetof(typeof(***(*elements)->objects_fld), id)) - -/* - * find_max_xxxx_ns_id gets a few elements. Each element is described by an id - * which its upper bits represents a namespace. It finds the max namespace. This - * could be used in order to know how many buckets do we need to allocate. If no - * elements exist, SHRT_MIN is returned. Namespace represents here different - * buckets. The common example is "common bucket" and "driver bucket". - * - * find_max_xxxx_id gets a few elements and a bucket. Each element is described - * by an id which its upper bits represent a namespace. It returns the max id - * which is contained in the same namespace defined in @bucket. This could be - * used in order to know how many elements do we need to allocate in the bucket. - * If no elements exist, SHRT_MIN is returned. - */ - -#define find_max_object_id(num_trees, trees, bucket) \ - find_max_element_entry_id(num_trees, trees, num_objects,\ - objects, bucket) -#define find_max_object_ns_id(num_trees, trees) \ - find_max_element_ns_entry_id(num_trees, trees, \ - num_objects, objects) - -#define find_max_method_id(num_iters, iters, bucket) \ - find_max_element_entry_id(num_iters, iters, num_methods,\ - methods, bucket) -#define find_max_method_ns_id(num_iters, iters) \ - find_max_element_ns_entry_id(num_iters, iters, \ - num_methods, methods) - -#define find_max_attr_id(num_iters, iters, bucket) \ - find_max_element_entry_id(num_iters, iters, num_attrs, \ - attrs, bucket) -#define find_max_attr_ns_id(num_iters, iters) \ - find_max_element_ns_entry_id(num_iters, iters, \ - num_attrs, attrs) - -static void free_method(struct uverbs_method_spec *method) -{ - unsigned int i; - - if (!method) - return; - - for (i = 0; i < method->num_buckets; i++) - kfree(method->attr_buckets[i]); - - kfree(method); -} - -#define IS_ATTR_OBJECT(attr) ((attr)->type == UVERBS_ATTR_TYPE_IDR || \ - (attr)->type == UVERBS_ATTR_TYPE_FD) - -/* - * This function gets array of size @num_method_defs which contains pointers to - * method definitions @method_defs. The function allocates an - * uverbs_method_spec structure and initializes its number of buckets and the - * elements in buckets to the correct attributes. While doing that, it - * validates that there aren't conflicts between attributes of different - * method_defs. - */ -static struct uverbs_method_spec *build_method_with_attrs(const struct uverbs_method_def **method_defs, - size_t num_method_defs) -{ - int bucket_idx; - int max_attr_buckets = 0; - size_t num_attr_buckets = 0; - int res = 0; - struct uverbs_method_spec *method = NULL; - const struct uverbs_attr_def **attr_defs; - unsigned int num_of_singularities = 0; - - max_attr_buckets = find_max_attr_ns_id(num_method_defs, method_defs); - if (max_attr_buckets >= 0) - num_attr_buckets = max_attr_buckets + 1; - - method = kzalloc(struct_size(method, attr_buckets, num_attr_buckets), - GFP_KERNEL); - if (!method) - return ERR_PTR(-ENOMEM); - - method->num_buckets = num_attr_buckets; - attr_defs = kcalloc(num_method_defs, sizeof(*attr_defs), GFP_KERNEL); - if (!attr_defs) { - res = -ENOMEM; - goto free_method; - } - for (bucket_idx = 0; bucket_idx < method->num_buckets; bucket_idx++) { - short min_id = SHRT_MIN; - int attr_max_bucket = 0; - struct uverbs_attr_spec_hash *hash = NULL; - - attr_max_bucket = find_max_attr_id(num_method_defs, method_defs, - bucket_idx); - if (attr_max_bucket < 0) - continue; - - hash = kzalloc(sizeof(*hash) + - ALIGN(sizeof(*hash->attrs) * (attr_max_bucket + 1), - sizeof(long)) + - BITS_TO_LONGS(attr_max_bucket + 1) * sizeof(long), - GFP_KERNEL); - if (!hash) { - res = -ENOMEM; - goto free; - } - hash->num_attrs = attr_max_bucket + 1; - method->num_child_attrs += hash->num_attrs; - hash->mandatory_attrs_bitmask = (void *)(hash + 1) + - ALIGN(sizeof(*hash->attrs) * - (attr_max_bucket + 1), - sizeof(long)); - - method->attr_buckets[bucket_idx] = hash; - - do { - size_t num_attr_defs; - struct uverbs_attr_spec *attr; - bool attr_obj_with_special_access; - - num_attr_defs = - get_attrs_above_id(attr_defs, - num_method_defs, - method_defs, - bucket_idx, - &min_id); - /* Last attr in bucket */ - if (!num_attr_defs) - break; - - if (num_attr_defs > 1) { - /* - * We don't allow two attribute definitions for - * the same attribute. This is usually a - * programmer error. If required, it's better to - * just add a new attribute to capture the new - * semantics. - */ - res = -EEXIST; - goto free; - } - - attr = &hash->attrs[min_id]; - memcpy(attr, &attr_defs[0]->attr, sizeof(*attr)); - - attr_obj_with_special_access = IS_ATTR_OBJECT(attr) && - (attr->u.obj.access == UVERBS_ACCESS_NEW || - attr->u.obj.access == UVERBS_ACCESS_DESTROY); - num_of_singularities += !!attr_obj_with_special_access; - if (WARN(num_of_singularities > 1, - "ib_uverbs: Method contains more than one object attr (%d) with new/destroy access\n", - min_id) || - WARN(attr_obj_with_special_access && - !attr->mandatory, - "ib_uverbs: Tried to merge attr (%d) but it's an object with new/destroy access but isn't mandatory\n", - min_id) || - WARN(IS_ATTR_OBJECT(attr) && - attr->zero_trailing, - "ib_uverbs: Tried to merge attr (%d) but it's an object with min_sz flag\n", - min_id)) { - res = -EINVAL; - goto free; - } - - if (attr->mandatory) - set_bit(min_id, hash->mandatory_attrs_bitmask); - min_id++; - - } while (1); - } - kfree(attr_defs); - return method; - -free: - kfree(attr_defs); -free_method: - free_method(method); - return ERR_PTR(res); -} - -static void free_object(struct uverbs_object_spec *object) -{ - unsigned int i, j; - - if (!object) - return; - - for (i = 0; i < object->num_buckets; i++) { - struct uverbs_method_spec_hash *method_buckets = - object->method_buckets[i]; - - if (!method_buckets) - continue; - - for (j = 0; j < method_buckets->num_methods; j++) - free_method(method_buckets->methods[j]); - - kfree(method_buckets); - } - - kfree(object); -} - -/* - * This function gets array of size @num_object_defs which contains pointers to - * object definitions @object_defs. The function allocated an - * uverbs_object_spec structure and initialize its number of buckets and the - * elements in buckets to the correct methods. While doing that, it - * sorts out the correct relationship between conflicts in the same method. - */ -static struct uverbs_object_spec *build_object_with_methods(const struct uverbs_object_def **object_defs, - size_t num_object_defs) -{ - u16 bucket_idx; - int max_method_buckets = 0; - u16 num_method_buckets = 0; - int res = 0; - struct uverbs_object_spec *object = NULL; - const struct uverbs_method_def **method_defs; - - max_method_buckets = find_max_method_ns_id(num_object_defs, object_defs); - if (max_method_buckets >= 0) - num_method_buckets = max_method_buckets + 1; - - object = kzalloc(struct_size(object, method_buckets, - num_method_buckets), - GFP_KERNEL); - if (!object) - return ERR_PTR(-ENOMEM); - - object->num_buckets = num_method_buckets; - method_defs = kcalloc(num_object_defs, sizeof(*method_defs), GFP_KERNEL); - if (!method_defs) { - res = -ENOMEM; - goto free_object; - } - - for (bucket_idx = 0; bucket_idx < object->num_buckets; bucket_idx++) { - short min_id = SHRT_MIN; - int methods_max_bucket = 0; - struct uverbs_method_spec_hash *hash = NULL; - - methods_max_bucket = find_max_method_id(num_object_defs, object_defs, - bucket_idx); - if (methods_max_bucket < 0) - continue; - - hash = kzalloc(struct_size(hash, methods, - methods_max_bucket + 1), - GFP_KERNEL); - if (!hash) { - res = -ENOMEM; - goto free; - } - - hash->num_methods = methods_max_bucket + 1; - object->method_buckets[bucket_idx] = hash; - - do { - size_t num_method_defs; - struct uverbs_method_spec *method; - int i; - - num_method_defs = - get_methods_above_id(method_defs, - num_object_defs, - object_defs, - bucket_idx, - &min_id); - /* Last method in bucket */ - if (!num_method_defs) - break; - - method = build_method_with_attrs(method_defs, - num_method_defs); - if (IS_ERR(method)) { - res = PTR_ERR(method); - goto free; - } - - /* - * The last tree which is given as an argument to the - * merge overrides previous method handler. - * Therefore, we iterate backwards and search for the - * first handler which != NULL. This also defines the - * set of flags used for this handler. - */ - for (i = num_method_defs - 1; - i >= 0 && !method_defs[i]->handler; i--) - ; - hash->methods[min_id++] = method; - /* NULL handler isn't allowed */ - if (WARN(i < 0, - "ib_uverbs: tried to merge function id %d, but all handlers are NULL\n", - min_id)) { - res = -EINVAL; - goto free; - } - method->handler = method_defs[i]->handler; - method->flags = method_defs[i]->flags; - - } while (1); - } - kfree(method_defs); - return object; - -free: - kfree(method_defs); -free_object: - free_object(object); - return ERR_PTR(res); -} - -void uverbs_free_spec_tree(struct uverbs_root_spec *root) -{ - unsigned int i, j; - - if (!root) - return; - - for (i = 0; i < root->num_buckets; i++) { - struct uverbs_object_spec_hash *object_hash = - root->object_buckets[i]; - - if (!object_hash) - continue; - - for (j = 0; j < object_hash->num_objects; j++) - free_object(object_hash->objects[j]); - - kfree(object_hash); - } - - kfree(root); -} - -struct uverbs_root_spec *uverbs_alloc_spec_tree(unsigned int num_trees, - const struct uverbs_object_tree_def **trees) -{ - u16 bucket_idx; - short max_object_buckets = 0; - size_t num_objects_buckets = 0; - struct uverbs_root_spec *root_spec = NULL; - const struct uverbs_object_def **object_defs; - int i; - int res = 0; - - max_object_buckets = find_max_object_ns_id(num_trees, trees); - /* - * Devices which don't want to support ib_uverbs, should just allocate - * an empty parsing tree. Every user-space command won't hit any valid - * entry in the parsing tree and thus will fail. - */ - if (max_object_buckets >= 0) - num_objects_buckets = max_object_buckets + 1; - - root_spec = kzalloc(struct_size(root_spec, object_buckets, - num_objects_buckets), - GFP_KERNEL); - if (!root_spec) - return ERR_PTR(-ENOMEM); - root_spec->num_buckets = num_objects_buckets; - - object_defs = kcalloc(num_trees, sizeof(*object_defs), - GFP_KERNEL); - if (!object_defs) { - res = -ENOMEM; - goto free_root; - } - - for (bucket_idx = 0; bucket_idx < root_spec->num_buckets; bucket_idx++) { - short min_id = SHRT_MIN; - short objects_max_bucket; - struct uverbs_object_spec_hash *hash = NULL; - - objects_max_bucket = find_max_object_id(num_trees, trees, - bucket_idx); - if (objects_max_bucket < 0) - continue; - - hash = kzalloc(struct_size(hash, objects, - objects_max_bucket + 1), - GFP_KERNEL); - if (!hash) { - res = -ENOMEM; - goto free; - } - hash->num_objects = objects_max_bucket + 1; - root_spec->object_buckets[bucket_idx] = hash; - - do { - size_t num_object_defs; - struct uverbs_object_spec *object; - - num_object_defs = get_objects_above_id(object_defs, - num_trees, - trees, - bucket_idx, - &min_id); - /* Last object in bucket */ - if (!num_object_defs) - break; - - object = build_object_with_methods(object_defs, - num_object_defs); - if (IS_ERR(object)) { - res = PTR_ERR(object); - goto free; - } - - /* - * The last tree which is given as an argument to the - * merge overrides previous object's type_attrs. - * Therefore, we iterate backwards and search for the - * first type_attrs which != NULL. - */ - for (i = num_object_defs - 1; - i >= 0 && !object_defs[i]->type_attrs; i--) - ; - /* - * NULL is a valid type_attrs. It means an object we - * can't instantiate (like DEVICE). - */ - object->type_attrs = i < 0 ? NULL : - object_defs[i]->type_attrs; - - hash->objects[min_id++] = object; - } while (1); - } - - kfree(object_defs); - return root_spec; - -free: - kfree(object_defs); -free_root: - uverbs_free_spec_tree(root_spec); - return ERR_PTR(res); -} diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 0fab083cafef09..823beca448e109 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -176,7 +176,6 @@ static void ib_uverbs_release_dev(struct kobject *kobj) uverbs_destroy_api(dev->uapi); cleanup_srcu_struct(&dev->disassociate_srcu); - uverbs_free_spec_tree(dev->specs_root); kfree(dev); } @@ -998,37 +997,12 @@ static CLASS_ATTR_STRING(abi_version, S_IRUGO, static int ib_uverbs_create_uapi(struct ib_device *device, struct ib_uverbs_device *uverbs_dev) { - const struct uverbs_object_tree_def **specs; - struct uverbs_root_spec *specs_root; - unsigned int num_specs = 1; struct uverbs_api *uapi; - unsigned int i; - - if (device->driver_specs) - for (i = 0; device->driver_specs[i]; i++) - num_specs++; - - specs = kmalloc_array(num_specs, sizeof(*specs), GFP_KERNEL); - if (!specs) - return -ENOMEM; - - specs[0] = uverbs_default_get_objects(); - if (device->driver_specs) - for (i = 0; device->driver_specs[i]; i++) - specs[i+1] = device->driver_specs[i]; - - specs_root = uverbs_alloc_spec_tree(num_specs, specs); - kfree(specs); - if (IS_ERR(specs_root)) - return PTR_ERR(specs_root); uapi = uverbs_alloc_api(device->driver_specs, device->driver_id); - if (IS_ERR(uapi)) { - uverbs_free_spec_tree(specs_root); + if (IS_ERR(uapi)) return PTR_ERR(uapi); - } - uverbs_dev->specs_root = specs_root; uverbs_dev->uapi = uapi; return 0; } diff --git a/include/rdma/uverbs_ioctl.h b/include/rdma/uverbs_ioctl.h index 24ef8d9ac6314e..9e997c3c2f0423 100644 --- a/include/rdma/uverbs_ioctl.h +++ b/include/rdma/uverbs_ioctl.h @@ -114,46 +114,6 @@ struct uverbs_attr_spec { } u2; }; -struct uverbs_attr_spec_hash { - size_t num_attrs; - unsigned long *mandatory_attrs_bitmask; - struct uverbs_attr_spec attrs[0]; -}; - -struct uverbs_attr_bundle; -struct ib_uverbs_file; - -struct uverbs_method_spec { - /* Combination of bits from enum UVERBS_ACTION_FLAG_XXXX */ - u32 flags; - size_t num_buckets; - size_t num_child_attrs; - int (*handler)(struct ib_uverbs_file *ufile, - struct uverbs_attr_bundle *ctx); - struct uverbs_attr_spec_hash *attr_buckets[0]; -}; - -struct uverbs_method_spec_hash { - size_t num_methods; - struct uverbs_method_spec *methods[0]; -}; - -struct uverbs_object_spec { - const struct uverbs_obj_type *type_attrs; - size_t num_buckets; - struct uverbs_method_spec_hash *method_buckets[0]; -}; - -struct uverbs_object_spec_hash { - size_t num_objects; - struct uverbs_object_spec *objects[0]; -}; - -struct uverbs_root_spec { - size_t num_buckets; - struct uverbs_object_spec_hash *object_buckets[0]; -}; - /* * Information about the API is loaded into a radix tree. For IOCTL we start * with a tuple of: @@ -673,55 +633,4 @@ static inline __malloc void *uverbs_zalloc(struct uverbs_attr_bundle *bundle, } #endif -/* ================================================= - * Definitions -> Specs infrastructure - * ================================================= - */ - -/* - * uverbs_alloc_spec_tree - Merges different common and driver specific feature - * into one parsing tree that every uverbs command will be parsed upon. - * - * @num_trees: Number of trees in the array @trees. - * @trees: Array of pointers to tree root definitions to merge. Each such tree - * possibly contains objects, methods and attributes definitions. - * - * Returns: - * uverbs_root_spec *: The root of the merged parsing tree. - * On error, we return an error code. Error is checked via IS_ERR. - * - * The following merges could take place: - * a. Two trees representing the same method with different handler - * -> We take the handler of the tree that its handler != NULL - * and its index in the trees array is greater. The incentive for that - * is that developers are expected to first merge common trees and then - * merge trees that gives specialized the behaviour. - * b. Two trees representing the same object with different - * type_attrs (struct uverbs_obj_type): - * -> We take the type_attrs of the tree that its type_attr != NULL - * and its index in the trees array is greater. This could be used - * in order to override the free function, allocation size, etc. - * c. Two trees representing the same method attribute (same id but possibly - * different attributes): - * -> ERROR (-ENOENT), we believe that's not the programmer's intent. - * - * An object without any methods is considered invalid and will abort the - * function with -ENOENT error. - */ -#if IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS) -struct uverbs_root_spec *uverbs_alloc_spec_tree(unsigned int num_trees, - const struct uverbs_object_tree_def **trees); -void uverbs_free_spec_tree(struct uverbs_root_spec *root); -#else -static inline struct uverbs_root_spec *uverbs_alloc_spec_tree(unsigned int num_trees, - const struct uverbs_object_tree_def **trees) -{ - return NULL; -} - -static inline void uverbs_free_spec_tree(struct uverbs_root_spec *root) -{ -} -#endif - #endif From patchwork Fri Aug 10 02:14:44 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Gunthorpe X-Patchwork-Id: 10562189 X-Patchwork-Delegate: jgg@ziepe.ca Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C2EB690E3 for ; Fri, 10 Aug 2018 02:15:00 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B641F2BBB0 for ; Fri, 10 Aug 2018 02:15:00 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id AAFC32BBD7; Fri, 10 Aug 2018 02:15:00 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9DFCB2BBB0 for ; Fri, 10 Aug 2018 02:14:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727143AbeHJEmi (ORCPT ); Fri, 10 Aug 2018 00:42:38 -0400 Received: from mail-pl0-f65.google.com ([209.85.160.65]:45623 "EHLO mail-pl0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727123AbeHJEmi (ORCPT ); Fri, 10 Aug 2018 00:42:38 -0400 Received: by mail-pl0-f65.google.com with SMTP id j8-v6so3351036pll.12 for ; Thu, 09 Aug 2018 19:14:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ziepe.ca; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=qPhpVRs3P0eI9N4Z/3d/49KHwXjwi7kBEnPAEZ9M7vE=; b=SMGaadU1Xup4mERXF5dydGfRM+i7Dp7QXurvvpvVWYtCGfWRonMgw/j9R8zXTYdX6n ZryCqBHKiJCOh8DmRj+DO943OK3Oj3W2Az9ljncvjqPK9VEYqvY5L1/+fbFmkcf31bez cHLnnRzcX+UJTDLlQrclbainjTs+WJvnPkPmaMt2KKjeTI3PaZNvThaoLZzQ/CDd03EV H98s7IypWh+Q/rkedEDQnmH9DAskK0fGyQ09Pdceap4IhaLSqJcA+ImeVUUOSIa4kuyQ zyCuyyVwfpA4rF7m2OG03YF6K8bypbIluSd+Dmp9IeF6BAX6jXO20cD0k94/MW7UXPKg dv4w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=qPhpVRs3P0eI9N4Z/3d/49KHwXjwi7kBEnPAEZ9M7vE=; b=G4wkSP0PJH/sVhHjAfb2K1YWWWkP3+V5g7DZvg3z6Xv2jC7x3FOcymBsbYhgCdzLvM 0SLKA4eDfGGzlnoz5ntM5FjcMZuKh7ZzikMXQMk259TuQXHDasykrFP6b4KKt0If9w4R qZv1UXDk3PYM1WhNe6XqYc0sgDHCTh2WwVwnk/GLFdlh+/H4CMY+Htm7aeB4uV1qK4vP Py39oJ72CfxK+Dj+KMkjC/7h/ncESSeD7mgIbV+Dm3g+ETPHtvM3xhfQ1pp75UIFhNDe 1/3Lils/+WQCAfOX3+ZRI2AmiH/ZqDeUcFHgUiLJGQHjqu4QalX7cwkcK94GsOjxpnaQ 5Gdw== X-Gm-Message-State: AOUpUlGdQSWZ+KJs2Ho4QIgU61SOAmfjtvMl3SA5reOGMz34xAiuP5QU GTf/eInq8Dd6/CIRNWrsnpZuAebhCPc= X-Google-Smtp-Source: AA+uWPx8kpOIdICDSn59TEXigaLZxDO/gQ8k7xHjK3rQVl/uTaevMG+8cje4Nobt9RAgUi1eumjGvw== X-Received: by 2002:a17:902:704c:: with SMTP id h12-v6mr4177968plt.237.1533867297288; Thu, 09 Aug 2018 19:14:57 -0700 (PDT) Received: from ziepe.ca (S010614cc2056d97f.ed.shawcable.net. [174.3.196.123]) by smtp.gmail.com with ESMTPSA id w192-v6sm9349261pfd.74.2018.08.09.19.14.52 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Thu, 09 Aug 2018 19:14:55 -0700 (PDT) Received: from jgg by mlx with local (Exim 4.90_1) (envelope-from ) id 1fnwx1-0003h3-Md; Thu, 09 Aug 2018 20:14:51 -0600 From: Jason Gunthorpe To: linux-rdma@vger.kernel.org, Leon Romanovsky , "Guy Levi(SW)" , Yishai Hadas , "Ruhl, Michael J" Cc: Jason Gunthorpe Subject: [PATCH v1 10/10] IB/uverbs: Do not check for device disassociation during ioctl Date: Thu, 9 Aug 2018 20:14:44 -0600 Message-Id: <20180810021444.14014-11-jgg@ziepe.ca> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180810021444.14014-1-jgg@ziepe.ca> References: <20180810021444.14014-1-jgg@ziepe.ca> Sender: linux-rdma-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-rdma@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Jason Gunthorpe Now that the ioctl path and uobjects are converted to use uverbs_api, it is now safe to remove the disassociation protection from the common ioctl code. This completes the work to make destroy functions continue to work even after device disassociation. Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/uverbs_ioctl.c | 42 ++++++++------------------ 1 file changed, 13 insertions(+), 29 deletions(-) diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c index e98dad4ca89826..0d26263df4ff1d 100644 --- a/drivers/infiniband/core/uverbs_ioctl.c +++ b/drivers/infiniband/core/uverbs_ioctl.c @@ -404,7 +404,6 @@ static int bundle_destroy(struct bundle_priv *pbundle, bool commit) kvfree(tmp); } - return ret; } @@ -471,47 +470,32 @@ static int ib_uverbs_cmd_verbs(struct ib_uverbs_file *ufile, return ret; } -#define IB_UVERBS_MAX_CMD_SZ 4096 - long ib_uverbs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct ib_uverbs_file *file = filp->private_data; struct ib_uverbs_ioctl_hdr __user *user_hdr = (struct ib_uverbs_ioctl_hdr __user *)arg; struct ib_uverbs_ioctl_hdr hdr; - struct ib_device *ib_dev; int srcu_key; - long err; + int err; - srcu_key = srcu_read_lock(&file->device->disassociate_srcu); - ib_dev = srcu_dereference(file->device->ib_dev, - &file->device->disassociate_srcu); - if (!ib_dev) { - err = -EIO; - goto out; - } + if (unlikely(cmd != RDMA_VERBS_IOCTL)) + return -ENOIOCTLCMD; - if (cmd == RDMA_VERBS_IOCTL) { - err = copy_from_user(&hdr, user_hdr, sizeof(hdr)); + err = copy_from_user(&hdr, user_hdr, sizeof(hdr)); + if (err) + return -EFAULT; - if (err || hdr.length > IB_UVERBS_MAX_CMD_SZ || - hdr.length != sizeof(hdr) + hdr.num_attrs * sizeof(struct ib_uverbs_attr)) { - err = -EINVAL; - goto out; - } + if (hdr.length > PAGE_SIZE || + hdr.length != struct_size(&hdr, attrs, hdr.num_attrs)) + return -EINVAL; - if (hdr.reserved1 || hdr.reserved2) { - err = -EPROTONOSUPPORT; - goto out; - } + if (hdr.reserved1 || hdr.reserved2) + return -EPROTONOSUPPORT; - err = ib_uverbs_cmd_verbs(file, &hdr, user_hdr->attrs); - } else { - err = -ENOIOCTLCMD; - } -out: + srcu_key = srcu_read_lock(&file->device->disassociate_srcu); + err = ib_uverbs_cmd_verbs(file, &hdr, user_hdr->attrs); srcu_read_unlock(&file->device->disassociate_srcu, srcu_key); - return err; }