From patchwork Fri Feb 10 10:46:22 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juergen Gross X-Patchwork-Id: 13135674 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id E106AC636CD for ; Fri, 10 Feb 2023 10:47:02 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.493253.763107 (Exim 4.92) (envelope-from ) id 1pQQvU-00062x-17; Fri, 10 Feb 2023 10:46:44 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 493253.763107; Fri, 10 Feb 2023 10:46:43 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pQQvT-00062k-Rx; Fri, 10 Feb 2023 10:46:43 +0000 Received: by outflank-mailman (input) for mailman id 493253; Fri, 10 Feb 2023 10:46:42 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pQQvS-000617-DB for xen-devel@lists.xenproject.org; Fri, 10 Feb 2023 10:46:42 +0000 Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id 31429bb5-a930-11ed-93b5-47a8fe42b414; Fri, 10 Feb 2023 11:46:38 +0100 (CET) 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-out2.suse.de (Postfix) with ESMTPS id B835E5CA5F; Fri, 10 Feb 2023 10:46:36 +0000 (UTC) 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 892191325E; Fri, 10 Feb 2023 10:46:36 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id 6FYVIIwg5mPFUwAAMHmgww (envelope-from ); Fri, 10 Feb 2023 10:46:36 +0000 X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 31429bb5-a930-11ed-93b5-47a8fe42b414 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1676025996; 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=EcyQSQ8MTpZXgX1s81+j7sy99tw1SNkYAs91wZGwPfs=; b=Q4izeK3vg+QRNfe+B27h8+Led+RcTZCktMmPvigGZDrNU4Xj1dllvMlKXG1Qnar/sdGTIV iPJC/ElqxDe3JzAxXD6BVOv6ZawW+yI0oj+q1LFSKjm3J8Xn8MnTjmftES/f6AsOFtjNWf yh+Gmy315qlOSF8ALfKeXDfBXBJihg4= From: Juergen Gross To: minios-devel@lists.xenproject.org, xen-devel@lists.xenproject.org Cc: samuel.thibault@ens-lyon.org, wl@xen.org, Juergen Gross Subject: [PATCH v2 1/7] Mini-OS: xenbus: add support for reading node from directory Date: Fri, 10 Feb 2023 11:46:22 +0100 Message-Id: <20230210104628.14374-2-jgross@suse.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230210104628.14374-1-jgross@suse.com> References: <20230210104628.14374-1-jgross@suse.com> MIME-Version: 1.0 Especially PV device drivers often need to read multiple Xenstore nodes from a common directory. Add support for reading a string or an unsigned value by specifying the directory and the node. Signed-off-by: Juergen Gross Reviewed-by: Samuel Thibault --- V2: - check sscanf() return value (Samuel Thibault) --- include/xenbus.h | 6 ++++++ xenbus.c | 40 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/include/xenbus.h b/include/xenbus.h index 3871f358..c0fc0ac5 100644 --- a/include/xenbus.h +++ b/include/xenbus.h @@ -108,6 +108,12 @@ int xenbus_read_integer(const char *path); * read and parsing were successful, 0 if not */ int xenbus_read_uuid(const char* path, unsigned char uuid[16]); +/* Support functions for reading values from directory/node tuple. */ +char *xenbus_read_string(xenbus_transaction_t xbt, const char *dir, + const char *node, char **value); +char *xenbus_read_unsigned(xenbus_transaction_t xbt, const char *dir, + const char *node, unsigned int *value); + /* Contraction of snprintf and xenbus_write(path/node). */ char* xenbus_printf(xenbus_transaction_t xbt, const char* node, const char* path, diff --git a/xenbus.c b/xenbus.c index 81e9b65d..923e8181 100644 --- a/xenbus.c +++ b/xenbus.c @@ -936,16 +936,21 @@ int xenbus_read_uuid(const char *path, unsigned char uuid[16]) return 1; } +#define BUFFER_SIZE 256 +static void xenbus_build_path(const char *dir, const char *node, char *res) +{ + BUG_ON(strlen(dir) + strlen(node) + 1 >= BUFFER_SIZE); + sprintf(res,"%s/%s", dir, node); +} + char *xenbus_printf(xenbus_transaction_t xbt, const char* node, const char* path, const char* fmt, ...) { -#define BUFFER_SIZE 256 char fullpath[BUFFER_SIZE]; char val[BUFFER_SIZE]; va_list args; - BUG_ON(strlen(node) + strlen(path) + 1 >= BUFFER_SIZE); - sprintf(fullpath,"%s/%s", node, path); + xenbus_build_path(node, path, fullpath); va_start(args, fmt); vsprintf(val, fmt, args); va_end(args); @@ -964,6 +969,35 @@ domid_t xenbus_get_self_id(void) return ret; } +char *xenbus_read_string(xenbus_transaction_t xbt, const char *dir, + const char *node, char **value) +{ + char path[BUFFER_SIZE]; + + xenbus_build_path(dir, node, path); + + return xenbus_read(xbt, path, value); +} + +char *xenbus_read_unsigned(xenbus_transaction_t xbt, const char *dir, + const char *node, unsigned int *value) +{ + char path[BUFFER_SIZE]; + char *msg; + char *str; + + xenbus_build_path(dir, node, path); + msg = xenbus_read(xbt, path, &str); + if ( msg ) + return msg; + + if ( sscanf(str, "%u", value) != 1 ) + msg = strdup("EINVAL"); + free(str); + + return msg; +} + /* * Local variables: * mode: C From patchwork Fri Feb 10 10:46:23 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juergen Gross X-Patchwork-Id: 13135675 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id D4E6CC05027 for ; Fri, 10 Feb 2023 10:47:04 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.493255.763122 (Exim 4.92) (envelope-from ) id 1pQQvY-0006PG-8Q; Fri, 10 Feb 2023 10:46:48 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 493255.763122; Fri, 10 Feb 2023 10:46:48 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pQQvY-0006P9-4l; Fri, 10 Feb 2023 10:46:48 +0000 Received: by outflank-mailman (input) for mailman id 493255; Fri, 10 Feb 2023 10:46:46 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pQQvW-000617-Jz for xen-devel@lists.xenproject.org; Fri, 10 Feb 2023 10:46:46 +0000 Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id 34a04e52-a930-11ed-93b5-47a8fe42b414; Fri, 10 Feb 2023 11:46:42 +0100 (CET) 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 615EC3FEC5; Fri, 10 Feb 2023 10:46:42 +0000 (UTC) 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 39D171325E; Fri, 10 Feb 2023 10:46:42 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id 5aTuDJIg5mPXUwAAMHmgww (envelope-from ); Fri, 10 Feb 2023 10:46:42 +0000 X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 34a04e52-a930-11ed-93b5-47a8fe42b414 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1676026002; 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=/AHf/75zmPALL2yeH8dnyZ0qXj5tN9xIh6TXHZM0XmI=; b=uUnrQU6OBTmGEoK5GrqQ5X1uKYO50tysm/j0qaooTSeJQ2BfFKK4egmCT4hUuwYhyS1ZEq LxH6MFeQ7hdpMDYz59hrNEqR8JXTYmxpLEpUk7LM/Qn5LZD28KoJep29gwFa0s0TS9Jbzz iE28cYUEKlTy1HyP4v909JUgLcPRPOA= From: Juergen Gross To: minios-devel@lists.xenproject.org, xen-devel@lists.xenproject.org Cc: samuel.thibault@ens-lyon.org, wl@xen.org, Juergen Gross Subject: [PATCH v2 2/7] Mini-OS: add concept of mount points Date: Fri, 10 Feb 2023 11:46:23 +0100 Message-Id: <20230210104628.14374-3-jgross@suse.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230210104628.14374-1-jgross@suse.com> References: <20230210104628.14374-1-jgross@suse.com> MIME-Version: 1.0 Add the concept of mount points to Mini-OS. A mount point is a path associated with a device pointer and an open() callback. A mount point can be either a file (e.g. "/dev/mem") or a directory ("/var/log"). This allows to replace the special casing in the generic open() handling with a generic mount point handling. Prepare the open() callbacks to support creating new files by adding a mode parameter. Additionally add a close() prototype to include/lib.h, as it is missing today. Signed-off-by: Juergen Gross Reviewed-by: Samuel Thibault --- V2: - pass path below mount point to open callbacks (Samuel Thibault) --- include/lib.h | 9 ++++++ lib/sys.c | 80 +++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 70 insertions(+), 19 deletions(-) diff --git a/include/lib.h b/include/lib.h index bec99646..36d94ec4 100644 --- a/include/lib.h +++ b/include/lib.h @@ -187,6 +187,13 @@ struct file_ops { bool (*select_wr)(struct file *file); }; +struct mount_point { + const char *path; + int (*open)(struct mount_point *mnt, const char *pathname, int flags, + mode_t mode); + void *dev; +}; + unsigned int alloc_file_type(const struct file_ops *ops); off_t lseek_default(struct file *file, off_t offset, int whence); @@ -198,6 +205,8 @@ int alloc_fd(unsigned int type); void close_all_files(void); extern struct thread *main_thread; void sparse(unsigned long data, size_t size); + +int close(int fd); #endif #endif /* _LIB_H_ */ diff --git a/lib/sys.c b/lib/sys.c index 8f8a3de2..2f33c937 100644 --- a/lib/sys.c +++ b/lib/sys.c @@ -263,11 +263,6 @@ char *getcwd(char *buf, size_t size) return buf; } -#define LOG_PATH "/var/log/" -#define SAVE_PATH "/var/lib/xen" -#define SAVE_CONSOLE 1 -#define RESTORE_CONSOLE 2 - int mkdir(const char *pathname, mode_t mode) { errno = EIO; @@ -286,18 +281,30 @@ int posix_openpt(int flags) return fd; } +static int open_pt(struct mount_point *mnt, const char *pathname, int flags, + mode_t mode) +{ + return posix_openpt(flags); +} + int open_savefile(const char *path, int save) { int fd; char nodename[64]; - snprintf(nodename, sizeof(nodename), "device/console/%d", save ? SAVE_CONSOLE : RESTORE_CONSOLE); + snprintf(nodename, sizeof(nodename), "device/console/%d", save ? 1 : 2); fd = open_consfront(nodename); printk("fd(%d) = open_savefile\n", fd); return fd; } + +static int open_save(struct mount_point *mnt, const char *pathname, int flags, + mode_t mode) +{ + return open_savefile(pathname, flags & O_WRONLY); +} #else int posix_openpt(int flags) { @@ -311,24 +318,59 @@ int open_savefile(const char *path, int save) } #endif -int open(const char *pathname, int flags, ...) +static int open_log(struct mount_point *mnt, const char *pathname, int flags, + mode_t mode) { int fd; + /* Ugly, but fine. */ - if (!strncmp(pathname,LOG_PATH,strlen(LOG_PATH))) { - fd = alloc_fd(FTYPE_CONSOLE); - printk("open(%s) -> %d\n", pathname, fd); - return fd; + fd = alloc_fd(FTYPE_CONSOLE); + printk("open(%s%s) -> %d\n", mnt->path, pathname, fd); + return fd; +} + +static int open_mem(struct mount_point *mnt, const char *pathname, int flags, + mode_t mode) +{ + int fd; + + fd = alloc_fd(FTYPE_MEM); + printk("open(%s%s) -> %d\n", mnt->path, pathname, fd); + return fd; +} + +static struct mount_point mount_points[] = { + { .path = "/var/log", .open = open_log, .dev = NULL }, + { .path = "/dev/mem", .open = open_mem, .dev = NULL }, +#ifdef CONFIG_CONSFRONT + { .path = "/dev/ptmx", .open = open_pt, .dev = NULL }, + { .path = "/var/lib/xen", .open = open_save, .dev = NULL }, +#endif +}; + +int open(const char *pathname, int flags, ...) +{ + unsigned int m, mlen; + struct mount_point *mnt; + mode_t mode = 0; + va_list ap; + + if ( flags & O_CREAT ) + { + va_start(ap, flags); + mode = va_arg(ap, mode_t); + va_end(ap); } - if (!strncmp(pathname, "/dev/mem", strlen("/dev/mem"))) { - fd = alloc_fd(FTYPE_MEM); - printk("open(/dev/mem) -> %d\n", fd); - return fd; + + for ( m = 0; m < ARRAY_SIZE(mount_points); m++ ) + { + mnt = mount_points + m; + mlen = strlen(mnt->path); + if ( !strncmp(pathname, mnt->path, mlen) && + (pathname[mlen] == '/' || pathname[mlen] == 0) ) + return mnt->open(mnt, pathname + mlen, flags, mode); } - if (!strncmp(pathname, "/dev/ptmx", strlen("/dev/ptmx"))) - return posix_openpt(flags); - if (!strncmp(pathname,SAVE_PATH,strlen(SAVE_PATH))) - return open_savefile(pathname, flags & O_WRONLY); + errno = EIO; return -1; } From patchwork Fri Feb 10 10:46:24 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juergen Gross X-Patchwork-Id: 13135676 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 44B91C05027 for ; Fri, 10 Feb 2023 10:47:08 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.493257.763133 (Exim 4.92) (envelope-from ) id 1pQQvc-0006kO-FD; Fri, 10 Feb 2023 10:46:52 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 493257.763133; Fri, 10 Feb 2023 10:46:52 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pQQvc-0006kF-CM; Fri, 10 Feb 2023 10:46:52 +0000 Received: by outflank-mailman (input) for mailman id 493257; Fri, 10 Feb 2023 10:46:50 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pQQva-000617-R2 for xen-devel@lists.xenproject.org; Fri, 10 Feb 2023 10:46:50 +0000 Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id 37f94573-a930-11ed-93b5-47a8fe42b414; Fri, 10 Feb 2023 11:46:48 +0100 (CET) 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-out2.suse.de (Postfix) with ESMTPS id F1F095CA5F; Fri, 10 Feb 2023 10:46:47 +0000 (UTC) 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 C403B1325E; Fri, 10 Feb 2023 10:46:47 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id B395Lpcg5mPlUwAAMHmgww (envelope-from ); Fri, 10 Feb 2023 10:46:47 +0000 X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 37f94573-a930-11ed-93b5-47a8fe42b414 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1676026007; 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=r6yg48m3tvne8UEfBZnk+9j9B6sQe1QaY7lXxFABCRM=; b=Pg/wOl+X1wnAx5gv9QVCPC0Svx3QQQCb9FVnjkyyR0ckKiDByOeK9io6QiUwEU2tS+WTuZ jr0/+13du395NvWMczqy1XTIzTajelRXA3VJZmpKoJWyyQOYDXyuLwEKSb6FRNDbNi3K0h c4X9mMUISJcSo6IT1RKi1Tr0gEuQDjs= From: Juergen Gross To: minios-devel@lists.xenproject.org, xen-devel@lists.xenproject.org Cc: samuel.thibault@ens-lyon.org, wl@xen.org, Juergen Gross Subject: [PATCH v2 3/7] Mini-OS: add support for runtime mounts Date: Fri, 10 Feb 2023 11:46:24 +0100 Message-Id: <20230210104628.14374-4-jgross@suse.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230210104628.14374-1-jgross@suse.com> References: <20230210104628.14374-1-jgross@suse.com> MIME-Version: 1.0 Add the support to mount a device at runtime. The number of dynamic mounts is limited by a #define. For devices supporting multiple files struct file is modified to hold a pointer to file specific data in contrast to device specific data. Signed-off-by: Juergen Gross Reviewed-by: Samuel Thibault --- include/lib.h | 5 +++++ lib/sys.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/include/lib.h b/include/lib.h index 36d94ec4..fd8c36de 100644 --- a/include/lib.h +++ b/include/lib.h @@ -172,6 +172,7 @@ struct file { union { int fd; /* Any fd from an upper layer. */ void *dev; + void *filedata; }; }; @@ -194,6 +195,10 @@ struct mount_point { void *dev; }; +int mount(const char *path, void *dev, + int (*open)(struct mount_point *, const char *, int, mode_t)); +void umount(const char *path); + unsigned int alloc_file_type(const struct file_ops *ops); off_t lseek_default(struct file *file, off_t offset, int whence); diff --git a/lib/sys.c b/lib/sys.c index 2f33c937..dc8a8c69 100644 --- a/lib/sys.c +++ b/lib/sys.c @@ -339,7 +339,14 @@ static int open_mem(struct mount_point *mnt, const char *pathname, int flags, return fd; } -static struct mount_point mount_points[] = { +#ifdef CONFIG_CONSFRONT +#define STATIC_MNTS 4 +#else +#define STATIC_MNTS 2 +#endif +#define DYNAMIC_MNTS 8 + +static struct mount_point mount_points[STATIC_MNTS + DYNAMIC_MNTS] = { { .path = "/var/log", .open = open_log, .dev = NULL }, { .path = "/dev/mem", .open = open_mem, .dev = NULL }, #ifdef CONFIG_CONSFRONT @@ -365,6 +372,8 @@ int open(const char *pathname, int flags, ...) for ( m = 0; m < ARRAY_SIZE(mount_points); m++ ) { mnt = mount_points + m; + if ( !mnt->path ) + continue; mlen = strlen(mnt->path); if ( !strncmp(pathname, mnt->path, mlen) && (pathname[mlen] == '/' || pathname[mlen] == 0) ) @@ -375,6 +384,45 @@ int open(const char *pathname, int flags, ...) return -1; } +int mount(const char *path, void *dev, + int (*open)(struct mount_point *, const char *, int, mode_t)) +{ + unsigned int m; + struct mount_point *mnt; + + for ( m = 0; m < ARRAY_SIZE(mount_points); m++ ) + { + mnt = mount_points + m; + if ( !mnt->path ) + { + mnt->path = strdup(path); + mnt->open = open; + mnt->dev = dev; + return 0; + } + } + + errno = ENOSPC; + return -1; +} + +void umount(const char *path) +{ + unsigned int m; + struct mount_point *mnt; + + for ( m = 0; m < ARRAY_SIZE(mount_points); m++ ) + { + mnt = mount_points + m; + if ( mnt->path && !strcmp(mnt->path, path) ) + { + free((char *)mnt->path); + mnt->path = NULL; + return; + } + } +} + int isatty(int fd) { return files[fd].type == FTYPE_CONSOLE; From patchwork Fri Feb 10 10:46:25 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juergen Gross X-Patchwork-Id: 13135677 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 6D5A9C636CD for ; Fri, 10 Feb 2023 10:47:15 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.493262.763148 (Exim 4.92) (envelope-from ) id 1pQQvi-0007KO-Rk; Fri, 10 Feb 2023 10:46:58 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 493262.763148; Fri, 10 Feb 2023 10:46:58 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pQQvi-0007KD-O1; Fri, 10 Feb 2023 10:46:58 +0000 Received: by outflank-mailman (input) for mailman id 493262; Fri, 10 Feb 2023 10:46:57 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pQQvg-000617-Oy for xen-devel@lists.xenproject.org; Fri, 10 Feb 2023 10:46:56 +0000 Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id 3b473f65-a930-11ed-93b5-47a8fe42b414; Fri, 10 Feb 2023 11:46:53 +0100 (CET) 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-out2.suse.de (Postfix) with ESMTPS id 875945CA5F; Fri, 10 Feb 2023 10:46:53 +0000 (UTC) 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 5A2101325E; Fri, 10 Feb 2023 10:46:53 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id zWCwFJ0g5mPzUwAAMHmgww (envelope-from ); Fri, 10 Feb 2023 10:46:53 +0000 X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 3b473f65-a930-11ed-93b5-47a8fe42b414 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1676026013; 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=LfzPuWES19Z6zkc6ddDA2+HHqNpphAyol7vuoCqTTog=; b=GIBT8TTNBayaUmMcymygthXHVyC152KeQDlcror7XNkR6fy91STK/zBi9jv06fw1TW0mVD NUZW4SFP7o63G6Moegu++0snEw5DKiTUwXXw20BJSTj6s7qyanIAE70qP7qj3jwvwBaMN3 FGk5rL7CQO1tvOLGFOlkAW7jPaBt9GY= From: Juergen Gross To: minios-devel@lists.xenproject.org, xen-devel@lists.xenproject.org Cc: samuel.thibault@ens-lyon.org, wl@xen.org, Juergen Gross Subject: [PATCH v2 4/7] Mini-OS: add 9pfs frontend Date: Fri, 10 Feb 2023 11:46:25 +0100 Message-Id: <20230210104628.14374-5-jgross@suse.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230210104628.14374-1-jgross@suse.com> References: <20230210104628.14374-1-jgross@suse.com> MIME-Version: 1.0 Add a frontend for the 9pfs PV device. For now add only the code needed to connect to the backend and the related disconnect functionality. The 9pfs protocol support will be added later. Due to its nature (ability to access files) the whole code is guarded by "#ifdef HAVE_LIBC". Signed-off-by: Juergen Gross Reviewed-by: Samuel Thibault --- V2: - add better error handling to version parsing (Samuel Thibault) --- 9pfront.c | 286 ++++++++++++++++++++++++++++++++++ Config.mk | 1 + Makefile | 1 + arch/x86/testbuild/all-no | 1 + arch/x86/testbuild/all-yes | 1 + arch/x86/testbuild/newxen-yes | 1 + include/9pfront.h | 7 + 7 files changed, 298 insertions(+) create mode 100644 9pfront.c create mode 100644 include/9pfront.h diff --git a/9pfront.c b/9pfront.c new file mode 100644 index 00000000..89ecb3a1 --- /dev/null +++ b/9pfront.c @@ -0,0 +1,286 @@ +/* + * Minimal 9pfs PV frontend for Mini-OS. + * Copyright (c) 2023 Juergen Gross, SUSE Software Solution GmbH + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_LIBC +struct dev_9pfs { + int id; + char nodename[20]; + unsigned int dom; + char *backend; + + char *tag; + const char *mnt; + + struct xen_9pfs_data_intf *intf; + struct xen_9pfs_data data; + RING_IDX prod_pvt_out; + RING_IDX cons_pvt_in; + + grant_ref_t ring_ref; + evtchn_port_t evtchn; + unsigned int ring_order; + xenbus_event_queue events; +}; + +#define DEFAULT_9PFS_RING_ORDER 4 + +static unsigned int ftype_9pfs; + +static void intr_9pfs(evtchn_port_t port, struct pt_regs *regs, void *data) +{ +} + +static int open_9pfs(struct mount_point *mnt, const char *pathname, int flags, + mode_t mode) +{ + errno = ENOSYS; + + return -1; +} + +static void free_9pfront(struct dev_9pfs *dev) +{ + unsigned int i; + + if ( dev->data.in && dev->intf ) + { + for ( i = 0; i < (1 << dev->ring_order); i++ ) + gnttab_end_access(dev->intf->ref[i]); + free_pages(dev->data.in, dev->ring_order); + } + unbind_evtchn(dev->evtchn); + gnttab_end_access(dev->ring_ref); + free_page(dev->intf); + free(dev->backend); + free(dev->tag); + free(dev); +} + +void *init_9pfront(unsigned int id, const char *mnt) +{ + struct dev_9pfs *dev; + char *msg; + char *reason = ""; + xenbus_transaction_t xbt; + int retry = 1; + char bepath[64] = { 0 }; + XenbusState state; + unsigned int i; + void *addr; + char *version; + char *v; + + printk("9pfsfront add %u, for mount at %s\n", id, mnt); + dev = malloc(sizeof(*dev)); + memset(dev, 0, sizeof(*dev)); + snprintf(dev->nodename, sizeof(dev->nodename), "device/9pfs/%u", id); + dev->id = id; + + msg = xenbus_read_unsigned(XBT_NIL, dev->nodename, "backend-id", &dev->dom); + if ( msg ) + goto err; + msg = xenbus_read_string(XBT_NIL, dev->nodename, "backend", &dev->backend); + if ( msg ) + goto err; + msg = xenbus_read_string(XBT_NIL, dev->nodename, "tag", &dev->tag); + if ( msg ) + goto err; + + snprintf(bepath, sizeof(bepath), "%s/state", dev->backend); + free(xenbus_watch_path_token(XBT_NIL, bepath, bepath, &dev->events)); + state = xenbus_read_integer(bepath); + while ( msg == NULL && state < XenbusStateInitWait ) + msg = xenbus_wait_for_state_change(bepath, &state, &dev->events); + if ( msg || state != XenbusStateInitWait ) + { + reason = "illegal backend state"; + goto err; + } + + msg = xenbus_read_unsigned(XBT_NIL, dev->backend, "max-ring-page-order", + &dev->ring_order); + if ( msg ) + goto err; + if ( dev->ring_order > DEFAULT_9PFS_RING_ORDER ) + dev->ring_order = DEFAULT_9PFS_RING_ORDER; + + msg = xenbus_read_string(XBT_NIL, dev->backend, "versions", &version); + if ( msg ) + goto err; + for ( v = version; *v; v++ ) + { + if ( strtoul(v, &v, 10) == 1 && (*v == ',' || *v == 0) ) + { + v = NULL; + break; + } + if ( *v != ',' && *v != 0 ) + { + reason = "backend published illegal version string"; + free(version); + goto err; + } + } + free(version); + if ( v ) + { + reason = "backend doesn't support version 1"; + goto err; + } + + dev->ring_ref = gnttab_alloc_and_grant((void **)&dev->intf); + memset(dev->intf, 0, PAGE_SIZE); + if ( evtchn_alloc_unbound(dev->dom, intr_9pfs, dev, &dev->evtchn) ) + { + reason = "no event channel"; + goto err; + } + dev->intf->ring_order = dev->ring_order; + dev->data.in = (void *)alloc_pages(dev->ring_order); + dev->data.out = dev->data.in + XEN_FLEX_RING_SIZE(dev->ring_order); + for ( i = 0; i < (1 << dev->ring_order); i++ ) + { + addr = dev->data.in + i * PAGE_SIZE; + dev->intf->ref[i] = gnttab_grant_access(dev->dom, virt_to_mfn(addr), 0); + } + + while ( retry ) + { + msg = xenbus_transaction_start(&xbt); + if ( msg ) + { + free(msg); + msg = NULL; + reason = "starting transaction"; + goto err; + } + + msg = xenbus_printf(xbt, dev->nodename, "version", "%u", 1); + if ( msg ) + goto err_tr; + msg = xenbus_printf(xbt, dev->nodename, "num-rings", "%u", 1); + if ( msg ) + goto err_tr; + msg = xenbus_printf(xbt, dev->nodename, "ring-ref0", "%u", + dev->ring_ref); + if ( msg ) + goto err_tr; + msg = xenbus_printf(xbt, dev->nodename, "event-channel-0", "%u", + dev->evtchn); + if ( msg ) + goto err_tr; + msg = xenbus_printf(xbt, dev->nodename, "state", "%u", + XenbusStateInitialised); + if ( msg ) + goto err_tr; + + free(xenbus_transaction_end(xbt, 0, &retry)); + } + + state = xenbus_read_integer(bepath); + while ( msg == NULL && state < XenbusStateConnected ) + msg = xenbus_wait_for_state_change(bepath, &state, &dev->events); + if ( msg || state != XenbusStateConnected ) + { + reason = "illegal backend state"; + goto err; + } + + msg = xenbus_printf(XBT_NIL, dev->nodename, "state", "%u", + XenbusStateConnected); + if ( msg ) + goto err; + + unmask_evtchn(dev->evtchn); + + dev->mnt = mnt; + if ( mount(dev->mnt, dev, open_9pfs) ) + { + reason = "mount failed"; + goto err; + } + + return dev; + + err_tr: + free(xenbus_transaction_end(xbt, 1, &retry)); + + err: + if ( bepath[0] ) + free(xenbus_unwatch_path_token(XBT_NIL, bepath, bepath)); + if ( msg ) + printk("9pfsfront add %u failed, error %s accessing Xenstore\n", + id, msg); + else + printk("9pfsfront add %u failed, %s\n", id, reason); + free_9pfront(dev); + free(msg); + return NULL; +} + +void shutdown_9pfront(void *dev) +{ + struct dev_9pfs *dev9p = dev; + char bepath[64]; + XenbusState state; + char *msg; + char *reason = ""; + + umount(dev9p->mnt); + snprintf(bepath, sizeof(bepath), "%s/state", dev9p->backend); + + msg = xenbus_printf(XBT_NIL, dev9p->nodename, "state", "%u", + XenbusStateClosing); + if ( msg ) + goto err; + + state = xenbus_read_integer(bepath); + while ( msg == NULL && state < XenbusStateClosing) + msg = xenbus_wait_for_state_change(bepath, &state, &dev9p->events); + if ( msg || state != XenbusStateClosing ) + { + reason = "illegal backend state"; + goto err; + } + + msg = xenbus_printf(XBT_NIL, dev9p->nodename, "state", "%u", + XenbusStateClosed); + if ( msg ) + goto err; + + free_9pfront(dev9p); + + return; + + err: + if ( msg ) + printk("9pfsfront shutdown %u failed, error %s accessing Xenstore\n", + dev9p->id, msg); + else + printk("9pfsfront shutdown %u failed, %s\n", dev9p->id, reason); + free(msg); +} + +static const struct file_ops ops_9pfs = { + .name = "9pfs", +}; + +__attribute__((constructor)) +static void initialize_9pfs(void) +{ + ftype_9pfs = alloc_file_type(&ops_9pfs); +} + +#endif /* HAVE_LIBC */ diff --git a/Config.mk b/Config.mk index 1a24b30e..677e93df 100644 --- a/Config.mk +++ b/Config.mk @@ -187,6 +187,7 @@ CONFIG-n += CONFIG_QEMU_XS_ARGS CONFIG-n += CONFIG_TEST CONFIG-n += CONFIG_PCIFRONT CONFIG-n += CONFIG_TPMFRONT +CONFIG-n += CONFIG_9PFRONT CONFIG-n += CONFIG_TPM_TIS CONFIG-n += CONFIG_TPMBACK CONFIG-n += CONFIG_BALLOON diff --git a/Makefile b/Makefile index 747c7c01..7ee181a2 100644 --- a/Makefile +++ b/Makefile @@ -39,6 +39,7 @@ SUBDIRS := lib src-$(CONFIG_BLKFRONT) += blkfront.c src-$(CONFIG_CONSFRONT) += consfront.c src-$(CONFIG_TPMFRONT) += tpmfront.c +src-$(CONFIG_9PFRONT) += 9pfront.c src-$(CONFIG_TPM_TIS) += tpm_tis.c src-$(CONFIG_TPMBACK) += tpmback.c src-y += console.c diff --git a/arch/x86/testbuild/all-no b/arch/x86/testbuild/all-no index f79a1012..5b3e99ed 100644 --- a/arch/x86/testbuild/all-no +++ b/arch/x86/testbuild/all-no @@ -12,6 +12,7 @@ CONFIG_NETFRONT = n CONFIG_FBFRONT = n CONFIG_KBDFRONT = n CONFIG_CONSFRONT = n +CONFIG_9PFRONT = n CONFIG_XENBUS = n CONFIG_LIBXS = n CONFIG_LWIP = n diff --git a/arch/x86/testbuild/all-yes b/arch/x86/testbuild/all-yes index faa3af32..8ae489a4 100644 --- a/arch/x86/testbuild/all-yes +++ b/arch/x86/testbuild/all-yes @@ -12,6 +12,7 @@ CONFIG_NETFRONT = y CONFIG_FBFRONT = y CONFIG_KBDFRONT = y CONFIG_CONSFRONT = y +CONFIG_9PFRONT = y CONFIG_XENBUS = y CONFIG_LIBXS = y CONFIG_BALLOON = y diff --git a/arch/x86/testbuild/newxen-yes b/arch/x86/testbuild/newxen-yes index dc83e670..ee27a328 100644 --- a/arch/x86/testbuild/newxen-yes +++ b/arch/x86/testbuild/newxen-yes @@ -12,6 +12,7 @@ CONFIG_NETFRONT = y CONFIG_FBFRONT = y CONFIG_KBDFRONT = y CONFIG_CONSFRONT = y +CONFIG_9PFRONT = y CONFIG_XENBUS = y CONFIG_LIBXS = y CONFIG_BALLOON = y diff --git a/include/9pfront.h b/include/9pfront.h new file mode 100644 index 00000000..722ec564 --- /dev/null +++ b/include/9pfront.h @@ -0,0 +1,7 @@ +#ifndef __9PFRONT_H__ +#define __9PFRONT_H__ + +void *init_9pfront(unsigned int id, const char *mnt); +void shutdown_9pfront(void *dev); + +#endif /* __9PFRONT_H__ */ From patchwork Fri Feb 10 10:46:26 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juergen Gross X-Patchwork-Id: 13135680 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id F1186C636CD for ; Fri, 10 Feb 2023 10:55:27 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.493298.763193 (Exim 4.92) (envelope-from ) id 1pQR3i-0002lf-SD; Fri, 10 Feb 2023 10:55:14 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 493298.763193; Fri, 10 Feb 2023 10:55:14 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pQR3i-0002lY-O4; Fri, 10 Feb 2023 10:55:14 +0000 Received: by outflank-mailman (input) for mailman id 493298; Fri, 10 Feb 2023 10:55:13 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pQQvn-000617-VA for xen-devel@lists.xenproject.org; Fri, 10 Feb 2023 10:47:04 +0000 Received: from smtp-out1.suse.de (smtp-out1.suse.de [2001:67c:2178:6::1c]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id 3e9e5fb6-a930-11ed-93b5-47a8fe42b414; Fri, 10 Feb 2023 11:46:59 +0100 (CET) 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 286413FEC5; Fri, 10 Feb 2023 10:46:59 +0000 (UTC) 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 EC1231325E; Fri, 10 Feb 2023 10:46:58 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id t2tDOKIg5mMAVAAAMHmgww (envelope-from ); Fri, 10 Feb 2023 10:46:58 +0000 X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 3e9e5fb6-a930-11ed-93b5-47a8fe42b414 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1676026019; 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=AjLtvshfjPJLxhGdXS+IgJVdKslWSTSlXSgC0tGAfD0=; b=NOT/uNDL/q3Nh9a1C32Rlo3B2Dyw3tSWtTow1koZyC/xfTeUU+zab4gzRWdQhPxW9MhA9h JfGEdoK2tm+/YaKjFmY6K14mBmlYXzsL0TURz4/IZFuIN9MwZKHFno9uQvLBOGAmFeIgi1 Ar1vr/wksJI1o4ekhjZl3Nyo8Kk0hYk= From: Juergen Gross To: minios-devel@lists.xenproject.org, xen-devel@lists.xenproject.org Cc: samuel.thibault@ens-lyon.org, wl@xen.org, Juergen Gross Subject: [PATCH v2 5/7] Mini-OS: add 9pfs transport layer Date: Fri, 10 Feb 2023 11:46:26 +0100 Message-Id: <20230210104628.14374-6-jgross@suse.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230210104628.14374-1-jgross@suse.com> References: <20230210104628.14374-1-jgross@suse.com> MIME-Version: 1.0 Add the transport layer of 9pfs. This is basically the infrastructure to send requests to the backend and to receive the related answers via the rings. As a first example add the version and attach requests of the 9pfs protocol when mounting a new 9pfs device. For the version use the "9P2000.u" variant, as it is the smallest subset supported by the qemu based backend. Signed-off-by: Juergen Gross Reviewed-by: Samuel Thibault --- V2: - add more comments (Samuel Thibault) - log short copy (Samuel Thibault) - send event after consuming response (Samuel Thibault) - reaturn EAGAIN in case no free request could be got (Samuel Thibault) --- 9pfront.c | 478 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 478 insertions(+) diff --git a/9pfront.c b/9pfront.c index 89ecb3a1..0b8d5461 100644 --- a/9pfront.c +++ b/9pfront.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include #include @@ -14,6 +16,9 @@ #include #ifdef HAVE_LIBC + +#define N_REQS 64 + struct dev_9pfs { int id; char nodename[20]; @@ -22,6 +27,7 @@ struct dev_9pfs { char *tag; const char *mnt; + unsigned int msize_max; struct xen_9pfs_data_intf *intf; struct xen_9pfs_data data; @@ -32,14 +38,470 @@ struct dev_9pfs { evtchn_port_t evtchn; unsigned int ring_order; xenbus_event_queue events; + + unsigned int free_reqs; + struct req { + unsigned int id; + unsigned int next_free; /* N_REQS == end of list. */ + unsigned int cmd; + int result; + bool inflight; + unsigned char *data; /* Returned data. */ + } req[N_REQS]; + + struct wait_queue_head waitq; + struct semaphore ring_out_sem; + struct semaphore ring_in_sem; }; #define DEFAULT_9PFS_RING_ORDER 4 +#define P9_CMD_VERSION 100 +#define P9_CMD_ATTACH 104 +#define P9_CMD_ERROR 107 + +#define P9_QID_SIZE 13 + +struct p9_header { + uint32_t size; + uint8_t cmd; + uint16_t tag; +} __attribute__((packed)); + +#define P9_VERSION "9P2000.u" +#define P9_ROOT_FID ~0 + static unsigned int ftype_9pfs; +static struct req *get_free_req(struct dev_9pfs *dev) +{ + struct req *req; + + if ( dev->free_reqs == N_REQS ) + return NULL; + + req = dev->req + dev->free_reqs; + dev->free_reqs = req->next_free; + + return req; +} + +static void put_free_req(struct dev_9pfs *dev, struct req *req) +{ + req->next_free = dev->free_reqs; + req->inflight = false; + req->data = NULL; + dev->free_reqs = req->id; +} + +static unsigned int ring_out_free(struct dev_9pfs *dev) +{ + RING_IDX ring_size = XEN_FLEX_RING_SIZE(dev->ring_order); + unsigned int queued; + + queued = xen_9pfs_queued(dev->prod_pvt_out, dev->intf->out_cons, ring_size); + rmb(); + + return ring_size - queued; +} + +static unsigned int ring_in_data(struct dev_9pfs *dev) +{ + RING_IDX ring_size = XEN_FLEX_RING_SIZE(dev->ring_order); + unsigned int queued; + + queued = xen_9pfs_queued(dev->intf->in_prod, dev->cons_pvt_in, ring_size); + rmb(); + + return queued; +} + +static void copy_to_ring(struct dev_9pfs *dev, void *data, unsigned int len) +{ + RING_IDX ring_size = XEN_FLEX_RING_SIZE(dev->ring_order); + RING_IDX prod = xen_9pfs_mask(dev->prod_pvt_out, ring_size); + RING_IDX cons = xen_9pfs_mask(dev->intf->out_cons, ring_size); + + xen_9pfs_write_packet(dev->data.out, data, len, &prod, cons, ring_size); + dev->prod_pvt_out += len; +} + +static void copy_from_ring(struct dev_9pfs *dev, void *data, unsigned int len) +{ + RING_IDX ring_size = XEN_FLEX_RING_SIZE(dev->ring_order); + RING_IDX prod = xen_9pfs_mask(dev->intf->in_prod, ring_size); + RING_IDX cons = xen_9pfs_mask(dev->cons_pvt_in, ring_size); + + xen_9pfs_read_packet(data, dev->data.in, len, prod, &cons, ring_size); + dev->cons_pvt_in += len; +} + +/* + * send_9p() and rcv_9p() are using a special format string for specifying + * the kind of data sent/expected. Each data item is represented by a single + * character: + * U: 4 byte unsigned integer (uint32_t) + * S: String (2 byte length + characters) + * in the rcv_9p() case the data for string is allocated (length omitted, + * string terminated by a NUL character) + * Q: A 13 byte "qid", consisting of 1 byte file type, 4 byte file version + * and 8 bytes unique file id. Only valid for receiving. + */ +static void send_9p(struct dev_9pfs *dev, struct req *req, const char *fmt, ...) +{ + struct p9_header hdr; + va_list ap, aq; + const char *f; + uint32_t intval; + uint16_t len; + char *strval; + + hdr.size = sizeof(hdr); + hdr.cmd = req->cmd; + hdr.tag = req->id; + + va_start(ap, fmt); + + va_copy(aq, ap); + for ( f = fmt; *f; f++ ) + { + switch ( *f ) + { + case 'U': + hdr.size += 4; + intval = va_arg(aq, unsigned int); + break; + case 'S': + hdr.size += 2; + strval = va_arg(aq, char *); + hdr.size += strlen(strval); + break; + default: + printk("send_9p: unknown format character %c\n", *f); + break; + } + } + va_end(aq); + + /* + * Waiting for free space must be done in the critical section! + * Otherwise we might get overtaken by other short requests. + */ + down(&dev->ring_out_sem); + + wait_event(dev->waitq, ring_out_free(dev) >= hdr.size); + + copy_to_ring(dev, &hdr, sizeof(hdr)); + for ( f = fmt; *f; f++ ) + { + switch ( *f ) + { + case 'U': + intval = va_arg(ap, unsigned int); + copy_to_ring(dev, &intval, sizeof(intval)); + break; + case 'S': + strval = va_arg(ap, char *); + len = strlen(strval); + copy_to_ring(dev, &len, sizeof(len)); + copy_to_ring(dev, strval, len); + break; + } + } + + wmb(); /* Data on ring must be seen before updating index. */ + dev->intf->out_prod = dev->prod_pvt_out; + req->inflight = true; + + up(&dev->ring_out_sem); + + va_end(ap); + + notify_remote_via_evtchn(dev->evtchn); +} + +/* + * Using an opportunistic approach for receiving data: in case multiple + * requests are outstanding (which is very unlikely), we nevertheless need + * to consume all data available until we reach the desired request. + * For requests other than the one we are waiting for, we link the complete + * data to the request via an intermediate buffer. For our own request we can + * omit that buffer and directly fill the caller provided variables. + * + * Helper functions: + * + * copy_bufs(): copy raw data into a target buffer. There can be 2 source + * buffers involved (in case the copy is done from the ring and it is across + * the ring end). The buffer pointers and lengths are updated according to + * the number of bytes copied. + * + * rcv_9p_copy(): copy the data (without the generic header) of a 9p response + * to the specified variables using the specified format string for + * deciphering the single item types. The decision whether to copy from the + * ring or an allocated buffer is done via the "hdr" parameter, which is + * NULL in the buffer case (in that case the header is located at the start + * of the buffer). + * + * rcv_9p_one(): Checks for an already filled buffer with the correct tag in + * it. If none is found, consumes one response. It checks the tag of the + * response in order to decide whether to allocate a buffer for putting the + * data into, or to fill the user supplied variables. Return true, if the + * tag did match. Waits if no data is ready to be consumed. + */ +static void copy_bufs(unsigned char **buf1, unsigned char **buf2, + unsigned int *len1, unsigned int *len2, + void *target, unsigned int len) +{ + if ( len <= *len1 ) + { + memcpy(target, *buf1, len); + *buf1 += len; + *len1 -= len; + } + else + { + memcpy(target, *buf1, *len1); + target = (char *)target + *len1; + len -= *len1; + *buf1 = *buf2; + *len1 = *len2; + *buf2 = NULL; + *len2 = 0; + if ( len > *len1 ) + { + printk("9pfs: short copy (dropping %u bytes)\n", len - *len1); + len = *len1; + } + memcpy(target, *buf1, *len1); + } +} + +static void rcv_9p_copy(struct dev_9pfs *dev, struct req *req, + struct p9_header *hdr, const char *fmt, va_list ap) +{ + struct p9_header *h = hdr ? hdr : (void *)req->data; + RING_IDX cons = dev->cons_pvt_in + h->size - sizeof(*h); + RING_IDX ring_size = XEN_FLEX_RING_SIZE(dev->ring_order); + unsigned char *buf1, *buf2; + unsigned int len1, len2; + const char *f; + char *str; + uint16_t len; + uint32_t err; + uint32_t *val; + char **strval; + uint8_t *qval; + + if ( hdr ) + { + buf1 = xen_9pfs_get_ring_ptr(dev->data.in, dev->cons_pvt_in, ring_size); + buf2 = xen_9pfs_get_ring_ptr(dev->data.in, 0, ring_size); + len1 = ring_size - xen_9pfs_mask(dev->cons_pvt_in, ring_size); + if ( len1 > h->size - sizeof(*h) ) + len1 = h->size - sizeof(*h); + len2 = h->size - sizeof(*h) - len1; + } + else + { + buf1 = req->data + sizeof(*h); + buf2 = NULL; + len1 = h->size - sizeof(*h); + len2 = 0; + } + + if ( h->cmd == P9_CMD_ERROR ) + { + copy_bufs(&buf1, &buf2, &len1, &len2, &len, sizeof(len)); + str = malloc(len + 1); + copy_bufs(&buf1, &buf2, &len1, &len2, str, len); + str[len] = 0; + printk("9pfs: request %u resulted in \"%s\"\n", req->cmd, str); + free(str); + err = EIO; + copy_bufs(&buf1, &buf2, &len1, &len2, &err, sizeof(err)); + req->result = err; + + if ( hdr ) + dev->cons_pvt_in = cons; + + return; + } + + if ( h->cmd != req->cmd + 1 ) + { + req->result = EDOM; + printk("9pfs: illegal response: wrong return type (%u instead of %u)\n", + h->cmd, req->cmd + 1); + + if ( hdr ) + dev->cons_pvt_in = cons; + + return; + } + + req->result = 0; + + for ( f = fmt; *f; f++ ) + { + switch ( *f ) + { + case 'U': + val = va_arg(ap, uint32_t *); + copy_bufs(&buf1, &buf2, &len1, &len2, val, sizeof(*val)); + break; + case 'S': + strval = va_arg(ap, char **); + copy_bufs(&buf1, &buf2, &len1, &len2, &len, sizeof(len)); + *strval = malloc(len + 1); + copy_bufs(&buf1, &buf2, &len1, &len2, *strval, len); + (*strval)[len] = 0; + break; + case 'Q': + qval = va_arg(ap, uint8_t *); + copy_bufs(&buf1, &buf2, &len1, &len2, qval, P9_QID_SIZE); + break; + default: + printk("rcv_9p: unknown format character %c\n", *f); + break; + } + } + + if ( hdr ) + dev->cons_pvt_in = cons; +} + +static bool rcv_9p_one(struct dev_9pfs *dev, struct req *req, const char *fmt, + va_list ap) +{ + struct p9_header hdr; + struct req *tmp; + + if ( req->data ) + { + rcv_9p_copy(dev, req, NULL, fmt, ap); + free(req->data); + req->data = NULL; + + return true; + } + + wait_event(dev->waitq, ring_in_data(dev) >= sizeof(hdr)); + + copy_from_ring(dev, &hdr, sizeof(hdr)); + + wait_event(dev->waitq, ring_in_data(dev) >= hdr.size - sizeof(hdr)); + + tmp = dev->req + hdr.tag; + if ( hdr.tag >= N_REQS || !tmp->inflight ) + { + printk("9pfs: illegal response: %s\n", + hdr.tag >= N_REQS ? "tag out of bounds" : "request not pending"); + dev->cons_pvt_in += hdr.size - sizeof(hdr); + + return false; + } + + tmp->inflight = false; + + if ( tmp != req ) + { + tmp->data = malloc(hdr.size); + memcpy(tmp->data, &hdr, sizeof(hdr)); + copy_from_ring(dev, tmp->data + sizeof(hdr), hdr.size - sizeof(hdr)); + + return false; + } + + rcv_9p_copy(dev, req, &hdr, fmt, ap); + + return true; +} + +static void rcv_9p(struct dev_9pfs *dev, struct req *req, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + + down(&dev->ring_in_sem); + + while ( !rcv_9p_one(dev, req, fmt, ap) ); + + rmb(); /* Read all data before updating ring index. */ + dev->intf->in_cons = dev->cons_pvt_in; + + notify_remote_via_evtchn(dev->evtchn); + + up(&dev->ring_in_sem); + + va_end(ap); +} + +static int p9_version(struct dev_9pfs *dev) +{ + unsigned int msize = XEN_FLEX_RING_SIZE(dev->ring_order) / 2; + struct req *req = get_free_req(dev); + char *verret; + int ret; + + if ( !req ) + return EAGAIN; + + req->cmd = P9_CMD_VERSION; + send_9p(dev, req, "US", msize, P9_VERSION); + rcv_9p(dev, req, "US", &dev->msize_max, &verret); + ret = req->result; + + put_free_req(dev, req); + + if ( ret ) + return ret; + + if ( strcmp(verret, P9_VERSION) ) + ret = ENOMSG; + free(verret); + + return ret; +} + +static int p9_attach(struct dev_9pfs *dev) +{ + uint32_t fid = P9_ROOT_FID; + uint32_t afid = 0; + uint32_t uid = 0; + uint8_t qid[P9_QID_SIZE]; + struct req *req = get_free_req(dev); + int ret; + + if ( !req ) + return EAGAIN; + + req->cmd = P9_CMD_ATTACH; + send_9p(dev, req, "UUSSU", fid, afid, "root", "root", uid); + rcv_9p(dev, req, "Q", qid); + ret = req->result; + + put_free_req(dev, req); + + return ret; +} + +static int connect_9pfs(struct dev_9pfs *dev) +{ + int ret; + + ret = p9_version(dev); + if ( ret ) + return ret; + + return p9_attach(dev); +} + static void intr_9pfs(evtchn_port_t port, struct pt_regs *regs, void *data) { + struct dev_9pfs *dev = data; + + wake_up(&dev->waitq); } static int open_9pfs(struct mount_point *mnt, const char *pathname, int flags, @@ -87,6 +549,16 @@ void *init_9pfront(unsigned int id, const char *mnt) memset(dev, 0, sizeof(*dev)); snprintf(dev->nodename, sizeof(dev->nodename), "device/9pfs/%u", id); dev->id = id; + init_waitqueue_head(&dev->waitq); + init_SEMAPHORE(&dev->ring_out_sem, 1); + init_SEMAPHORE(&dev->ring_in_sem, 1); + + for ( i = 0; i < N_REQS; i++ ) + { + dev->req[i].id = i; + dev->req[i].next_free = i + 1; + } + dev->free_reqs = 0; msg = xenbus_read_unsigned(XBT_NIL, dev->nodename, "backend-id", &dev->dom); if ( msg ) @@ -205,6 +677,12 @@ void *init_9pfront(unsigned int id, const char *mnt) unmask_evtchn(dev->evtchn); + if ( connect_9pfs(dev) ) + { + reason = "9pfs connect failed"; + goto err; + } + dev->mnt = mnt; if ( mount(dev->mnt, dev, open_9pfs) ) { From patchwork Fri Feb 10 10:46:27 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juergen Gross X-Patchwork-Id: 13135681 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id DDD84C636CD for ; Fri, 10 Feb 2023 10:55:35 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.493311.763208 (Exim 4.92) (envelope-from ) id 1pQR3w-0003Hq-BJ; Fri, 10 Feb 2023 10:55:28 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 493311.763208; Fri, 10 Feb 2023 10:55:28 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pQR3w-0003Hh-7H; Fri, 10 Feb 2023 10:55:28 +0000 Received: by outflank-mailman (input) for mailman id 493311; Fri, 10 Feb 2023 10:55:26 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pQQvt-000617-JG for xen-devel@lists.xenproject.org; Fri, 10 Feb 2023 10:47:09 +0000 Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id 4205029c-a930-11ed-93b5-47a8fe42b414; Fri, 10 Feb 2023 11:47:05 +0100 (CET) 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-out2.suse.de (Postfix) with ESMTPS id D5DC85CA5F; Fri, 10 Feb 2023 10:47:04 +0000 (UTC) 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 A94551325E; Fri, 10 Feb 2023 10:47:04 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id hKAUKKgg5mMOVAAAMHmgww (envelope-from ); Fri, 10 Feb 2023 10:47:04 +0000 X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 4205029c-a930-11ed-93b5-47a8fe42b414 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1676026024; 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=yGjQysJi2clZT+3RgGQtfxmXBb6C9V7YM0oN6qZktqE=; b=DN7mFMD2WhwPI+vBEQysLSoQpzspVI+X7+tFvlT64t5SwokXtsCOVozaggSUNqFJohmiWa GPaIB7A+v1JqrAGshcJS5d8/taM0oth79rDulBOGh1vNWhpYdgvgQ0Ek28D3UskYv5fLEg Li1ljbnDQ5RnOI5M/YHTrljgjK10JR0= From: Juergen Gross To: minios-devel@lists.xenproject.org, xen-devel@lists.xenproject.org Cc: samuel.thibault@ens-lyon.org, wl@xen.org, Juergen Gross Subject: [PATCH v2 6/7] Mini-OS: add open and close handling to the 9pfs frontend Date: Fri, 10 Feb 2023 11:46:27 +0100 Message-Id: <20230210104628.14374-7-jgross@suse.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230210104628.14374-1-jgross@suse.com> References: <20230210104628.14374-1-jgross@suse.com> MIME-Version: 1.0 Add the open() and close() support to the 9pfs frontend. This requires to split the path name and to walk to the desired directory level. Signed-off-by: Juergen Gross --- V2: - check path to be canonical - avoid short read when walking the path - fix get_fid() (Samuel Thibault) - return EAGAIN if no free request got (Samuel Thibault) --- 9pfront.c | 320 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 318 insertions(+), 2 deletions(-) diff --git a/9pfront.c b/9pfront.c index 0b8d5461..b4c54535 100644 --- a/9pfront.c +++ b/9pfront.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -52,13 +53,32 @@ struct dev_9pfs { struct wait_queue_head waitq; struct semaphore ring_out_sem; struct semaphore ring_in_sem; + + unsigned long long fid_mask; /* Bit mask for free fids. */ +}; + +struct file_9pfs { + uint32_t fid; + struct dev_9pfs *dev; + bool append; }; #define DEFAULT_9PFS_RING_ORDER 4 +/* P9 protocol commands (response is either cmd+1 or P9_CMD_ERROR). */ #define P9_CMD_VERSION 100 #define P9_CMD_ATTACH 104 #define P9_CMD_ERROR 107 +#define P9_CMD_WALK 110 +#define P9_CMD_OPEN 112 +#define P9_CMD_CREATE 114 +#define P9_CMD_CLUNK 120 + +/* P9 protocol open flags. */ +#define P9_OREAD 0 /* read */ +#define P9_OWRITE 1 /* write */ +#define P9_ORDWR 2 /* read and write */ +#define P9_OTRUNC 16 /* or'ed in, truncate file first */ #define P9_QID_SIZE 13 @@ -69,10 +89,27 @@ struct p9_header { } __attribute__((packed)); #define P9_VERSION "9P2000.u" -#define P9_ROOT_FID ~0 +#define P9_ROOT_FID 0 static unsigned int ftype_9pfs; +static unsigned int get_fid(struct dev_9pfs *dev) +{ + unsigned int fid; + + fid = ffs(dev->fid_mask); + if ( fid ) + dev->fid_mask &= ~(1ULL << (fid - 1)); + + return fid; +} + +static void put_fid(struct dev_9pfs *dev, unsigned int fid) +{ + if ( fid ) + dev->fid_mask |= 1ULL << (fid - 1); +} + static struct req *get_free_req(struct dev_9pfs *dev) { struct req *req; @@ -140,6 +177,9 @@ static void copy_from_ring(struct dev_9pfs *dev, void *data, unsigned int len) * send_9p() and rcv_9p() are using a special format string for specifying * the kind of data sent/expected. Each data item is represented by a single * character: + * b: 1 byte unsigned integer (uint8_t) + * Only valid for sending. + * u: 2 byte unsigned integer (uint16_t) * U: 4 byte unsigned integer (uint32_t) * S: String (2 byte length + characters) * in the rcv_9p() case the data for string is allocated (length omitted, @@ -153,7 +193,9 @@ static void send_9p(struct dev_9pfs *dev, struct req *req, const char *fmt, ...) va_list ap, aq; const char *f; uint32_t intval; + uint16_t shortval; uint16_t len; + uint8_t byte; char *strval; hdr.size = sizeof(hdr); @@ -167,6 +209,14 @@ static void send_9p(struct dev_9pfs *dev, struct req *req, const char *fmt, ...) { switch ( *f ) { + case 'b': + hdr.size += 1; + byte = va_arg(aq, unsigned int); + break; + case 'u': + hdr.size += 2; + shortval = va_arg(aq, unsigned int); + break; case 'U': hdr.size += 4; intval = va_arg(aq, unsigned int); @@ -196,6 +246,14 @@ static void send_9p(struct dev_9pfs *dev, struct req *req, const char *fmt, ...) { switch ( *f ) { + case 'b': + byte = va_arg(ap, unsigned int); + copy_to_ring(dev, &byte, sizeof(byte)); + break; + case 'u': + shortval = va_arg(ap, unsigned int); + copy_to_ring(dev, &shortval, sizeof(shortval)); + break; case 'U': intval = va_arg(ap, unsigned int); copy_to_ring(dev, &intval, sizeof(intval)); @@ -288,6 +346,7 @@ static void rcv_9p_copy(struct dev_9pfs *dev, struct req *req, char *str; uint16_t len; uint32_t err; + uint16_t *shortval; uint32_t *val; char **strval; uint8_t *qval; @@ -345,6 +404,10 @@ static void rcv_9p_copy(struct dev_9pfs *dev, struct req *req, { switch ( *f ) { + case 'u': + shortval = va_arg(ap, uint16_t *); + copy_bufs(&buf1, &buf2, &len1, &len2, shortval, sizeof(*shortval)); + break; case 'U': val = va_arg(ap, uint32_t *); copy_bufs(&buf1, &buf2, &len1, &len2, val, sizeof(*val)); @@ -486,6 +549,166 @@ static int p9_attach(struct dev_9pfs *dev) return ret; } +static int p9_clunk(struct dev_9pfs *dev, uint32_t fid) +{ + struct req *req = get_free_req(dev); + int ret; + + if ( !req ) + return EAGAIN; + + req->cmd = P9_CMD_CLUNK; + send_9p(dev, req, "U", fid); + rcv_9p(dev, req, ""); + ret = req->result; + + put_free_req(dev, req); + + return ret; +} + +static int p9_walk(struct dev_9pfs *dev, uint32_t fid, uint32_t newfid, + char *name) +{ + struct req *req = get_free_req(dev); + int ret; + uint16_t nqid; + uint8_t qid[P9_QID_SIZE]; + + if ( !req ) + return EAGAIN; + + req->cmd = P9_CMD_WALK; + if ( name[0] ) + { + send_9p(dev, req, "UUuS", fid, newfid, 1, name); + rcv_9p(dev, req, "uQ", &nqid, qid); + } + else + { + send_9p(dev, req, "UUu", fid, newfid, 0); + rcv_9p(dev, req, "u", &nqid); + } + + ret = req->result; + + put_free_req(dev, req); + + return ret; +} + +static int p9_open(struct dev_9pfs *dev, uint32_t fid, uint8_t omode) +{ + struct req *req = get_free_req(dev); + int ret; + uint8_t qid[P9_QID_SIZE]; + uint32_t iounit; + + if ( !req ) + return EAGAIN; + + req->cmd = P9_CMD_OPEN; + send_9p(dev, req, "Ub", fid, omode); + rcv_9p(dev, req, "QU", qid, &iounit); + + ret = req->result; + + put_free_req(dev, req); + + return ret; +} + +static int p9_create(struct dev_9pfs *dev, uint32_t fid, char *path, + uint32_t mode, uint8_t omode) +{ + struct req *req = get_free_req(dev); + int ret; + uint8_t qid[P9_QID_SIZE]; + uint32_t iounit; + + if ( !req ) + return EAGAIN; + + req->cmd = P9_CMD_CREATE; + send_9p(dev, req, "USUbS", fid, path, mode, omode, ""); + rcv_9p(dev, req, "QU", qid, &iounit); + + ret = req->result; + + put_free_req(dev, req); + + return ret; +} + +/* + * Walk from root levels with the levels listed in <*paths> as a + * sequence of names. Returns the number of steps not having been able to + * walk, with <*paths> pointing at the name of the failing walk step. + * will be associated with the last successful walk step. Note that + * the first step should always succeed, as it is an empty walk in order + * to start at the root (needed for creating new files in root). + */ +static unsigned int walk_9pfs(struct dev_9pfs *dev, uint32_t fid, + unsigned int steps, char **paths) +{ + uint32_t curr_fid = P9_ROOT_FID; + int ret; + + while ( steps-- ) + { + ret = p9_walk(dev, curr_fid, fid, *paths); + if ( ret ) + return steps + 1; + curr_fid = fid; + *paths += strlen(*paths) + 1; + } + + return 0; +} + +static unsigned int split_path(const char *pathname, char **split_ptr) +{ + unsigned int parts = 1; + char *p; + + *split_ptr = strdup(pathname); + + for ( p = strchr(*split_ptr, '/'); p; p = strchr(p + 1, '/') ) + { + *p = 0; + parts++; + } + + return parts; +} + +static bool path_canonical(const char *pathname) +{ + unsigned int len = strlen(pathname); + const char *c; + + /* Empty path is allowed. */ + if ( !len ) + return true; + + /* No trailing '/'. */ + if ( pathname[len - 1] == '/' ) + return false; + + /* No self or parent references. */ + c = pathname; + while ( (c = strstr(c, "/.")) != NULL ) + { + if ( c[2] == '.' ) + c++; + if ( c[2] == 0 || c[2] == '/' ) + return false; + c += 2; + } + + return true; +} + static int connect_9pfs(struct dev_9pfs *dev) { int ret; @@ -504,10 +727,101 @@ static void intr_9pfs(evtchn_port_t port, struct pt_regs *regs, void *data) wake_up(&dev->waitq); } +static int close_9pfs(struct file *file) +{ + struct file_9pfs *f9pfs = file->filedata; + + if ( f9pfs->fid != P9_ROOT_FID ) + { + p9_clunk(f9pfs->dev, f9pfs->fid); + put_fid(f9pfs->dev, f9pfs->fid); + } + + free(f9pfs); + + return 0; +} + static int open_9pfs(struct mount_point *mnt, const char *pathname, int flags, mode_t mode) { - errno = ENOSYS; + int fd; + char *path = NULL; + char *p; + struct file *file; + struct file_9pfs *f9pfs; + uint16_t nwalk; + uint8_t omode; + int ret; + + if ( !path_canonical(pathname) ) + return EINVAL; + + f9pfs = calloc(1, sizeof(*f9pfs)); + f9pfs->dev = mnt->dev; + f9pfs->fid = P9_ROOT_FID; + + fd = alloc_fd(ftype_9pfs); + file = get_file_from_fd(fd); + file->filedata = f9pfs; + + switch ( flags & O_ACCMODE ) + { + case O_RDONLY: + omode = P9_OREAD; + break; + case O_WRONLY: + omode = P9_OWRITE; + break; + case O_RDWR: + omode = P9_ORDWR; + break; + default: + ret = EINVAL; + goto err; + } + + if ( flags & O_TRUNC ) + omode |= P9_OTRUNC; + f9pfs->append = flags & O_APPEND; + + nwalk = split_path(pathname, &path); + + f9pfs->fid = get_fid(mnt->dev); + if ( !f9pfs->fid ) + { + ret = ENFILE; + goto err; + } + p = path; + nwalk = walk_9pfs(mnt->dev, f9pfs->fid, nwalk, &p); + if ( nwalk ) + { + if ( nwalk > 1 || !(flags & O_CREAT) ) + { + ret = ENOENT; + goto err; + } + + ret = p9_create(mnt->dev, f9pfs->fid, p, mode, omode); + if ( ret ) + goto err; + goto out; + } + + ret = p9_open(mnt->dev, f9pfs->fid, omode); + if ( ret ) + goto err; + + out: + free(path); + + return fd; + + err: + free(path); + close(fd); + errno = ret; return -1; } @@ -552,6 +866,7 @@ void *init_9pfront(unsigned int id, const char *mnt) init_waitqueue_head(&dev->waitq); init_SEMAPHORE(&dev->ring_out_sem, 1); init_SEMAPHORE(&dev->ring_in_sem, 1); + dev->fid_mask = ~0ULL; for ( i = 0; i < N_REQS; i++ ) { @@ -753,6 +1068,7 @@ void shutdown_9pfront(void *dev) static const struct file_ops ops_9pfs = { .name = "9pfs", + .close = close_9pfs, }; __attribute__((constructor)) From patchwork Fri Feb 10 10:46:28 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juergen Gross X-Patchwork-Id: 13135678 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2FB21C05027 for ; Fri, 10 Feb 2023 10:47:23 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.493274.763166 (Exim 4.92) (envelope-from ) id 1pQQvw-0008P8-J2; Fri, 10 Feb 2023 10:47:12 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 493274.763166; Fri, 10 Feb 2023 10:47:12 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pQQvw-0008P1-GC; Fri, 10 Feb 2023 10:47:12 +0000 Received: by outflank-mailman (input) for mailman id 493274; Fri, 10 Feb 2023 10:47:11 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pQQvv-0005jA-Mw for xen-devel@lists.xenproject.org; Fri, 10 Feb 2023 10:47:11 +0000 Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id 45732faa-a930-11ed-933c-83870f6b2ba8; Fri, 10 Feb 2023 11:47:10 +0100 (CET) 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 9B2403FEC6; Fri, 10 Feb 2023 10:47:10 +0000 (UTC) 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 6202C1325E; Fri, 10 Feb 2023 10:47:10 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id ApZvFq4g5mMjVAAAMHmgww (envelope-from ); Fri, 10 Feb 2023 10:47:10 +0000 X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 45732faa-a930-11ed-933c-83870f6b2ba8 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1676026030; 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=eQI5EY4iGPACMuqIgP0kKRTaNVN1WVxx1P8uV/lIB7o=; b=oV9d+cW6hqWzg0jCv6JPRO0kUaBN5Zgsf8SQZg5LpJMKDYArbtsjuJ0TJpO2HQCgPOgkcV ywousDOOm1JjkmUDLWTFlFyU7YTy38rQanmoDmjXH67uJEImxpQI7+FJgkG7yE9rXQ4gsz e1RRnbRCO6el+4skulPXuq2mZ0oSWXU= From: Juergen Gross To: minios-devel@lists.xenproject.org, xen-devel@lists.xenproject.org Cc: samuel.thibault@ens-lyon.org, wl@xen.org, Juergen Gross Subject: [PATCH v2 7/7] Mini-OS: add read and write support to 9pfsfront Date: Fri, 10 Feb 2023 11:46:28 +0100 Message-Id: <20230210104628.14374-8-jgross@suse.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230210104628.14374-1-jgross@suse.com> References: <20230210104628.14374-1-jgross@suse.com> MIME-Version: 1.0 Add support to read from and write to a file handled by 9pfsfront. Signed-off-by: Juergen Gross --- V2: - add check for max message size - return EAGAIN in case no free request got (Samuel Thibault) - loop until all data read/written (Samuel Thibault) --- 9pfront.c | 211 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) diff --git a/9pfront.c b/9pfront.c index b4c54535..c606c437 100644 --- a/9pfront.c +++ b/9pfront.c @@ -72,7 +72,10 @@ struct file_9pfs { #define P9_CMD_WALK 110 #define P9_CMD_OPEN 112 #define P9_CMD_CREATE 114 +#define P9_CMD_READ 116 +#define P9_CMD_WRITE 118 #define P9_CMD_CLUNK 120 +#define P9_CMD_STAT 124 /* P9 protocol open flags. */ #define P9_OREAD 0 /* read */ @@ -88,11 +91,39 @@ struct p9_header { uint16_t tag; } __attribute__((packed)); +struct p9_stat { + uint16_t size; + uint16_t type; + uint32_t dev; + uint8_t qid[13]; + uint32_t mode; + uint32_t atime; + uint32_t mtime; + uint64_t length; + char *name; + char *uid; + char *gid; + char *muid; + char *extension; + uint32_t n_uid; + uint32_t n_gid; + uint32_t n_muid; +}; + #define P9_VERSION "9P2000.u" #define P9_ROOT_FID 0 static unsigned int ftype_9pfs; +static void free_stat(struct p9_stat *stat) +{ + free(stat->name); + free(stat->uid); + free(stat->gid); + free(stat->muid); + free(stat->extension); +} + static unsigned int get_fid(struct dev_9pfs *dev) { unsigned int fid; @@ -181,9 +212,12 @@ static void copy_from_ring(struct dev_9pfs *dev, void *data, unsigned int len) * Only valid for sending. * u: 2 byte unsigned integer (uint16_t) * U: 4 byte unsigned integer (uint32_t) + * L: 8 byte unsigned integer (uint64_t) * S: String (2 byte length + characters) * in the rcv_9p() case the data for string is allocated (length omitted, * string terminated by a NUL character) + * D: Binary data (4 byte length + bytes of data), requires a length + * and a buffer pointer parameter. * Q: A 13 byte "qid", consisting of 1 byte file type, 4 byte file version * and 8 bytes unique file id. Only valid for receiving. */ @@ -192,10 +226,12 @@ static void send_9p(struct dev_9pfs *dev, struct req *req, const char *fmt, ...) struct p9_header hdr; va_list ap, aq; const char *f; + uint64_t longval; uint32_t intval; uint16_t shortval; uint16_t len; uint8_t byte; + uint8_t *data; char *strval; hdr.size = sizeof(hdr); @@ -221,11 +257,21 @@ static void send_9p(struct dev_9pfs *dev, struct req *req, const char *fmt, ...) hdr.size += 4; intval = va_arg(aq, unsigned int); break; + case 'L': + hdr.size += 8; + longval = va_arg(aq, uint64_t); + break; case 'S': hdr.size += 2; strval = va_arg(aq, char *); hdr.size += strlen(strval); break; + case 'D': + hdr.size += 4; + intval = va_arg(aq, unsigned int); + hdr.size += intval; + data = va_arg(aq, uint8_t *); + break; default: printk("send_9p: unknown format character %c\n", *f); break; @@ -258,12 +304,22 @@ static void send_9p(struct dev_9pfs *dev, struct req *req, const char *fmt, ...) intval = va_arg(ap, unsigned int); copy_to_ring(dev, &intval, sizeof(intval)); break; + case 'L': + longval = va_arg(ap, uint64_t); + copy_to_ring(dev, &longval, sizeof(longval)); + break; case 'S': strval = va_arg(ap, char *); len = strlen(strval); copy_to_ring(dev, &len, sizeof(len)); copy_to_ring(dev, strval, len); break; + case 'D': + intval = va_arg(ap, unsigned int); + copy_to_ring(dev, &intval, sizeof(intval)); + data = va_arg(ap, uint8_t *); + copy_to_ring(dev, data, intval); + break; } } @@ -348,6 +404,8 @@ static void rcv_9p_copy(struct dev_9pfs *dev, struct req *req, uint32_t err; uint16_t *shortval; uint32_t *val; + uint64_t *longval; + uint8_t *data; char **strval; uint8_t *qval; @@ -412,6 +470,10 @@ static void rcv_9p_copy(struct dev_9pfs *dev, struct req *req, val = va_arg(ap, uint32_t *); copy_bufs(&buf1, &buf2, &len1, &len2, val, sizeof(*val)); break; + case 'L': + longval = va_arg(ap, uint64_t *); + copy_bufs(&buf1, &buf2, &len1, &len2, longval, sizeof(*longval)); + break; case 'S': strval = va_arg(ap, char **); copy_bufs(&buf1, &buf2, &len1, &len2, &len, sizeof(len)); @@ -419,6 +481,12 @@ static void rcv_9p_copy(struct dev_9pfs *dev, struct req *req, copy_bufs(&buf1, &buf2, &len1, &len2, *strval, len); (*strval)[len] = 0; break; + case 'D': + val = va_arg(ap, uint32_t *); + data = va_arg(ap, uint8_t *); + copy_bufs(&buf1, &buf2, &len1, &len2, val, sizeof(*val)); + copy_bufs(&buf1, &buf2, &len1, &len2, data, *val); + break; case 'Q': qval = va_arg(ap, uint8_t *); copy_bufs(&buf1, &buf2, &len1, &len2, qval, P9_QID_SIZE); @@ -640,6 +708,110 @@ static int p9_create(struct dev_9pfs *dev, uint32_t fid, char *path, return ret; } +static int p9_stat(struct dev_9pfs *dev, uint32_t fid, struct p9_stat *stat) +{ + struct req *req = get_free_req(dev); + int ret; + + if ( !req ) + return EAGAIN; + + memset(stat, 0, sizeof(*stat)); + req->cmd = P9_CMD_STAT; + send_9p(dev, req, "U", fid); + rcv_9p(dev, req, "uuUQUUULSSSSSUUU", &stat->size, &stat->type, &stat->dev, + stat->qid, &stat->mode, &stat->atime, &stat->mtime, &stat->length, + &stat->name, &stat->uid, &stat->gid, &stat->muid, &stat->extension, + &stat->n_uid, &stat->n_gid, &stat->n_muid); + + ret = req->result; + + put_free_req(dev, req); + + return ret; +} + +static int p9_read(struct dev_9pfs *dev, uint32_t fid, uint64_t offset, + uint8_t *data, uint32_t len) +{ + struct req *req = get_free_req(dev); + int ret = 0; + uint32_t count; + + if ( !req ) + { + errno = EAGAIN; + return -1; + } + req->cmd = P9_CMD_READ; + + while ( len ) + { + count = len; + if ( count > dev->msize_max - 24 ) + count = dev->msize_max - 24; + + send_9p(dev, req, "ULU", fid, offset, count); + rcv_9p(dev, req, "D", &count, data); + + if ( !count ) + break; + if ( req->result ) + { + ret = -1; + errno = EIO; + break; + } + ret += count; + offset += count; + data += count; + len -= count; + } + + put_free_req(dev, req); + + return ret; +} + +static int p9_write(struct dev_9pfs *dev, uint32_t fid, uint64_t offset, + const uint8_t *data, uint32_t len) +{ + struct req *req = get_free_req(dev); + int ret = 0; + uint32_t count; + + if ( !req ) + { + errno = EAGAIN; + return -1; + } + req->cmd = P9_CMD_WRITE; + + while ( len ) + { + count = len; + if ( count > dev->msize_max - 24 ) + count = dev->msize_max - 24; + + send_9p(dev, req, "ULD", fid, offset, count, data); + rcv_9p(dev, req, "U", &count); + if ( req->result ) + { + ret = -1; + errno = EIO; + break; + } + ret += count; + offset += count; + data += count; + len -= count; + } + + put_free_req(dev, req); + + return ret; +} + /* * Walk from root levels with the levels listed in <*paths> as a * sequence of names. Returns the number of steps not having been able to @@ -727,6 +899,43 @@ static void intr_9pfs(evtchn_port_t port, struct pt_regs *regs, void *data) wake_up(&dev->waitq); } +static int read_9pfs(struct file *file, void *buf, size_t nbytes) +{ + struct file_9pfs *f9pfs = file->filedata; + int ret; + + ret = p9_read(f9pfs->dev, f9pfs->fid, file->offset, buf, nbytes); + if ( ret >= 0 ) + file->offset += ret; + + return ret; +} + +static int write_9pfs(struct file *file, const void *buf, size_t nbytes) +{ + struct file_9pfs *f9pfs = file->filedata; + struct p9_stat stat; + int ret; + + if ( f9pfs->append ) + { + ret = p9_stat(f9pfs->dev, f9pfs->fid, &stat); + free_stat(&stat); + if ( ret ) + { + errno = EIO; + return -1; + } + file->offset = stat.length; + } + + ret = p9_write(f9pfs->dev, f9pfs->fid, file->offset, buf, nbytes); + if ( ret >= 0 ) + file->offset += ret; + + return ret; +} + static int close_9pfs(struct file *file) { struct file_9pfs *f9pfs = file->filedata; @@ -1068,6 +1277,8 @@ void shutdown_9pfront(void *dev) static const struct file_ops ops_9pfs = { .name = "9pfs", + .read = read_9pfs, + .write = write_9pfs, .close = close_9pfs, };