From patchwork Mon Feb 13 08:44: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: 13137941 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 AC5D3C636CC for ; Mon, 13 Feb 2023 08:44:37 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.494207.764207 (Exim 4.92) (envelope-from ) id 1pRURj-0005Kp-24; Mon, 13 Feb 2023 08:44:23 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 494207.764207; Mon, 13 Feb 2023 08:44:23 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pRURi-0005Kg-UG; Mon, 13 Feb 2023 08:44:22 +0000 Received: by outflank-mailman (input) for mailman id 494207; Mon, 13 Feb 2023 08:44:22 +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 1pRURi-00053b-8Y for xen-devel@lists.xenproject.org; Mon, 13 Feb 2023 08:44:22 +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 9bda6e54-ab7a-11ed-933c-83870f6b2ba8; Mon, 13 Feb 2023 09:44:20 +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 95DCF67B09; Mon, 13 Feb 2023 08:44:21 +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 6D2A21391B; Mon, 13 Feb 2023 08:44:21 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id VAl9GWX46WMuRAAAMHmgww (envelope-from ); Mon, 13 Feb 2023 08:44:21 +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: 9bda6e54-ab7a-11ed-933c-83870f6b2ba8 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1676277861; 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=U4WUHNcXaKUs5EWJgyYOwx2UyA3oTZifWWQZCeAXA8E=; b=r91MzCy85Iz1/IfPwuNm+gVo6sS8uA04Tq51j4D7DN/0uBFeYTGxHmfLk5yiywCZbf8d6T udqXCa918VMQ+NMjKC7jCIr1fSLuylUAGZkkgITcfp8L0vXHP6QalG4N/BOyWNkewUwjCA eZVNhUqOzaW/mjJ2D+Bx2trwCwEyO4k= 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 v3 1/7] Mini-OS: xenbus: add support for reading node from directory Date: Mon, 13 Feb 2023 09:44:06 +0100 Message-Id: <20230213084412.21065-2-jgross@suse.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230213084412.21065-1-jgross@suse.com> References: <20230213084412.21065-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 Mon Feb 13 08:44: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: 13137943 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 C0A11C64EC4 for ; Mon, 13 Feb 2023 08:44:37 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.494210.764226 (Exim 4.92) (envelope-from ) id 1pRURq-0005kd-FL; Mon, 13 Feb 2023 08:44:30 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 494210.764226; Mon, 13 Feb 2023 08:44:30 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pRURq-0005kU-Ar; Mon, 13 Feb 2023 08:44:30 +0000 Received: by outflank-mailman (input) for mailman id 494210; Mon, 13 Feb 2023 08:44: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 1pRURp-00053b-AI for xen-devel@lists.xenproject.org; Mon, 13 Feb 2023 08:44:29 +0000 Received: from smtp-out1.suse.de (smtp-out1.suse.de [2001:67c:2178:6::1c]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id 9f3030d6-ab7a-11ed-933c-83870f6b2ba8; Mon, 13 Feb 2023 09:44:26 +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 30DED37870; Mon, 13 Feb 2023 08:44:27 +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 03E4E1391B; Mon, 13 Feb 2023 08:44:26 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id yNUpO2r46WM2RAAAMHmgww (envelope-from ); Mon, 13 Feb 2023 08:44:26 +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: 9f3030d6-ab7a-11ed-933c-83870f6b2ba8 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1676277867; 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=19ujpdeO6r/ntB3v/0hzqQCc5N6kEKU3yTBXBtOtbZg=; b=UxYiQRhP1uw/dAULpCCF9xOTAqeUbO9hm0aaDfQjC1i0wV90bjKIPIzKCsoIV41Aiq+/3K cV8NacSRhsjG58kxQNyVHDGZ+stNlJvON/xNpy6S2L7Q/dfUiMaRgda/eFqjmbcgYNkvLO EL5Y5HLwN8l3iKbedmbWVBMcX3x4Lxo= 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 v3 2/7] Mini-OS: add concept of mount points Date: Mon, 13 Feb 2023 09:44:07 +0100 Message-Id: <20230213084412.21065-3-jgross@suse.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230213084412.21065-1-jgross@suse.com> References: <20230213084412.21065-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 Mon Feb 13 08:44: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: 13137944 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 CF862C636CC for ; Mon, 13 Feb 2023 08:44:45 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.494216.764241 (Exim 4.92) (envelope-from ) id 1pRURy-0006N4-Ox; Mon, 13 Feb 2023 08:44:38 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 494216.764241; Mon, 13 Feb 2023 08:44:38 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pRURy-0006Mu-LJ; Mon, 13 Feb 2023 08:44:38 +0000 Received: by outflank-mailman (input) for mailman id 494216; Mon, 13 Feb 2023 08:44:36 +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 1pRURw-0006An-NG for xen-devel@lists.xenproject.org; Mon, 13 Feb 2023 08:44:36 +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 a3098a0a-ab7a-11ed-93b5-47a8fe42b414; Mon, 13 Feb 2023 09:44:33 +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 B5FC137870; Mon, 13 Feb 2023 08:44:32 +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 8D23C1391B; Mon, 13 Feb 2023 08:44:32 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id aHdDIXD46WNARAAAMHmgww (envelope-from ); Mon, 13 Feb 2023 08:44:32 +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: a3098a0a-ab7a-11ed-93b5-47a8fe42b414 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1676277872; 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=7/tiDXbP/9+hZp0jDtSI+PwtYbXnE16R86Manl6T7bw=; b=qiR+HkdnGMmX36aZ+SoeWq7GNf4wwvzOGMdiNfYGeiA1zLvLOv6d/EiRWw5K3JRpmdJr1S 8nUOwXjEBHl7+0sNC8SUyEqCHPZOaAWUunLG4c6G56biCIP0q4goSBslMbUBZ2rS8JxS6/ MYvFRShMfQnaj/DJmzIY0bop4HB1F+M= 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 v3 3/7] Mini-OS: add support for runtime mounts Date: Mon, 13 Feb 2023 09:44:08 +0100 Message-Id: <20230213084412.21065-4-jgross@suse.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230213084412.21065-1-jgross@suse.com> References: <20230213084412.21065-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 --- V3: - set number of possible mountpoints to 16 (Andrew Cooper) --- include/lib.h | 5 +++++ lib/sys.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 49 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..118fc441 100644 --- a/lib/sys.c +++ b/lib/sys.c @@ -85,6 +85,8 @@ } #define NOFILE 32 +#define N_MOUNTS 16 + extern void minios_evtchn_close_fd(int fd); extern void minios_gnttab_close_fd(int fd); @@ -339,7 +341,7 @@ static int open_mem(struct mount_point *mnt, const char *pathname, int flags, return fd; } -static struct mount_point mount_points[] = { +static struct mount_point mount_points[N_MOUNTS] = { { .path = "/var/log", .open = open_log, .dev = NULL }, { .path = "/dev/mem", .open = open_mem, .dev = NULL }, #ifdef CONFIG_CONSFRONT @@ -365,6 +367,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 +379,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 Mon Feb 13 08:44: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: 13137945 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 67A0DC636CC for ; Mon, 13 Feb 2023 08:44:51 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.494222.764256 (Exim 4.92) (envelope-from ) id 1pRUS4-0006rw-4y; Mon, 13 Feb 2023 08:44:44 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 494222.764256; Mon, 13 Feb 2023 08:44:44 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pRUS4-0006r9-14; Mon, 13 Feb 2023 08:44:44 +0000 Received: by outflank-mailman (input) for mailman id 494222; Mon, 13 Feb 2023 08:44:43 +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 1pRUS2-0006An-PP for xen-devel@lists.xenproject.org; Mon, 13 Feb 2023 08:44:42 +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 a66207d9-ab7a-11ed-93b5-47a8fe42b414; Mon, 13 Feb 2023 09:44: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-out1.suse.de (Postfix) with ESMTPS id 574D037870; Mon, 13 Feb 2023 08:44:38 +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 27CEC1391B; Mon, 13 Feb 2023 08:44:38 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id NVlaCHb46WNKRAAAMHmgww (envelope-from ); Mon, 13 Feb 2023 08:44:38 +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: a66207d9-ab7a-11ed-93b5-47a8fe42b414 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1676277878; 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=4NFSUNX/XcwJ+J4tdrvx1QT/0r6zmT/B4WFWAW17s1Y=; b=ustIl96+ogoy1DaxbvOYXnW7OajUyM3EpHALnPxdTl4PQWnCUph2nuuVepesGXpkt4r8NL iGr8qspU1Bgi5Hyqp2A6plTEteeirlzrHsxeFcST/dlYnekUQQjDJeKaBRVpOpxk1wU+R1 w3byhGuWbnR4KhqqjZNbmOlSHXa9Aps= 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 v3 4/7] Mini-OS: add 9pfs frontend Date: Mon, 13 Feb 2023 09:44:09 +0100 Message-Id: <20230213084412.21065-5-jgross@suse.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230213084412.21065-1-jgross@suse.com> References: <20230213084412.21065-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 Mon Feb 13 08:44:10 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: 13137946 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 B3161C636D4 for ; Mon, 13 Feb 2023 08:44:56 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.494224.764270 (Exim 4.92) (envelope-from ) id 1pRUS9-0007Q4-Lo; Mon, 13 Feb 2023 08:44:49 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 494224.764270; Mon, 13 Feb 2023 08:44: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 1pRUS9-0007Pp-Ip; Mon, 13 Feb 2023 08:44:49 +0000 Received: by outflank-mailman (input) for mailman id 494224; Mon, 13 Feb 2023 08:44:48 +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 1pRUS8-0006An-HL for xen-devel@lists.xenproject.org; Mon, 13 Feb 2023 08:44:48 +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 a9b5cdd0-ab7a-11ed-93b5-47a8fe42b414; Mon, 13 Feb 2023 09:44:44 +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 E4B5837878; Mon, 13 Feb 2023 08:44:43 +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 B3FCA1391B; Mon, 13 Feb 2023 08:44:43 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id Ph6mKnv46WNXRAAAMHmgww (envelope-from ); Mon, 13 Feb 2023 08:44:43 +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: a9b5cdd0-ab7a-11ed-93b5-47a8fe42b414 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1676277883; 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=vQv13aoJJoMtKTA7WtwSo7Ix8wqfh+IDZYgezsgINzs=; b=mie5sBtfJneqcDqjPNYBjOVLK5Mu3eoXFYC456ywsuTdUnYRhVJU+tTnnuOQn6g7Mxk1xS i02GShmKVUR60G+JAADQN7b2FrADG7EUKEgiRfsG2p7CCSW2qQezvOsxKl7M6+XLIjYKE6 JhILyPnLiCHWUx18K/Wy7cgOE04GYvQ= 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 v3 5/7] Mini-OS: add 9pfs transport layer Date: Mon, 13 Feb 2023 09:44:10 +0100 Message-Id: <20230213084412.21065-6-jgross@suse.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230213084412.21065-1-jgross@suse.com> References: <20230213084412.21065-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 Mon Feb 13 08:44:11 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: 13137947 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 A08FCC636D4 for ; Mon, 13 Feb 2023 08:44:59 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.494228.764282 (Exim 4.92) (envelope-from ) id 1pRUSD-0007mb-0c; Mon, 13 Feb 2023 08:44:53 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 494228.764282; Mon, 13 Feb 2023 08:44: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 1pRUSC-0007mK-SJ; Mon, 13 Feb 2023 08:44:52 +0000 Received: by outflank-mailman (input) for mailman id 494228; Mon, 13 Feb 2023 08:44:51 +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 1pRUSB-00053b-9D for xen-devel@lists.xenproject.org; Mon, 13 Feb 2023 08:44:51 +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 ac7d7eb8-ab7a-11ed-933c-83870f6b2ba8; Mon, 13 Feb 2023 09:44: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-out1.suse.de (Postfix) with ESMTPS id 7E49637878; Mon, 13 Feb 2023 08:44:49 +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 4EB861391B; Mon, 13 Feb 2023 08:44:49 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id jYzjEYH46WNdRAAAMHmgww (envelope-from ); Mon, 13 Feb 2023 08:44:49 +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: ac7d7eb8-ab7a-11ed-933c-83870f6b2ba8 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1676277889; 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=wuLv/cVrd8nYj9ZnkPp0QX3mht4hZHquHGoCMyjlj9Y=; b=FOg9dV3cCjFNLjjcGtqOwZEN4eOnIsIPTWopUZeP4xCTUHeUT67PGlbAukAcIoUc7gl34J Y1jHcjKeWX2Yfr5RKdOo9j48QR8HReS229abwxdr3tT/jFsw0WmtlsltLteX+bYhSPRY7e +eHNiEzPz/WI6OVzvF1gAgUxMlJFznc= 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 v3 6/7] Mini-OS: add open and close handling to the 9pfs frontend Date: Mon, 13 Feb 2023 09:44:11 +0100 Message-Id: <20230213084412.21065-7-jgross@suse.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230213084412.21065-1-jgross@suse.com> References: <20230213084412.21065-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 Reviewed-by: Samuel Thibault --- 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) V3: - add check for "//" in path_canonical() (Samuel Thibault) --- 9pfront.c | 324 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 322 insertions(+), 2 deletions(-) diff --git a/9pfront.c b/9pfront.c index 0b8d5461..fb2e5669 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,170 @@ 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; + } + + /* No "//". */ + if ( strstr(pathname, "//") ) + return false; + + return true; +} + static int connect_9pfs(struct dev_9pfs *dev) { int ret; @@ -504,10 +731,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 +870,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 +1072,7 @@ void shutdown_9pfront(void *dev) static const struct file_ops ops_9pfs = { .name = "9pfs", + .close = close_9pfs, }; __attribute__((constructor)) From patchwork Mon Feb 13 08:44:12 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: 13137948 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 68EAEC636D7 for ; Mon, 13 Feb 2023 08:45:28 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.494248.764300 (Exim 4.92) (envelope-from ) id 1pRUSf-0000xC-M9; Mon, 13 Feb 2023 08:45:21 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 494248.764300; Mon, 13 Feb 2023 08:45: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 1pRUSf-0000x3-Hv; Mon, 13 Feb 2023 08:45:21 +0000 Received: by outflank-mailman (input) for mailman id 494248; Mon, 13 Feb 2023 08:45:20 +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 1pRUSI-0006An-PA for xen-devel@lists.xenproject.org; Mon, 13 Feb 2023 08:44:58 +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 b05b9c56-ab7a-11ed-93b5-47a8fe42b414; Mon, 13 Feb 2023 09:44:55 +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 15D2437870; Mon, 13 Feb 2023 08:44:55 +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 E2B901391B; Mon, 13 Feb 2023 08:44:54 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id MGEsNob46WNwRAAAMHmgww (envelope-from ); Mon, 13 Feb 2023 08:44:54 +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: b05b9c56-ab7a-11ed-93b5-47a8fe42b414 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1676277895; 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=nsb+k9M0ZRBDQHW/kSOuXta4SExd/WLGLnOu4GRbNW4=; b=Fcg2Q83nLC0WBcoRucEIdajqN7DsYJYPRsQPs+EnbbinXqqUVaSWq/5SZvWLrMiVUuH7OM 6RvXh3I1syHWV0+AbGaKQZEc3B5Qyxkga0cEwTzN1UWkD3UlVLAB08K6IfO2dgJZoPG94d ZQBwFac7ZekExICyEYzSUgC0BbM/mWs= 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 v3 7/7] Mini-OS: add read and write support to 9pfsfront Date: Mon, 13 Feb 2023 09:44:12 +0100 Message-Id: <20230213084412.21065-8-jgross@suse.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230213084412.21065-1-jgross@suse.com> References: <20230213084412.21065-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 Reviewed-by: Samuel Thibault --- 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) V3: - use an exact limit for read/write (Samuel Thibault) - log read(write errors (Samuel Thibault) --- 9pfront.c | 216 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) diff --git a/9pfront.c b/9pfront.c index fb2e5669..5da8a365 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[P9_QID_SIZE]; + 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,115 @@ 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, count_max; + + if ( !req ) + { + errno = EAGAIN; + return -1; + } + req->cmd = P9_CMD_READ; + count_max = dev->msize_max - (sizeof(struct p9_header) + sizeof(uint32_t)); + + while ( len ) + { + count = len; + if ( count > count_max ) + count = count_max; + + 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; + printk("9pfs: read got error %d\n", req->result); + 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, count_max; + + if ( !req ) + { + errno = EAGAIN; + return -1; + } + req->cmd = P9_CMD_WRITE; + count_max = dev->msize_max - (sizeof(struct p9_header) + sizeof(uint32_t) + + sizeof(uint64_t) + sizeof(uint32_t)); + + while ( len ) + { + count = len; + if ( count > count_max ) + count = count_max; + + send_9p(dev, req, "ULD", fid, offset, count, data); + rcv_9p(dev, req, "U", &count); + if ( req->result ) + { + ret = -1; + errno = EIO; + printk("9pfs: write got error %d\n", req->result); + 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 @@ -731,6 +908,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; @@ -1072,6 +1286,8 @@ void shutdown_9pfront(void *dev) static const struct file_ops ops_9pfs = { .name = "9pfs", + .read = read_9pfs, + .write = write_9pfs, .close = close_9pfs, };