From patchwork Mon Mar 6 15:58:38 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 64821 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:5915:0:0:0:0:0 with SMTP id v21csp1922615wrd; Mon, 6 Mar 2023 08:03:23 -0800 (PST) X-Google-Smtp-Source: AK7set9cY3T/VNUI4pUnckrrOt8WWFvPN6uL+WHgzkCSeQFxSwof1/FLMra6on9BkRby9qFG7mqO X-Received: by 2002:a17:902:f7c7:b0:19c:da68:337b with SMTP id h7-20020a170902f7c700b0019cda68337bmr9546217plw.16.1678118603087; Mon, 06 Mar 2023 08:03:23 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1678118603; cv=none; d=google.com; s=arc-20160816; b=ho2EuEr7PyJkWMii9/c2WZuNShZzaLHdtsATD4gXQlRAJhTJ48NoY+MUcHgMGUgnfC tde/CVU3aJbVPKDliVdhs7GpEGSzB9vQJ1eoJtV24CtcxC82D964r6aeAwDn+eYrN0Wp rCj+48wXPt9yEJxr+70wdu+zLfSED6POo/Tb0s5IijmCOW8kruTOFnWy16DILmbUUZVS azqMmabyiCdYCsqd+C36MJVgHMuCnNcVx4iFC8/iqtMm62nRPlhQu8L8T3OuYiKz50Pe xSILo8aGitWOHZVg8I1Ei31bHDR//xdRyZaMJiiyH3N3Em3X9tUKD6RIg8IEE9TJRkSP Q1xw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature:dkim-signature; bh=RzHUCgyDVd1/vFJIVF/yHXdWWow6tO5+rSrZEBgBa/c=; b=oGkrdfIRFu13Y07TrVfDEyFSi6/EF0INNRA6d546q8A6It9ev8WzguEHsa7Cu0KV6Y Di5LobGVBrH8z5a7L2kk0KjgME0UwLvXyrPBD1fTJ8rZUk1i7COvoiuUBA2ZcGS9lbs8 x4KN/SpRJKxLtSZEYfDPmF/28Bdmc2dUwj6bBGV/7pdEJpakDn5SpxQzFoN//3koZoAr ZKH862dEH2wjL0b3Pfaj86ks1Tls+QlkOziwsf1DfFNQfM19NRx8Np3sUhRDTjR3e+po zxyJf62d2VZxtRu1XA5FGDek3jW4R+QHBQgxtcL16no73MM7NFqHjIhLeSirBYXGwG29 tMCA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@suse.de header.s=susede2_rsa header.b=VyetxvZ3; dkim=neutral (no key) header.i=@suse.de header.s=susede2_ed25519 header.b=GVWq0zHJ; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=suse.de Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id kj5-20020a17090306c500b001968c61066esi8875792plb.493.2023.03.06.08.03.03; Mon, 06 Mar 2023 08:03:23 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@suse.de header.s=susede2_rsa header.b=VyetxvZ3; dkim=neutral (no key) header.i=@suse.de header.s=susede2_ed25519 header.b=GVWq0zHJ; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=suse.de Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230434AbjCFQAo (ORCPT + 99 others); Mon, 6 Mar 2023 11:00:44 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41164 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230215AbjCFQA1 (ORCPT ); Mon, 6 Mar 2023 11:00:27 -0500 Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4661F25E09; Mon, 6 Mar 2023 08:00:26 -0800 (PST) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id D8AA72236F; Mon, 6 Mar 2023 16:00:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1678118424; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=RzHUCgyDVd1/vFJIVF/yHXdWWow6tO5+rSrZEBgBa/c=; b=VyetxvZ3ORexkxsuy9ptjw4e5iKIRS6AtzM3owyFLAQtiKrEKVQ9OG/cR6tK3PRgu1sNRe 2i3fZa2NJQBfLehZT3TKF3vcS32wpe219jE6y7l2fYNtJL+CviITlg2rD8ml+KodbdSuUd J1rNF4avXuY8yMuQ5WLGlmqgrbGFNjg= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1678118424; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=RzHUCgyDVd1/vFJIVF/yHXdWWow6tO5+rSrZEBgBa/c=; b=GVWq0zHJQbDPUNtYod/JQRKJmUcCoDbJRr7rn6i6IULWpMZKZlGML5Vr/quQhC851qTigA zZ/vYCslR9zsLOCQ== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 8332F13A6A; Mon, 6 Mar 2023 16:00:24 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id EA9EHxgOBmQ/PwAAMHmgww (envelope-from ); Mon, 06 Mar 2023 16:00:24 +0000 From: Thomas Zimmermann To: deller@gmx.de, paulus@samba.org, benh@kernel.crashing.org, linux@armlinux.org.uk, pjones@redhat.com, timur@kernel.org, adaplas@gmail.com, s.hauer@pengutronix.de, shawnguo@kernel.org, mbroemme@libmpq.org, thomas@winischhofer.net, James.Bottomley@HansenPartnership.com, spock@gentoo.org, sudipm.mukherjee@gmail.com, teddy.wang@siliconmotion.com, geert+renesas@glider.be, corbet@lwn.net Cc: linux-fbdev@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Thomas Zimmermann Subject: [PATCH 01/99] lib: Add option iterator Date: Mon, 6 Mar 2023 16:58:38 +0100 Message-Id: <20230306160016.4459-2-tzimmermann@suse.de> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230306160016.4459-1-tzimmermann@suse.de> References: <20230306160016.4459-1-tzimmermann@suse.de> MIME-Version: 1.0 X-Spam-Status: No, score=-4.4 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_MED,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1759634892442311230?= X-GMAIL-MSGID: =?utf-8?q?1759634892442311230?= Add struct option_iter and helpers that walk over individual options of an option string. Add documentation. Kernel parameters often have the format of param=opt1,opt2:val,opt3 where the option string contains a number of comma-separated options. Drivers usually use strsep() in a loop to extract individual options from the string. Each call to strsep() modifies the given string, so callers have to duplicate kernel parameters that are to be parsed multiple times. The new struct option_iter and its helpers wrap this code behind a clean interface. Drivers can iterate over the options without having to know the details of the option-string format. The iterator handles string memory internally without modifying the original options. Signed-off-by: Thomas Zimmermann --- Documentation/core-api/kernel-api.rst | 9 +++ include/linux/cmdline.h | 29 ++++++++ lib/Makefile | 2 +- lib/cmdline_iter.c | 97 +++++++++++++++++++++++++++ 4 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 include/linux/cmdline.h create mode 100644 lib/cmdline_iter.c diff --git a/Documentation/core-api/kernel-api.rst b/Documentation/core-api/kernel-api.rst index 62f961610773..cdc7ba8decf9 100644 --- a/Documentation/core-api/kernel-api.rst +++ b/Documentation/core-api/kernel-api.rst @@ -93,9 +93,18 @@ Bitmap Operations Command-line Parsing -------------------- +.. kernel-doc:: lib/cmdline_iter.c + :doc: overview + .. kernel-doc:: lib/cmdline.c :export: +.. kernel-doc:: lib/cmdline_iter.c + :export: + +.. kernel-doc:: include/linux/cmdline.h + :internal: + Sorting ------- diff --git a/include/linux/cmdline.h b/include/linux/cmdline.h new file mode 100644 index 000000000000..5d7e648e98a5 --- /dev/null +++ b/include/linux/cmdline.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef LINUX_CMDLINE_H +#define LINUX_CMDLINE_H + +/** + * struct option_iter - Iterates over string of kernel or module options + */ +struct option_iter { + char *optbuf; + char *next_opt; +}; + +void option_iter_init(struct option_iter *iter, const char *options); +void option_iter_release(struct option_iter *iter); +const char *option_iter_incr(struct option_iter *iter); + +/** + * option_iter_next - Loop condition to move over options + * @iter_: the iterator + * @opt_: the name of the option variable + * + * Iterates over option strings as part of a while loop and + * stores the current option in opt_. + */ +#define option_iter_next(iter_, opt_) \ + (((opt_) = option_iter_incr(iter_)) != NULL) + +#endif diff --git a/lib/Makefile b/lib/Makefile index 4d9461bfea42..829ea6647d7a 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -27,7 +27,7 @@ KASAN_SANITIZE_string.o := n CFLAGS_string.o += -fno-stack-protector endif -lib-y := ctype.o string.o vsprintf.o cmdline.o \ +lib-y := ctype.o string.o vsprintf.o cmdline.o cmdline_iter.o \ rbtree.o radix-tree.o timerqueue.o xarray.o \ maple_tree.o idr.o extable.o irq_regs.o argv_split.o \ flex_proportions.o ratelimit.o show_mem.o \ diff --git a/lib/cmdline_iter.c b/lib/cmdline_iter.c new file mode 100644 index 000000000000..d9371dfea08b --- /dev/null +++ b/lib/cmdline_iter.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include + +/** + * DOC: overview + * + * A kernel parameter's option string can contain multiple comma-separated + * options. Modules can parse an option string with struct &option_iter and + * its helpers. After obtaining the string, initialize and instance of the + * option iterator and loop iver its content as show below. + * + * .. code-block:: c + * + * const char *options = ...; // provided option string + * + * struct option_iter iter; + * const char *opt; + * + * option_iter_init(&iter, options); + * + * while (option_iter_next(&iter, &opt)) { + * if (!strcmp(opt, "foo")) + * ... + * else (strcmp(opt, "bar")) + * ... + * else + * pr_warn("unknown option %s\n", opt); + * } + * + * option_iter_release(&iter); + * + * The call to option_iter_init() initializes the iterator instance + * from the option string. The while loop walks over the individual + * options in the sting and returns each in the second argument. The + * returned memory is owned by the iterator instance and callers may + * not modify or free it. The call to option_iter_release() frees all + * resources of the iterator. This process does not modify the original + * option string. If the option string contains an empty option (i.e., + * two commas next to each other), option_iter_next() skips the empty + * option automatically. + */ + +/** + * option_iter_init - Initializes an option iterator + * @iter: the iterator to initialize + * @options: the options string + */ +void option_iter_init(struct option_iter *iter, const char *options) +{ + if (options && *options) + iter->optbuf = kstrdup(options, GFP_KERNEL); // can be NULL + else + iter->optbuf = NULL; + iter->next_opt = iter->optbuf; +} +EXPORT_SYMBOL(option_iter_init); + +/** + * option_iter_release - Releases an option iterator's resources + * @iter: the iterator + */ +void option_iter_release(struct option_iter *iter) +{ + kfree(iter->optbuf); + iter->next_opt = NULL; +} +EXPORT_SYMBOL(option_iter_release); + +/** + * option_iter_incr - Return current option and advance to the next + * @iter: the iterator + * + * Returns: + * The current option string, or NULL if there are no more options. + */ +const char *option_iter_incr(struct option_iter *iter) +{ + char *opt; + + if (!iter->next_opt) { // can be OK if kstrdup failed + if (iter->optbuf) // iter has already been released; logic error + pr_err("Incrementing option iterator without string\n"); + return NULL; + } + + do { + opt = strsep(&iter->next_opt, ","); + if (!opt) + return NULL; + } while (!*opt); // found empty option string, try next + + return opt; +} +EXPORT_SYMBOL(option_iter_incr);