From patchwork Thu Nov 26 23:32:54 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Weinberger X-Patchwork-Id: 11934917 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id DB678C63777 for ; Thu, 26 Nov 2020 23:34:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B291621D1A for ; Thu, 26 Nov 2020 23:34:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2391960AbgKZXdk (ORCPT ); Thu, 26 Nov 2020 18:33:40 -0500 Received: from lilium.sigma-star.at ([109.75.188.150]:55286 "EHLO lilium.sigma-star.at" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2391953AbgKZXdk (ORCPT ); Thu, 26 Nov 2020 18:33:40 -0500 Received: from localhost (localhost [127.0.0.1]) by lilium.sigma-star.at (Postfix) with ESMTP id 781C518191062; Fri, 27 Nov 2020 00:33:38 +0100 (CET) Received: from lilium.sigma-star.at ([127.0.0.1]) by localhost (lilium.sigma-star.at [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id cF12J7oxYFjU; Fri, 27 Nov 2020 00:33:38 +0100 (CET) Received: from lilium.sigma-star.at ([127.0.0.1]) by localhost (lilium.sigma-star.at [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id JpRn7f_UXNiF; Fri, 27 Nov 2020 00:33:38 +0100 (CET) From: Richard Weinberger To: miklos@szeredi.hu Cc: miquel.raynal@bootlin.com, vigneshr@ti.com, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, Richard Weinberger Subject: [PATCH 1/7] fuse: Export fuse_simple_request Date: Fri, 27 Nov 2020 00:32:54 +0100 Message-Id: <20201126233300.10714-2-richard@nod.at> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20201126233300.10714-1-richard@nod.at> References: <20201126233300.10714-1-richard@nod.at> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org MUSE will use this function to issue requests, so export it. Signed-off-by: Richard Weinberger --- fs/fuse/dev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 588f8d1240aa..8b7209537683 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -522,6 +522,7 @@ ssize_t fuse_simple_request(struct fuse_mount *fm, struct fuse_args *args) return ret; } +EXPORT_SYMBOL_GPL(fuse_simple_request); static bool fuse_request_queue_background(struct fuse_req *req) { From patchwork Thu Nov 26 23:32:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Weinberger X-Patchwork-Id: 11934913 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3ACB6C83010 for ; Thu, 26 Nov 2020 23:33:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 20C432145D for ; Thu, 26 Nov 2020 23:33:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2392001AbgKZXdy (ORCPT ); Thu, 26 Nov 2020 18:33:54 -0500 Received: from lilium.sigma-star.at ([109.75.188.150]:55308 "EHLO lilium.sigma-star.at" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2391954AbgKZXdl (ORCPT ); Thu, 26 Nov 2020 18:33:41 -0500 Received: from localhost (localhost [127.0.0.1]) by lilium.sigma-star.at (Postfix) with ESMTP id DBD311816C728; Fri, 27 Nov 2020 00:33:38 +0100 (CET) Received: from lilium.sigma-star.at ([127.0.0.1]) by localhost (lilium.sigma-star.at [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id 1vN-nVJd0zxn; Fri, 27 Nov 2020 00:33:38 +0100 (CET) Received: from lilium.sigma-star.at ([127.0.0.1]) by localhost (lilium.sigma-star.at [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id vmeUVo1kcicr; Fri, 27 Nov 2020 00:33:38 +0100 (CET) From: Richard Weinberger To: miklos@szeredi.hu Cc: miquel.raynal@bootlin.com, vigneshr@ti.com, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, Richard Weinberger Subject: [PATCH 2/7] fuse: Export IO helpers Date: Fri, 27 Nov 2020 00:32:55 +0100 Message-Id: <20201126233300.10714-3-richard@nod.at> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20201126233300.10714-1-richard@nod.at> References: <20201126233300.10714-1-richard@nod.at> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org MUSE will use this functions in its IO path, so export them. Signed-off-by: Richard Weinberger --- fs/fuse/file.c | 16 +++------------- fs/fuse/fuse_i.h | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index c03034e8c152..ed91ca8b1203 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -20,8 +20,8 @@ #include #include -static struct page **fuse_pages_alloc(unsigned int npages, gfp_t flags, - struct fuse_page_desc **desc) +struct page **fuse_pages_alloc(unsigned int npages, gfp_t flags, + struct fuse_page_desc **desc) { struct page **pages; @@ -31,6 +31,7 @@ static struct page **fuse_pages_alloc(unsigned int npages, gfp_t flags, return pages; } +EXPORT_SYMBOL_GPL(fuse_pages_alloc); static int fuse_send_open(struct fuse_mount *fm, u64 nodeid, struct file *file, int opcode, struct fuse_open_out *outargp) @@ -1338,17 +1339,6 @@ static inline void fuse_page_descs_length_init(struct fuse_page_desc *descs, descs[i].length = PAGE_SIZE - descs[i].offset; } -static inline unsigned long fuse_get_user_addr(const struct iov_iter *ii) -{ - return (unsigned long)ii->iov->iov_base + ii->iov_offset; -} - -static inline size_t fuse_get_frag_size(const struct iov_iter *ii, - size_t max_size) -{ - return min(iov_iter_single_seg_count(ii), max_size); -} - static int fuse_get_user_pages(struct fuse_args_pages *ap, struct iov_iter *ii, size_t *nbytesp, int write, unsigned int max_pages) diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index d51598017d13..d23954908610 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -31,6 +31,7 @@ #include #include #include +#include /** Default max number of pages that can be used in a single read request */ #define FUSE_DEFAULT_MAX_PAGES_PER_REQ 32 @@ -858,6 +859,17 @@ static inline u64 fuse_get_attr_version(struct fuse_conn *fc) return atomic64_read(&fc->attr_version); } +static inline unsigned long fuse_get_user_addr(const struct iov_iter *ii) +{ + return (unsigned long)ii->iov->iov_base + ii->iov_offset; +} + +static inline size_t fuse_get_frag_size(const struct iov_iter *ii, + size_t max_size) +{ + return min(iov_iter_single_seg_count(ii), max_size); +} + /** Device operations */ extern const struct file_operations fuse_dev_operations; @@ -1210,4 +1222,8 @@ void fuse_dax_inode_cleanup(struct inode *inode); bool fuse_dax_check_alignment(struct fuse_conn *fc, unsigned int map_alignment); void fuse_dax_cancel_work(struct fuse_conn *fc); +/* file.c */ +struct page **fuse_pages_alloc(unsigned int npages, gfp_t flags, + struct fuse_page_desc **desc); + #endif /* _FS_FUSE_I_H */ From patchwork Thu Nov 26 23:32:56 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Weinberger X-Patchwork-Id: 11934915 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id EFA00C64E90 for ; Thu, 26 Nov 2020 23:33:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AE6B822258 for ; Thu, 26 Nov 2020 23:33:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2391981AbgKZXdm (ORCPT ); Thu, 26 Nov 2020 18:33:42 -0500 Received: from lilium.sigma-star.at ([109.75.188.150]:55330 "EHLO lilium.sigma-star.at" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2391955AbgKZXdl (ORCPT ); Thu, 26 Nov 2020 18:33:41 -0500 Received: from localhost (localhost [127.0.0.1]) by lilium.sigma-star.at (Postfix) with ESMTP id 5647B180C6DDC; Fri, 27 Nov 2020 00:33:39 +0100 (CET) Received: from lilium.sigma-star.at ([127.0.0.1]) by localhost (lilium.sigma-star.at [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id Be9LC0iaFSmU; Fri, 27 Nov 2020 00:33:38 +0100 (CET) Received: from lilium.sigma-star.at ([127.0.0.1]) by localhost (lilium.sigma-star.at [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id OF5vAhagXaIq; Fri, 27 Nov 2020 00:33:38 +0100 (CET) From: Richard Weinberger To: miklos@szeredi.hu Cc: miquel.raynal@bootlin.com, vigneshr@ti.com, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, Richard Weinberger Subject: [PATCH 3/7] fuse: Make cuse_parse_one a common helper Date: Fri, 27 Nov 2020 00:32:56 +0100 Message-Id: <20201126233300.10714-4-richard@nod.at> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20201126233300.10714-1-richard@nod.at> References: <20201126233300.10714-1-richard@nod.at> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org This function will be used by MUSE too, let's share it. Signed-off-by: Richard Weinberger --- fs/fuse/Kconfig | 4 +++ fs/fuse/Makefile | 1 + fs/fuse/cuse.c | 58 +-------------------------------------- fs/fuse/fuse_i.h | 2 ++ fs/fuse/helper.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 78 insertions(+), 57 deletions(-) create mode 100644 fs/fuse/helper.c diff --git a/fs/fuse/Kconfig b/fs/fuse/Kconfig index 40ce9a1c12e5..9c8cc1e7b3a5 100644 --- a/fs/fuse/Kconfig +++ b/fs/fuse/Kconfig @@ -18,9 +18,13 @@ config FUSE_FS If you want to develop a userspace FS, or if you want to use a filesystem based on FUSE, answer Y or M. +config FUSE_HELPER + def_bool n + config CUSE tristate "Character device in Userspace support" depends on FUSE_FS + select FUSE_HELPER help This FUSE extension allows character devices to be implemented in userspace. diff --git a/fs/fuse/Makefile b/fs/fuse/Makefile index 8c7021fb2cd4..7a5768cce6be 100644 --- a/fs/fuse/Makefile +++ b/fs/fuse/Makefile @@ -9,5 +9,6 @@ obj-$(CONFIG_VIRTIO_FS) += virtiofs.o fuse-y := dev.o dir.o file.o inode.o control.o xattr.o acl.o readdir.o fuse-$(CONFIG_FUSE_DAX) += dax.o +fuse-$(CONFIG_FUSE_HELPER) += helper.o virtiofs-y := virtio_fs.o diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c index 45082269e698..fe8515844064 100644 --- a/fs/fuse/cuse.c +++ b/fs/fuse/cuse.c @@ -199,62 +199,6 @@ struct cuse_devinfo { const char *name; }; -/** - * cuse_parse_one - parse one key=value pair - * @pp: i/o parameter for the current position - * @end: points to one past the end of the packed string - * @keyp: out parameter for key - * @valp: out parameter for value - * - * *@pp points to packed strings - "key0=val0\0key1=val1\0" which ends - * at @end - 1. This function parses one pair and set *@keyp to the - * start of the key and *@valp to the start of the value. Note that - * the original string is modified such that the key string is - * terminated with '\0'. *@pp is updated to point to the next string. - * - * RETURNS: - * 1 on successful parse, 0 on EOF, -errno on failure. - */ -static int cuse_parse_one(char **pp, char *end, char **keyp, char **valp) -{ - char *p = *pp; - char *key, *val; - - while (p < end && *p == '\0') - p++; - if (p == end) - return 0; - - if (end[-1] != '\0') { - pr_err("info not properly terminated\n"); - return -EINVAL; - } - - key = val = p; - p += strlen(p); - - if (valp) { - strsep(&val, "="); - if (!val) - val = key + strlen(key); - key = strstrip(key); - val = strstrip(val); - } else - key = strstrip(key); - - if (!strlen(key)) { - pr_err("zero length info key specified\n"); - return -EINVAL; - } - - *pp = p; - *keyp = key; - if (valp) - *valp = val; - - return 1; -} - /** * cuse_parse_dev_info - parse device info * @p: device info string @@ -275,7 +219,7 @@ static int cuse_parse_devinfo(char *p, size_t len, struct cuse_devinfo *devinfo) int rc; while (true) { - rc = cuse_parse_one(&p, end, &key, &val); + rc = fuse_kv_parse_one(&p, end, &key, &val); if (rc < 0) return rc; if (!rc) diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index d23954908610..8eba93cd8fb8 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1225,5 +1225,7 @@ void fuse_dax_cancel_work(struct fuse_conn *fc); /* file.c */ struct page **fuse_pages_alloc(unsigned int npages, gfp_t flags, struct fuse_page_desc **desc); +/* helper.c */ +int fuse_kv_parse_one(char **pp, char *end, char **keyp, char **valp); #endif /* _FS_FUSE_I_H */ diff --git a/fs/fuse/helper.c b/fs/fuse/helper.c new file mode 100644 index 000000000000..0c828daf8e8a --- /dev/null +++ b/fs/fuse/helper.c @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Helper functions used by CUSE and MUSE + * + * Copyright (C) 2008-2009 SUSE Linux Products GmbH + * Copyright (C) 2008-2009 Tejun Heo + * + */ + +#include +#include + +#include "fuse_i.h" + +/** + * fuse_kv_parse_one - parse one key=value pair + * @pp: i/o parameter for the current position + * @end: points to one past the end of the packed string + * @keyp: out parameter for key + * @valp: out parameter for value + * + * *@pp points to packed strings - "key0=val0\0key1=val1\0" which ends + * at @end - 1. This function parses one pair and set *@keyp to the + * start of the key and *@valp to the start of the value. Note that + * the original string is modified such that the key string is + * terminated with '\0'. *@pp is updated to point to the next string. + * + * RETURNS: + * 1 on successful parse, 0 on EOF, -errno on failure. + */ +int fuse_kv_parse_one(char **pp, char *end, char **keyp, char **valp) +{ + char *p = *pp; + char *key, *val; + + while (p < end && *p == '\0') + p++; + if (p == end) + return 0; + + if (end[-1] != '\0') { + pr_err("info not properly terminated\n"); + return -EINVAL; + } + + key = val = p; + p += strlen(p); + + if (valp) { + strsep(&val, "="); + if (!val) + val = key + strlen(key); + key = strstrip(key); + val = strstrip(val); + } else + key = strstrip(key); + + if (!strlen(key)) { + pr_err("zero length info key specified\n"); + return -EINVAL; + } + + *pp = p; + *keyp = key; + if (valp) + *valp = val; + + return 1; +} +EXPORT_SYMBOL_GPL(fuse_kv_parse_one); From patchwork Thu Nov 26 23:32:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Weinberger X-Patchwork-Id: 11934919 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0183EC64E75 for ; Thu, 26 Nov 2020 23:34:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id CA74D21D7E for ; Thu, 26 Nov 2020 23:34:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2391977AbgKZXdy (ORCPT ); Thu, 26 Nov 2020 18:33:54 -0500 Received: from lilium.sigma-star.at ([109.75.188.150]:55350 "EHLO lilium.sigma-star.at" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2391956AbgKZXdl (ORCPT ); Thu, 26 Nov 2020 18:33:41 -0500 Received: from localhost (localhost [127.0.0.1]) by lilium.sigma-star.at (Postfix) with ESMTP id 7F3AC1815EF9C; Fri, 27 Nov 2020 00:33:39 +0100 (CET) Received: from lilium.sigma-star.at ([127.0.0.1]) by localhost (lilium.sigma-star.at [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id huVm_zYbsoic; Fri, 27 Nov 2020 00:33:39 +0100 (CET) Received: from lilium.sigma-star.at ([127.0.0.1]) by localhost (lilium.sigma-star.at [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id jl_Vnuij2GT2; Fri, 27 Nov 2020 00:33:39 +0100 (CET) From: Richard Weinberger To: miklos@szeredi.hu Cc: miquel.raynal@bootlin.com, vigneshr@ti.com, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, Richard Weinberger Subject: [PATCH 4/7] mtd: Add MTD_MUSE flag Date: Fri, 27 Nov 2020 00:32:57 +0100 Message-Id: <20201126233300.10714-5-richard@nod.at> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20201126233300.10714-1-richard@nod.at> References: <20201126233300.10714-1-richard@nod.at> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org This flag will get set if an MTD is implemeted in userspace using MUSE. Signed-off-by: Richard Weinberger --- include/uapi/mtd/mtd-abi.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/mtd/mtd-abi.h b/include/uapi/mtd/mtd-abi.h index 65b9db936557..2ad2217e3a96 100644 --- a/include/uapi/mtd/mtd-abi.h +++ b/include/uapi/mtd/mtd-abi.h @@ -105,6 +105,7 @@ struct mtd_write_req { #define MTD_NO_ERASE 0x1000 /* No erase necessary */ #define MTD_POWERUP_LOCK 0x2000 /* Always locked after reset */ #define MTD_SLC_ON_MLC_EMULATION 0x4000 /* Emulate SLC behavior on MLC NANDs */ +#define MTD_MUSE 0x8000 /* This MTD is implemented in userspace */ /* Some common devices / combinations of capabilities */ #define MTD_CAP_ROM 0 From patchwork Thu Nov 26 23:32:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Weinberger X-Patchwork-Id: 11934905 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 43D19C64E7B for ; Thu, 26 Nov 2020 23:33:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 13AA52145D for ; Thu, 26 Nov 2020 23:33:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2391990AbgKZXdn (ORCPT ); Thu, 26 Nov 2020 18:33:43 -0500 Received: from lilium.sigma-star.at ([109.75.188.150]:55378 "EHLO lilium.sigma-star.at" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2391953AbgKZXdn (ORCPT ); Thu, 26 Nov 2020 18:33:43 -0500 Received: from localhost (localhost [127.0.0.1]) by lilium.sigma-star.at (Postfix) with ESMTP id EC98D181C88E5; Fri, 27 Nov 2020 00:33:39 +0100 (CET) Received: from lilium.sigma-star.at ([127.0.0.1]) by localhost (lilium.sigma-star.at [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id NUbqF_zWrq22; Fri, 27 Nov 2020 00:33:39 +0100 (CET) Received: from lilium.sigma-star.at ([127.0.0.1]) by localhost (lilium.sigma-star.at [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id QEwXlqxG2Uc3; Fri, 27 Nov 2020 00:33:39 +0100 (CET) From: Richard Weinberger To: miklos@szeredi.hu Cc: miquel.raynal@bootlin.com, vigneshr@ti.com, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, Richard Weinberger Subject: [PATCH 5/7] fuse: Add MUSE specific defines FUSE interface Date: Fri, 27 Nov 2020 00:32:58 +0100 Message-Id: <20201126233300.10714-6-richard@nod.at> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20201126233300.10714-1-richard@nod.at> References: <20201126233300.10714-1-richard@nod.at> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org Raise the FUSE API minor version to 33 and add all MUSE specific operations and data structures. MUSE_INIT: Initialize a new connection and install the MTD MUSE_ERASE: Erase a block MUSE_READ: Read a page MUSE_WRITE: Write a page MUSE_MARKBAD: Mark a block as bad MUSE_ISBAD: Check whether a block is bad MUSE_SYNC: Flush all cached data Signed-off-by: Richard Weinberger --- include/uapi/linux/fuse.h | 73 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index 7233502ea991..2f7cbe5ce434 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -175,6 +175,10 @@ * * 7.32 * - add flags to fuse_attr, add FUSE_ATTR_SUBMOUNT, add FUSE_SUBMOUNTS + * + * 7.33 + * - add support for MUSE: MUSE_INIT, MUSE_ERASE, MUSE_READ, MUSE_WRITE, + * MUSE_MARKBAD, MUSE_ISBAD and MUSE_SYNC */ #ifndef _LINUX_FUSE_H @@ -210,7 +214,7 @@ #define FUSE_KERNEL_VERSION 7 /** Minor version number of this interface */ -#define FUSE_KERNEL_MINOR_VERSION 32 +#define FUSE_KERNEL_MINOR_VERSION 33 /** The node ID of the root inode */ #define FUSE_ROOT_ID 1 @@ -483,6 +487,15 @@ enum fuse_opcode { /* CUSE specific operations */ CUSE_INIT = 4096, + /* MUSE specific operations */ + MUSE_INIT = 8192, + MUSE_ERASE = 8193, + MUSE_READ = 8194, + MUSE_WRITE = 8195, + MUSE_MARKBAD = 8196, + MUSE_ISBAD = 8197, + MUSE_SYNC = 8198, + /* Reserved opcodes: helpful to detect structure endian-ness */ CUSE_INIT_BSWAP_RESERVED = 1048576, /* CUSE_INIT << 8 */ FUSE_INIT_BSWAP_RESERVED = 436207616, /* FUSE_INIT << 24 */ @@ -936,4 +949,62 @@ struct fuse_removemapping_one { #define FUSE_REMOVEMAPPING_MAX_ENTRY \ (PAGE_SIZE / sizeof(struct fuse_removemapping_one)) +#define MUSE_INIT_INFO_MAX 4096 + +struct muse_init_in { + uint32_t fuse_major; + uint32_t fuse_minor; +}; + +struct muse_init_out { + uint32_t fuse_major; + uint32_t fuse_minor; + uint32_t max_read; + uint32_t max_write; +}; + +struct muse_erase_in { + uint64_t addr; + uint64_t len; +}; + +struct muse_read_in { + uint64_t dataaddr; + uint64_t datalen; + uint32_t flags; + uint32_t padding; +}; + +struct muse_read_out { + uint64_t datalen; + uint32_t soft_error; + uint32_t padding; +}; + +struct muse_write_in { + uint64_t dataaddr; + uint64_t datalen; + uint32_t flags; + uint32_t padding; +}; + +struct muse_write_out { + uint64_t datalen; + uint32_t soft_error; + uint32_t padding; +}; + +struct muse_markbad_in { + uint64_t addr; +}; + +struct muse_isbad_in { + uint64_t addr; +}; + +struct muse_isbad_out { + uint32_t result; + uint32_t padding; +}; + #endif /* _LINUX_FUSE_H */ From patchwork Thu Nov 26 23:32:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Weinberger X-Patchwork-Id: 11934909 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C345CC71155 for ; Thu, 26 Nov 2020 23:33:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9461921D91 for ; Thu, 26 Nov 2020 23:33:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2403983AbgKZXdr (ORCPT ); Thu, 26 Nov 2020 18:33:47 -0500 Received: from lilium.sigma-star.at ([109.75.188.150]:55398 "EHLO lilium.sigma-star.at" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2391977AbgKZXdr (ORCPT ); Thu, 26 Nov 2020 18:33:47 -0500 Received: from localhost (localhost [127.0.0.1]) by lilium.sigma-star.at (Postfix) with ESMTP id 69AA9181C8918; Fri, 27 Nov 2020 00:33:41 +0100 (CET) Received: from lilium.sigma-star.at ([127.0.0.1]) by localhost (lilium.sigma-star.at [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id y0WI_39iVq3Y; Fri, 27 Nov 2020 00:33:40 +0100 (CET) Received: from lilium.sigma-star.at ([127.0.0.1]) by localhost (lilium.sigma-star.at [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id 4muHbyB312yT; Fri, 27 Nov 2020 00:33:39 +0100 (CET) From: Richard Weinberger To: miklos@szeredi.hu Cc: miquel.raynal@bootlin.com, vigneshr@ti.com, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, Richard Weinberger Subject: [PATCH 6/7] fuse: Implement MUSE: MTD in userspace Date: Fri, 27 Nov 2020 00:32:59 +0100 Message-Id: <20201126233300.10714-7-richard@nod.at> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20201126233300.10714-1-richard@nod.at> References: <20201126233300.10714-1-richard@nod.at> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org MUSE allows implementing a MTD in userspace. So far userspace has control over mtd_read, mtd_write, mtd_erase, mtd_block_isbad, mtd_block_markbad, and mtd_sync. It can also set the following MTD parameters: name, flags, site, writesize and erasesize. That way advanced simulators for many type of flashes can be implemented in userspace. Signed-off-by: Richard Weinberger --- fs/fuse/Kconfig | 11 + fs/fuse/Makefile | 1 + fs/fuse/muse.c | 730 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 742 insertions(+) create mode 100644 fs/fuse/muse.c diff --git a/fs/fuse/Kconfig b/fs/fuse/Kconfig index 9c8cc1e7b3a5..2fc63dc18a53 100644 --- a/fs/fuse/Kconfig +++ b/fs/fuse/Kconfig @@ -56,3 +56,14 @@ config FUSE_DAX If you want to allow mounting a Virtio Filesystem with the "dax" option, answer Y. + +config MUSE + tristate "Memory Technology Device (MTD) in Userspace support" + depends on FUSE_FS + select FUSE_HELPER + select MTD + help + This FUSE extension allows an MTD to be implemented in userspace. + + If you want to develop or use a userspace MTD based on MUSE, + answer Y or M. diff --git a/fs/fuse/Makefile b/fs/fuse/Makefile index 7a5768cce6be..67a7af3fb047 100644 --- a/fs/fuse/Makefile +++ b/fs/fuse/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_FUSE_FS) += fuse.o obj-$(CONFIG_CUSE) += cuse.o obj-$(CONFIG_VIRTIO_FS) += virtiofs.o +obj-$(CONFIG_MUSE) += muse.o fuse-y := dev.o dir.o file.o inode.o control.o xattr.o acl.o readdir.o fuse-$(CONFIG_FUSE_DAX) += dax.o diff --git a/fs/fuse/muse.c b/fs/fuse/muse.c new file mode 100644 index 000000000000..b947f5aa2e1c --- /dev/null +++ b/fs/fuse/muse.c @@ -0,0 +1,730 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MUSE: MTD in userspace + * Copyright (C) 2020 sigma star gmbh + * Author: Richard Weinberger + */ + +#define pr_fmt(fmt) "MUSE: " fmt + +#include +#include +#include +#include +#include + +#include "fuse_i.h" + +static struct file_operations muse_ctrl_fops; + +/* + * struct muse_conn - MUSE connection object. + * + * @fm: FUSE mount object. + * @fc: FUSE connection object. + * @mtd: MTD object. + * @init_done: true when the MTD was registered. + * + * Describes a connection to a userspace server. + * Each connection implements a single MTD. + */ +struct muse_conn { + struct fuse_mount fm; + struct fuse_conn fc; + struct mtd_info mtd; + bool init_done; +}; + +struct muse_init_args { + struct fuse_args_pages ap; + struct muse_init_in in; + struct muse_init_out out; + struct page *page; + struct fuse_page_desc desc; +}; + +static void muse_fc_release(struct fuse_conn *fc) +{ + struct muse_conn *mc = container_of(fc, struct muse_conn, fc); + + kfree_rcu(mc, fc.rcu); +} + +static int muse_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + struct muse_conn *mc = mtd->priv; + struct fuse_mount *fm = &mc->fm; + struct muse_erase_in inarg; + FUSE_ARGS(args); + ssize_t ret; + + inarg.addr = instr->addr; + inarg.len = instr->len; + + args.opcode = MUSE_ERASE; + args.nodeid = FUSE_ROOT_ID; + args.in_numargs = 1; + args.in_args[0].size = sizeof(inarg); + args.in_args[0].value = &inarg; + + ret = fuse_simple_request(fm, &args); + if (ret < 0) + return ret; + + return 0; +} + +static int muse_mtd_markbad(struct mtd_info *mtd, loff_t addr) +{ + struct muse_conn *mc = mtd->priv; + struct fuse_mount *fm = &mc->fm; + struct muse_markbad_in inarg; + FUSE_ARGS(args); + ssize_t ret; + + inarg.addr = addr; + + args.opcode = MUSE_MARKBAD; + args.nodeid = FUSE_ROOT_ID; + args.in_numargs = 1; + args.in_args[0].size = sizeof(inarg); + args.in_args[0].value = &inarg; + + ret = fuse_simple_request(fm, &args); + if (ret < 0) + return ret; + + return 0; +} + +static int muse_mtd_isbad(struct mtd_info *mtd, loff_t addr) +{ + struct muse_conn *mc = mtd->priv; + struct fuse_mount *fm = &mc->fm; + struct muse_isbad_in inarg; + struct muse_isbad_out outarg; + FUSE_ARGS(args); + ssize_t ret; + + inarg.addr = addr; + + args.opcode = MUSE_ISBAD; + args.nodeid = FUSE_ROOT_ID; + args.in_numargs = 1; + args.in_args[0].size = sizeof(inarg); + args.in_args[0].value = &inarg; + args.out_numargs = 1; + args.out_args[0].size = sizeof(outarg); + args.out_args[0].value = &outarg; + + ret = fuse_simple_request(fm, &args); + if (ret < 0) + return ret; + + return outarg.result; +} + +static void muse_mtd_sync(struct mtd_info *mtd) +{ + struct muse_conn *mc = mtd->priv; + struct fuse_mount *fm = &mc->fm; + FUSE_ARGS(args); + + args.opcode = MUSE_SYNC; + args.nodeid = FUSE_ROOT_ID; + args.in_numargs = 0; + + fuse_simple_request(fm, &args); +} + +static ssize_t muse_send_write(struct fuse_args_pages *ap, struct fuse_mount *fm, + loff_t from, size_t count, int *soft_error) +{ + struct fuse_args *args = &ap->args; + ssize_t ret; + + struct muse_write_in in; + struct muse_write_out out; + + in.dataaddr = from; + in.datalen = count; + in.flags = 0; + args->opcode = MUSE_WRITE; + args->nodeid = FUSE_ROOT_ID; + args->in_numargs = 2; + args->in_args[0].size = sizeof(in); + args->in_args[0].value = ∈ + /* + * args->in_args[1].value was set in set_ap_inout_bufs() + */ + args->in_args[1].size = count; + args->out_numargs = 1; + args->out_args[0].size = sizeof(out); + args->out_args[0].value = &out; + + ret = fuse_simple_request(fm, &ap->args); + if (ret < 0) + goto out; + + ret = out.datalen; + *soft_error = out.soft_error; + +out: + return ret; +} + +static ssize_t muse_send_read(struct fuse_args_pages *ap, struct fuse_mount *fm, + loff_t from, size_t count, int *soft_error) +{ + struct fuse_args *args = &ap->args; + ssize_t ret; + + struct muse_read_in in; + struct muse_read_out out; + + in.dataaddr = from; + in.datalen = count; + in.flags = 0; + args->opcode = MUSE_READ; + args->nodeid = FUSE_ROOT_ID; + args->in_numargs = 1; + args->in_args[0].size = sizeof(in); + args->in_args[0].value = ∈ + args->out_argvar = true; + args->out_numargs = 2; + args->out_args[0].size = sizeof(out); + args->out_args[0].value = &out; + /* + * args->out_args[1].value was set in set_ap_inout_bufs() + */ + args->out_args[1].size = count; + + ret = fuse_simple_request(fm, &ap->args); + if (ret < 0) + goto out; + + ret = out.datalen; + *soft_error = out.soft_error; + +out: + return ret; +} + +/* + * set_ap_inout_bufs - Set in/out buffers for fuse args + * + * @ap: FUSE args pages object + * @iter: IOV iter which describes source/destination of the IO operation + * @count: Inputs the max amount of data we can process, + * outputs the amount of data @iter has left. + * @write: If non-zero, this is a write operation, read otherwise. + * + * This function takes a IOV iter object and sets up FUSE args pointer. + * Since in MTD all buffers are kernel memory we can directly use + * fuse_get_user_addr(). + */ +static void set_ap_inout_bufs(struct fuse_args_pages *ap, struct iov_iter *iter, + size_t *count, int write) +{ + unsigned long addr; + size_t frag_size; + + addr = fuse_get_user_addr(iter); + frag_size = fuse_get_frag_size(iter, *count); + + if (write) + ap->args.in_args[1].value = (void *)addr; + else + ap->args.out_args[1].value = (void *)addr; + + iov_iter_advance(iter, frag_size); + *count = frag_size; +} + +/* + * muse_do_io - MUSE main IO processing function. + * + * @mc: MUSE connection object. + * @ops: MTD read/write operation object. + * @pos: Where to start reading/writing on the MTD. + * @retcode: Outputs the return code for the MTD subsystem. + * @write: If non-zero, this is a write operation, read otherwise. + * + * This function is responsible for processing reads and writes to the MTD. + * It directly takes @pos and @ops from the MTD subsystem. + * All IO is synchronous and buffers provided by @ops have to be kernel memory. + * Each MUSE_READ/MUSE_WRITE operation is at most mtd->writebuffer long, + * such that the userspace server can assume that each operaion affects at most + * one page. + * The userspace server can inject also custom errors into the IO path, + * mostly -EUCLEAN to signal fixed bit-flips or -EBADMSG for uncorrectable + * bit-flips. + * + * It returns the amount of processed bytes and via @retcode the return code + * for the MTD subsystem. + */ +static ssize_t muse_do_io(struct muse_conn *mc, struct mtd_oob_ops *ops, + loff_t pos, int *retcode, int write) +{ + struct kvec iov = { .iov_base = ops->datbuf, .iov_len = ops->len }; + struct fuse_mount *fm = &mc->fm; + struct fuse_conn *fc = fm->fc; + size_t fc_max_io = write ? fc->max_write : fc->max_read; + size_t count; + size_t retlen = 0; + struct fuse_args_pages ap; + unsigned int max_pages; + int bitflips = 0; + int eccerrors = 0; + ssize_t ret = 0; + struct iov_iter iter; + + /* + * TODO: Implement OOB support + */ + if (ops->mode != MTD_OPS_PLACE_OOB || ops->ooblen) { + ret = -ENOTSUPP; + goto out; + } + + iov_iter_kvec(&iter, write ? WRITE : READ, &iov, 1, ops->len); + + /* + * A full page needs to fit into a single FUSE request. + */ + if (fc_max_io < mc->mtd.writebufsize) { + ret = -ENOBUFS; + goto out; + } + + count = iov_iter_count(&iter); + + max_pages = iov_iter_npages(&iter, fc->max_pages); + memset(&ap, 0, sizeof(ap)); + + ap.pages = fuse_pages_alloc(max_pages, GFP_KERNEL, &ap.descs); + if (!ap.pages) { + ret = -ENOMEM; + goto out; + } + + *retcode = 0; + + while (count) { + size_t nbytes = min_t(size_t, count, mc->mtd.writebufsize); + int soft_error; + + set_ap_inout_bufs(&ap, &iter, &nbytes, write); + + if (write) + ret = muse_send_write(&ap, fm, pos, nbytes, &soft_error); + else + ret = muse_send_read(&ap, fm, pos, nbytes, &soft_error); + + kfree(ap.pages); + ap.pages = NULL; + + if (ret < 0) { + iov_iter_revert(&iter, nbytes); + break; + } + + if (soft_error) { + /* + * Userspace wants to inject an error code. + */ + + if (write) { + /* + * For writes, take it as-is. + */ + ret = soft_error; + break; + } + + /* + * -EUCLEAN and -EBADMSG are special for reads + * in MTD, it expects from a device to return all + * requsted data even if there are (un)correctable errors. + * The upper layer, such as UBI, has to deal with them. + */ + if (soft_error == -EUCLEAN) { + bitflips++; + } else if (soft_error == -EBADMSG) { + eccerrors++; + } else { + ret = soft_error; + break; + } + } + + /* + * No short reads are allowed in MTD. + */ + if (ret != nbytes) { + iov_iter_revert(&iter, nbytes - ret); + ret = -EIO; + break; + } + + count -= ret; + retlen += ret; + pos += ret; + + if (count) { + max_pages = iov_iter_npages(&iter, fc->max_pages); + memset(&ap, 0, sizeof(ap)); + ap.pages = fuse_pages_alloc(max_pages, GFP_KERNEL, &ap.descs); + if (!ap.pages) + break; + } + } + + kfree(ap.pages); + + if (bitflips) + *retcode = -EUCLEAN; + if (eccerrors) + *retcode = -EBADMSG; + +out: + /* + * If ret is set, it must be a fatal error which overrides + * -EUCLEAN and -EBADMSG. + */ + if (ret < 0) + *retcode = ret; + + return retlen; +} + +static int muse_mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) +{ + struct muse_conn *mc = mtd->priv; + int retcode; + + ops->retlen = muse_do_io(mc, ops, from, &retcode, 0); + + return retcode; +} + +static int muse_mtd_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) +{ + struct muse_conn *mc = mtd->priv; + int retcode; + + ops->retlen = muse_do_io(mc, ops, to, &retcode, 1); + + return retcode; +} + +static int muse_mtd_get_device(struct mtd_info *mtd) +{ + struct muse_conn *mc = mtd->priv; + + fuse_conn_get(&mc->fc); + + return 0; +} + +static void muse_mtd_put_device(struct mtd_info *mtd) +{ + struct muse_conn *mc = mtd->priv; + + fuse_conn_put(&mc->fc); +} + +struct mtdreq { + const char *name; + struct mtd_info_user mi; +}; + +static int muse_parse_mtdreq(char *p, size_t len, struct mtd_info *mtd) +{ + struct mtdreq req = {}; + char *end = p + len; + char *key, *val; + int ret; + + for (;;) { + ret = fuse_kv_parse_one(&p, end, &key, &val); + if (ret < 0) + goto out; + if (!ret) + break; + + if (strcmp(key, "NAME") == 0) { + req.name = val; + } else if (strcmp(key, "TYPE") == 0) { + ret = kstrtoul(val, 10, &req.mi.type); + if (ret) + goto out; + } else if (strcmp(key, "FLAGS") == 0) { + ret = kstrtoul(val, 10, &req.mi.flags); + if (ret) + goto out; + } else if (strcmp(key, "SIZE") == 0) { + ret = kstrtoul(val, 10, &req.mi.size); + if (ret) + goto out; + } else if (strcmp(key, "WRITESIZE") == 0) { + ret = kstrtoul(val, 10, &req.mi.writesize); + if (ret) + goto out; + } else if (strcmp(key, "ERASESIZE") == 0) { + ret = kstrtoul(val, 10, &req.mi.erasesize); + if (ret) + goto out; + } else { + pr_warn("Ignoring unknown MTD param \"%s\"\n", key); + } + } + + ret = -EINVAL; + + if (!req.name) + goto out; + + if (!req.mi.size || !req.mi.writesize || !req.mi.erasesize) + goto out; + + if (req.mi.size % req.mi.writesize) + goto out; + + if (req.mi.size % req.mi.erasesize) + goto out; + + if (req.mi.flags & ~(MTD_WRITEABLE | MTD_BIT_WRITEABLE | MTD_NO_ERASE)) + goto out; + + /* + * MTD_ABSENT and MTD_UBIVOLUME and special, and can only be used by + * internal MTD drivers. Allowing userspace to emulate them asks for + * trouble. + */ + if (req.mi.type == MTD_ABSENT || req.mi.type == MTD_UBIVOLUME) + goto out; + + mtd->name = kstrdup(req.name, GFP_KERNEL); + if (!mtd->name) { + ret = -ENOMEM; + goto out; + } + + mtd->size = req.mi.size; + mtd->erasesize = req.mi.erasesize; + mtd->writesize = req.mi.writesize; + mtd->writebufsize = mtd->writesize; + mtd->type = req.mi.type; + mtd->flags = MTD_MUSE | req.mi.flags; + + ret = 0; +out: + return ret; +} + +static void muse_process_init_reply(struct fuse_mount *fm, + struct fuse_args *args, int error) +{ + struct fuse_conn *fc = fm->fc; + struct muse_init_args *mia = container_of(args, struct muse_init_args, ap.args); + struct muse_conn *mc = container_of(fc, struct muse_conn, fc); + struct fuse_args_pages *ap = &mia->ap; + struct muse_init_out *arg = &mia->out; + struct page *page = ap->pages[0]; + struct mtd_info *mtd = &mc->mtd; + int ret; + + if (error || arg->fuse_major != FUSE_KERNEL_VERSION || arg->fuse_minor < 33) + goto abort; + + fc->minor = arg->fuse_minor; + fc->max_read = max_t(unsigned int, arg->max_read, 4096); + fc->max_write = max_t(unsigned int, arg->max_write, 4096); + + ret = muse_parse_mtdreq(page_address(page), ap->args.out_args[1].size, mtd); + if (ret) + goto abort; + + mtd->_erase = muse_mtd_erase; + mtd->_sync = muse_mtd_sync; + mtd->_read_oob = muse_mtd_read_oob; + mtd->_write_oob = muse_mtd_write_oob; + mtd->_get_device = muse_mtd_get_device; + mtd->_put_device = muse_mtd_put_device; + + /* + * Bad blocks make only sense on NAND devices. + * As soon _block_isbad is set, upper layer such as + * UBI expects a working _block_isbad, so userspace + * has to implement MUSE_ISBAD. + */ + if (mtd_type_is_nand(mtd)) { + mtd->_block_isbad = muse_mtd_isbad; + mtd->_block_markbad = muse_mtd_markbad; + } + + mtd->priv = mc; + mtd->owner = THIS_MODULE; + + /* + * We want one READ/WRITE op per MTD io. So the MTD pagesize needs + * to fit into max_write/max_read + */ + if (fc->max_write < mtd->writebufsize || fc->max_read < mtd->writebufsize) + goto abort; + + if (mtd_device_register(mtd, NULL, 0) != 0) + goto abort; + + mc->init_done = true; + + kfree(mia); + __free_page(page); + return; + +abort: + fuse_abort_conn(fc); +} + +static int muse_send_init(struct muse_conn *mc) +{ + struct fuse_mount *fm = &mc->fm; + struct fuse_args_pages *ap; + struct muse_init_args *mia; + struct page *page; + int ret = -ENOMEM; + + BUILD_BUG_ON(MUSE_INIT_INFO_MAX > PAGE_SIZE); + + page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!page) + goto err; + + mia = kzalloc(sizeof(*mia), GFP_KERNEL); + if (!mia) + goto err_page; + + ap = &mia->ap; + mia->in.fuse_major = FUSE_KERNEL_VERSION; + mia->in.fuse_minor = FUSE_KERNEL_MINOR_VERSION; + ap->args.opcode = MUSE_INIT; + ap->args.in_numargs = 1; + ap->args.in_args[0].size = sizeof(mia->in); + ap->args.in_args[0].value = &mia->in; + ap->args.out_numargs = 2; + ap->args.out_args[0].size = sizeof(mia->out); + ap->args.out_args[0].value = &mia->out; + ap->args.out_args[1].size = MUSE_INIT_INFO_MAX; + ap->args.out_argvar = true; + ap->args.out_pages = true; + ap->num_pages = 1; + ap->pages = &mia->page; + ap->descs = &mia->desc; + mia->page = page; + mia->desc.length = ap->args.out_args[1].size; + ap->args.end = muse_process_init_reply; + + ret = fuse_simple_background(fm, &ap->args, GFP_KERNEL); + if (ret) + goto err_ia; + + return 0; + +err_ia: + kfree(mia); +err_page: + __free_page(page); +err: + return ret; +} + +static int muse_ctrl_open(struct inode *inode, struct file *file) +{ + struct muse_conn *mc; + struct fuse_dev *fud; + int ret; + + /* + * Paranoia check. + */ + if (!capable(CAP_SYS_ADMIN)) { + ret = -EPERM; + goto err; + } + + mc = kzalloc(sizeof(*mc), GFP_KERNEL); + if (!mc) { + ret = -ENOMEM; + goto err; + } + + fuse_conn_init(&mc->fc, &mc->fm, get_user_ns(&init_user_ns), + &fuse_dev_fiq_ops, NULL); + + fud = fuse_dev_alloc_install(&mc->fc); + if (!fud) { + ret = -ENOMEM; + goto err_free; + } + + mc->fc.release = muse_fc_release; + mc->fc.initialized = 1; + + ret = muse_send_init(mc); + if (ret) + goto err_dev; + + file->private_data = fud; + + return 0; + +err_dev: + fuse_dev_free(fud); + fuse_conn_put(&mc->fc); +err_free: + kfree(mc); +err: + return ret; +} + +static int muse_ctrl_release(struct inode *inode, struct file *file) +{ + struct fuse_dev *fud = file->private_data; + struct muse_conn *mc = container_of(fud->fc, struct muse_conn, fc); + + if (mc->init_done) + mtd_device_unregister(&mc->mtd); + + fuse_conn_put(&mc->fc); + + return fuse_dev_release(inode, file); +} + +static struct miscdevice muse_ctrl_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "muse", + .fops = &muse_ctrl_fops, +}; + +static int __init muse_init(void) +{ + muse_ctrl_fops = fuse_dev_operations; + muse_ctrl_fops.owner = THIS_MODULE; + muse_ctrl_fops.open = muse_ctrl_open; + muse_ctrl_fops.release = muse_ctrl_release; + + return misc_register(&muse_ctrl_dev); +} + +static void __exit muse_exit(void) +{ + misc_deregister(&muse_ctrl_dev); +} + +module_init(muse_init); +module_exit(muse_exit); + +MODULE_AUTHOR("Richard Weinberger "); +MODULE_DESCRIPTION("MTD in userspace"); +MODULE_LICENSE("GPL"); From patchwork Thu Nov 26 23:33:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Weinberger X-Patchwork-Id: 11934907 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 85741C64E7C for ; Thu, 26 Nov 2020 23:33:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5F7D62224C for ; Thu, 26 Nov 2020 23:33:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2403879AbgKZXdn (ORCPT ); Thu, 26 Nov 2020 18:33:43 -0500 Received: from lilium.sigma-star.at ([109.75.188.150]:55386 "EHLO lilium.sigma-star.at" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2391952AbgKZXdn (ORCPT ); Thu, 26 Nov 2020 18:33:43 -0500 Received: from localhost (localhost [127.0.0.1]) by lilium.sigma-star.at (Postfix) with ESMTP id C3E58181C8919; Fri, 27 Nov 2020 00:33:40 +0100 (CET) Received: from lilium.sigma-star.at ([127.0.0.1]) by localhost (lilium.sigma-star.at [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id uf6cIM3ZuHZ6; Fri, 27 Nov 2020 00:33:40 +0100 (CET) Received: from lilium.sigma-star.at ([127.0.0.1]) by localhost (lilium.sigma-star.at [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id OhjwzHkz5YTb; Fri, 27 Nov 2020 00:33:40 +0100 (CET) From: Richard Weinberger To: miklos@szeredi.hu Cc: miquel.raynal@bootlin.com, vigneshr@ti.com, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, Richard Weinberger Subject: [PATCH 7/7] MAINTAINERS: Add entry for MUSE Date: Fri, 27 Nov 2020 00:33:00 +0100 Message-Id: <20201126233300.10714-8-richard@nod.at> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20201126233300.10714-1-richard@nod.at> References: <20201126233300.10714-1-richard@nod.at> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org Since MUSE lifes in fs/fuse/, make sure that linux-mtd@ is CC'ed on patches such that MTD related aspects of changes can be reviewed. Signed-off-by: Richard Weinberger --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 94ac10a153c7..92359bb8d133 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11959,6 +11959,13 @@ L: linux-usb@vger.kernel.org S: Maintained F: drivers/usb/musb/ +MUSE: MTD IN USERSPACE DRIVER +M: Richard Weinberger +L: linux-mtd@lists.infradead.org +L: linux-fsdevel@vger.kernel.org +S: Maintained +F: fs/fuse/muse.c + MXL301RF MEDIA DRIVER M: Akihiro Tsukada L: linux-media@vger.kernel.org