From patchwork Fri Feb 3 09:18:03 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?SsO8cmdlbiBHcm/Dnw==?= X-Patchwork-Id: 13127252 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 6FA2CC6379F for ; Fri, 3 Feb 2023 09:18:41 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.489056.757370 (Exim 4.92) (envelope-from ) id 1pNsD7-00079R-VV; Fri, 03 Feb 2023 09:18:21 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 489056.757370; Fri, 03 Feb 2023 09:18:21 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pNsD7-000793-S6; Fri, 03 Feb 2023 09:18:21 +0000 Received: by outflank-mailman (input) for mailman id 489056; Fri, 03 Feb 2023 09:18:21 +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 1pNsD7-0006sG-8I for xen-devel@lists.xenproject.org; Fri, 03 Feb 2023 09:18:21 +0000 Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id b1f94e37-a3a3-11ed-933c-83870f6b2ba8; Fri, 03 Feb 2023 10:18:19 +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 D4C3C20FB1; Fri, 3 Feb 2023 09:18:17 +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 AB8B01346D; Fri, 3 Feb 2023 09:18:17 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id oqyuKFnR3GMREwAAMHmgww (envelope-from ); Fri, 03 Feb 2023 09:18:17 +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: b1f94e37-a3a3-11ed-933c-83870f6b2ba8 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1675415897; 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=z81Lk0F6Fek1HMkTBl7IwshhUmTJkCu1CQ5yFDMGHEk=; b=qPrMTeO36fOo9LpfULKQZr0DuSFU+In+5S3JH3QghH/n9PK7erMaAdu72JKpbbe8/P5tpp arucenRLw4PDxTzX+LHI8sYVY/XY21Ydwt/mmJzhmuQFZgcd/rb8iACWWNas2uVEi0uswy cFcQYoZxRsj2afrV/yqX99DzOtCIlGs= 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 1/7] Mini-OS: xenbus: add support for reading node from directory Date: Fri, 3 Feb 2023 10:18:03 +0100 Message-Id: <20230203091809.14478-2-jgross@suse.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230203091809.14478-1-jgross@suse.com> References: <20230203091809.14478-1-jgross@suse.com> MIME-Version: 1.0 Especially PV device drivers often need to read multiple Xenstore nodes from a common dirctory. Add support for reading a string or an unsigned value by specifying the directory and the node. Signed-off-by: Juergen Gross --- include/xenbus.h | 6 ++++++ xenbus.c | 39 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 42 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..811cde25 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,34 @@ 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; + + sscanf(str, "%u", value); + free(str); + + return NULL; +} + /* * Local variables: * mode: C From patchwork Fri Feb 3 09:18:04 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?SsO8cmdlbiBHcm/Dnw==?= X-Patchwork-Id: 13127253 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 5B2A5C636D6 for ; Fri, 3 Feb 2023 09:18:41 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.489057.757380 (Exim 4.92) (envelope-from ) id 1pNsDE-0007Tx-6g; Fri, 03 Feb 2023 09:18:28 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 489057.757380; Fri, 03 Feb 2023 09:18: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 1pNsDE-0007Tq-3j; Fri, 03 Feb 2023 09:18:28 +0000 Received: by outflank-mailman (input) for mailman id 489057; Fri, 03 Feb 2023 09:18: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 1pNsDC-0006pI-Ek for xen-devel@lists.xenproject.org; Fri, 03 Feb 2023 09:18:26 +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 b54821c0-a3a3-11ed-9254-a70e01b1f5fa; Fri, 03 Feb 2023 10:18:23 +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 6FA9D3447B; Fri, 3 Feb 2023 09:18:23 +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 48E911346D; Fri, 3 Feb 2023 09:18:23 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id KfqgEF/R3GMcEwAAMHmgww (envelope-from ); Fri, 03 Feb 2023 09:18:23 +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: b54821c0-a3a3-11ed-9254-a70e01b1f5fa DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1675415903; 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=u/eAoULjmKQ205Pb/0fKq3T8ckSspq3tkjdl4gh7sRs=; b=CWGwhVzTH3faw0JgioySSsL+u67Fu9JB16kROsA1CGyMu8YXLsaqi6t2DmoNR9S94xK3ll Llk00mmYQ9l6l4YZ9nh5mpuGobtmGGRh6AtpEwt5tXQcyUJ2suymbcTAJM9cApjGGe0Ef/ cMbNHex5rMnd25/Ra9QuSHXWbN6emWs= 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 2/7] Mini-OS: add concept of mount points Date: Fri, 3 Feb 2023 10:18:04 +0100 Message-Id: <20230203091809.14478-3-jgross@suse.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230203091809.14478-1-jgross@suse.com> References: <20230203091809.14478-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 --- 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..1475c621 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) -> %d\n", 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) -> %d\n", 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, 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 3 09:18:05 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?SsO8cmdlbiBHcm/Dnw==?= X-Patchwork-Id: 13127251 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 21BDBC61DA4 for ; Fri, 3 Feb 2023 09:18:41 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.489059.757396 (Exim 4.92) (envelope-from ) id 1pNsDH-0007oO-Gn; Fri, 03 Feb 2023 09:18:31 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 489059.757396; Fri, 03 Feb 2023 09:18:31 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pNsDH-0007oF-D1; Fri, 03 Feb 2023 09:18:31 +0000 Received: by outflank-mailman (input) for mailman id 489059; Fri, 03 Feb 2023 09:18:29 +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 1pNsDF-0006sG-OB for xen-devel@lists.xenproject.org; Fri, 03 Feb 2023 09:18:29 +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 b8a0311c-a3a3-11ed-933c-83870f6b2ba8; Fri, 03 Feb 2023 10:18:29 +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 079943447D; Fri, 3 Feb 2023 09:18:29 +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 D2CB01346D; Fri, 3 Feb 2023 09:18:28 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id Jm4sMmTR3GMkEwAAMHmgww (envelope-from ); Fri, 03 Feb 2023 09:18:28 +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: b8a0311c-a3a3-11ed-933c-83870f6b2ba8 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1675415909; 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=GtWQKRAyY57feFJk8BbUzmL2nez/i6gSp+ydtlu7X9A=; b=W2spmIMlIzYekMsW/Nktfe/U0VVGVGHAsO/wqtUDQBwSfMriG+gLhv4eU8qX16ZeD2kqxU ZwKQEMJBklXMCsymSYU8e5wjFP83bBCQJHQuI898uqC2ZZh+HcL+lDyUoAEP0pp2V4jebs xzCkqi97iujyPKCo0BapNivCn+zUZbs= 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 3/7] Mini-OS: add support for runtime mounts Date: Fri, 3 Feb 2023 10:18:05 +0100 Message-Id: <20230203091809.14478-4-jgross@suse.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230203091809.14478-1-jgross@suse.com> References: <20230203091809.14478-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 1475c621..4171bfd6 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 3 09:18:06 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?SsO8cmdlbiBHcm/Dnw==?= X-Patchwork-Id: 13127254 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 540C1C61DA4 for ; Fri, 3 Feb 2023 09:18:47 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.489066.757411 (Exim 4.92) (envelope-from ) id 1pNsDP-0008Mc-UT; Fri, 03 Feb 2023 09:18:39 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 489066.757411; Fri, 03 Feb 2023 09:18:39 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pNsDP-0008MR-Qf; Fri, 03 Feb 2023 09:18:39 +0000 Received: by outflank-mailman (input) for mailman id 489066; Fri, 03 Feb 2023 09:18:38 +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 1pNsDO-0006pI-2u for xen-devel@lists.xenproject.org; Fri, 03 Feb 2023 09:18:38 +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 bc0146c9-a3a3-11ed-9254-a70e01b1f5fa; Fri, 03 Feb 2023 10:18:34 +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 96F2020FB2; Fri, 3 Feb 2023 09:18:34 +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 678211346D; Fri, 3 Feb 2023 09:18:34 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id cND9F2rR3GMzEwAAMHmgww (envelope-from ); Fri, 03 Feb 2023 09:18:34 +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: bc0146c9-a3a3-11ed-9254-a70e01b1f5fa DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1675415914; 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=6iYbZqvNtZ/TCv37DDm/n8MEFIvNUWO9D/z+764HvEc=; b=PvSNSH+NewoOoU0ugPNEvH9zAz1FTuOTWeZRPgVfEAh2zOCt3CuVjrHsE/PVoffjxKN0EU JcvwnbAM8zx6M0mTZvzKCKjkZwm0qKCCIXNoNsUkPEH29Vb9hOPSYxgplT9PLN5adHiTON oTi/haqrs6ss8lsydRGnu13UQJRB4Q0= 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 4/7] Mini-OS: add 9pfs frontend Date: Fri, 3 Feb 2023 10:18:06 +0100 Message-Id: <20230203091809.14478-5-jgross@suse.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230203091809.14478-1-jgross@suse.com> References: <20230203091809.14478-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 --- 9pfront.c | 280 ++++++++++++++++++++++++++++++++++ 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, 292 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..cf4b5cb3 --- /dev/null +++ b/9pfront.c @@ -0,0 +1,280 @@ +/* + * 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 = NULL; + break; + } + } + free(version); + if ( v ) + { + reason = "version 1 not supported"; + 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 3 09:18:07 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?SsO8cmdlbiBHcm/Dnw==?= X-Patchwork-Id: 13127255 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 487F0C63797 for ; Fri, 3 Feb 2023 09:18:50 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.489072.757431 (Exim 4.92) (envelope-from ) id 1pNsDT-0000eH-QV; Fri, 03 Feb 2023 09:18:43 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 489072.757431; Fri, 03 Feb 2023 09:18: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 1pNsDT-0000e6-Jh; Fri, 03 Feb 2023 09:18:43 +0000 Received: by outflank-mailman (input) for mailman id 489072; Fri, 03 Feb 2023 09:18:42 +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 1pNsDS-0006sG-E6 for xen-devel@lists.xenproject.org; Fri, 03 Feb 2023 09:18:42 +0000 Received: from smtp-out2.suse.de (smtp-out2.suse.de [2001:67c:2178:6::1d]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id bf4baddc-a3a3-11ed-933c-83870f6b2ba8; Fri, 03 Feb 2023 10:18:40 +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 3189320FB2; Fri, 3 Feb 2023 09:18:40 +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 03E6F1346D; Fri, 3 Feb 2023 09:18:39 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id FRRGO2/R3GNDEwAAMHmgww (envelope-from ); Fri, 03 Feb 2023 09:18:39 +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: bf4baddc-a3a3-11ed-933c-83870f6b2ba8 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1675415920; 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=YKIS+Tj09UAtPDRHqh2MXWRos25VF1afTytdwvl7/5k=; b=KUuyPjwItpYs63kRYfGt/5oRDVOKuvoVf8vbVqFDCIx95OBQl8iVgUgkJHS5CRDVv/m8g7 EaGuJFoNQ313RSHZpRbvLvAPkx39b+PQFviBZwgjoZZp2JJa8EOTpZATR0RFk5XJ/LDiSF iAuxKUZNA28rNLGDbAMyUv39EQdaw00= 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 5/7] Mini-OS: add 9pfs transport layer Date: Fri, 3 Feb 2023 10:18:07 +0100 Message-Id: <20230203091809.14478-6-jgross@suse.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230203091809.14478-1-jgross@suse.com> References: <20230203091809.14478-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 --- 9pfront.c | 451 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 451 insertions(+) diff --git a/9pfront.c b/9pfront.c index cf4b5cb3..f6fac50a 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,443 @@ 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 + +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. + */ +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 ) + 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, 13); + 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; + + 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 ENOENT; + + 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[13]; + struct req *req = get_free_req(dev); + int ret; + + if ( !req ) + return ENOENT; + + 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 +522,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 ) @@ -199,6 +644,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 3 09:18:08 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?SsO8cmdlbiBHcm/Dnw==?= X-Patchwork-Id: 13127256 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 E5116C61DA4 for ; Fri, 3 Feb 2023 09:18:55 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.489077.757441 (Exim 4.92) (envelope-from ) id 1pNsDZ-00019E-2e; Fri, 03 Feb 2023 09:18:49 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 489077.757441; Fri, 03 Feb 2023 09:18:49 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pNsDY-000191-Uc; Fri, 03 Feb 2023 09:18:48 +0000 Received: by outflank-mailman (input) for mailman id 489077; Fri, 03 Feb 2023 09:18:47 +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 1pNsDW-0006sG-Qr for xen-devel@lists.xenproject.org; Fri, 03 Feb 2023 09:18:47 +0000 Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id c2af7a08-a3a3-11ed-933c-83870f6b2ba8; Fri, 03 Feb 2023 10:18:46 +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 DCDDF20FB3; Fri, 3 Feb 2023 09:18:45 +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 B12891346D; Fri, 3 Feb 2023 09:18:45 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id qiq+KXXR3GNOEwAAMHmgww (envelope-from ); Fri, 03 Feb 2023 09:18:45 +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: c2af7a08-a3a3-11ed-933c-83870f6b2ba8 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1675415925; 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=DTiD9k1sCY7qPC5hUeI+17ax3Vq23ag+y7zk3UOd7aM=; b=SLfU45Jhn6S379Qf7olIldMyNbApKjP//8ON7kw9NH2TA2HhAExqlDviup7UwFR8krpqGm cl7Yqor4zT6gA1x/RrG419ScopckPtWmEuzvQGnGzygUL25bfNvZUaou/IWHJzZpn2HhB+ 6DWrguxS5RC/61hvj9l6XxIBLOk/3ws= 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 6/7] Mini-OS: add open and close handling to the 9pfs frontend Date: Fri, 3 Feb 2023 10:18:08 +0100 Message-Id: <20230203091809.14478-7-jgross@suse.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230203091809.14478-1-jgross@suse.com> References: <20230203091809.14478-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. The opened file needs to be queried via stat in order to obtain the data needed for proper access (access rights, size, type of file). Signed-off-by: Juergen Gross --- 9pfront.c | 285 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 283 insertions(+), 2 deletions(-) diff --git a/9pfront.c b/9pfront.c index f6fac50a..ebe48601 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 */ struct p9_header { uint32_t size; @@ -67,10 +87,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; @@ -138,6 +175,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, @@ -151,7 +191,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); @@ -165,6 +207,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); @@ -194,6 +244,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)); @@ -263,6 +321,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; @@ -320,6 +379,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)); @@ -459,6 +522,134 @@ 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 ENOENT; + + 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[13]; + + if ( !req ) + return ENOENT; + + req->cmd = P9_CMD_WALK; + if ( name[0] ) + send_9p(dev, req, "UUuS", fid, newfid, 1, name); + else + send_9p(dev, req, "UUu", fid, newfid, 0); + rcv_9p(dev, req, "uQ", &nqid, qid); + + 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[13]; + uint32_t iounit; + + if ( !req ) + return ENOENT; + + 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[13]; + uint32_t iounit; + + if ( !req ) + return ENOENT; + + 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 int connect_9pfs(struct dev_9pfs *dev) { int ret; @@ -477,10 +668,98 @@ 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; + + 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 + strlen(mnt->path), &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; } @@ -525,6 +804,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++ ) { @@ -720,6 +1000,7 @@ void shutdown_9pfront(void *dev) static const struct file_ops ops_9pfs = { .name = "9pfs", + .close = close_9pfs, }; __attribute__((constructor)) From patchwork Fri Feb 3 09:18:09 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?SsO8cmdlbiBHcm/Dnw==?= X-Patchwork-Id: 13127283 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 1EFEEC636CC for ; Fri, 3 Feb 2023 09:25:59 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.489109.757456 (Exim 4.92) (envelope-from ) id 1pNsKB-0003xt-5j; Fri, 03 Feb 2023 09:25:39 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 489109.757456; Fri, 03 Feb 2023 09:25:39 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pNsKB-0003xm-2f; Fri, 03 Feb 2023 09:25:39 +0000 Received: by outflank-mailman (input) for mailman id 489109; Fri, 03 Feb 2023 09:25:38 +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 1pNsDf-0006pI-R8 for xen-devel@lists.xenproject.org; Fri, 03 Feb 2023 09:18:55 +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 c5face31-a3a3-11ed-9254-a70e01b1f5fa; Fri, 03 Feb 2023 10:18:51 +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 7053320FB3; Fri, 3 Feb 2023 09:18:51 +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 4555A1346D; Fri, 3 Feb 2023 09:18:51 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id 9tKnD3vR3GNUEwAAMHmgww (envelope-from ); Fri, 03 Feb 2023 09:18:51 +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: c5face31-a3a3-11ed-9254-a70e01b1f5fa DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1675415931; 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=Idrvyq/CByJ2DQQaGlOqPT2h9f5xudP46VSUBxT02f4=; b=WCQLk/QNq/M3jtl676+Yekybd2+OHWkHTOJVlXFQBkfIH5X6FBwVSiLfrd0f7L5TsqsUT8 mKYp2zgWqZzwgyCUmMlt+tCS08ZXNNHI9ikDDCfpqNTYAy0mtI3yBzClQ6AnoFCa2p266N HOMi8OXMPyPbsE38ZSWpET58cGWFibY= 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 7/7] Mini-OS: add read and write support to 9pfsfront Date: Fri, 3 Feb 2023 10:18:09 +0100 Message-Id: <20230203091809.14478-8-jgross@suse.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230203091809.14478-1-jgross@suse.com> References: <20230203091809.14478-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 --- 9pfront.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) diff --git a/9pfront.c b/9pfront.c index ebe48601..45f2f9a9 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 */ @@ -86,11 +89,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; @@ -179,9 +210,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. */ @@ -190,10 +224,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); @@ -219,11 +255,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; @@ -256,12 +302,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; } } @@ -323,6 +379,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; @@ -387,6 +445,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)); @@ -394,6 +456,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, 13); @@ -608,6 +676,88 @@ 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 ENOENT; + + 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; + uint32_t count; + + if ( !req ) + { + errno = EIO; + return -1; + } + + req->cmd = P9_CMD_READ; + send_9p(dev, req, "ULU", fid, offset, len); + rcv_9p(dev, req, "D", &count, data); + + if ( req->result ) + { + ret = -1; + errno = EIO; + } + else + ret = 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; + uint32_t count; + + if ( !req ) + { + errno = EIO; + return -1; + } + + req->cmd = P9_CMD_WRITE; + send_9p(dev, req, "ULD", fid, offset, len, data); + rcv_9p(dev, req, "U", &count); + if ( req->result ) + { + ret = -1; + errno = EIO; + } + else + ret = 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 @@ -668,6 +818,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; @@ -1000,6 +1187,8 @@ void shutdown_9pfront(void *dev) static const struct file_ops ops_9pfs = { .name = "9pfs", + .read = read_9pfs, + .write = write_9pfs, .close = close_9pfs, };