From nobody Thu Nov 28 09:47:29 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass(p=quarantine dis=none) header.from=suse.com ARC-Seal: i=1; a=rsa-sha256; t=1676277908; cv=none; d=zohomail.com; s=zohoarc; b=cCZ5d7yQ9J3t/Yp4By+frbtXIdbj/NvQ0O5jDbMFrTEaAuf9ONqPMSHW2giJn9N0YbzwwCSqf63IQNFC3U3IFB253vEls6Ky1xTyF4GshIi0kk5IvubVA7u3rWZ4ZHQpEaPhMKK0uvkAYsJ5IKWafqpJzrp+1nl9mtYdIAor4FM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1676277908; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=wuLv/cVrd8nYj9ZnkPp0QX3mht4hZHquHGoCMyjlj9Y=; b=jEpKE00IJM2hYQ0RdKJcNnfd/0QvBL47LQj8e33nksRowtAsTsCc8VnvlZ9hcIIGACHVzdUyEvLCrV/XXv7YMeSqAC5+Vbq1Y6Wu5L3CtQtaGPAIlJhBhg5eDb0kuB66a6WW3B6sppvHu1ZUwt3mcXtoO8vpZP844oJZ/I1wCog= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 167627790812466.6266860712509; Mon, 13 Feb 2023 00:45:08 -0800 (PST) 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 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-Outflank-Mailman: Message body and most headers restored to incoming version 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 Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @suse.com) X-ZM-MESSAGEID: 1676277909201100003 Content-Type: text/plain; charset="utf-8" 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; }; =20 #define DEFAULT_9PFS_RING_ORDER 4 =20 +/* 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 */ =20 #define P9_QID_SIZE 13 =20 @@ -69,10 +89,27 @@ struct p9_header { } __attribute__((packed)); =20 #define P9_VERSION "9P2000.u" -#define P9_ROOT_FID ~0 +#define P9_ROOT_FID 0 =20 static unsigned int ftype_9pfs; =20 +static unsigned int get_fid(struct dev_9pfs *dev) +{ + unsigned int fid; + + fid =3D ffs(dev->fid_mask); + if ( fid ) + dev->fid_mask &=3D ~(1ULL << (fid - 1)); + + return fid; +} + +static void put_fid(struct dev_9pfs *dev, unsigned int fid) +{ + if ( fid ) + dev->fid_mask |=3D 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 sing= le * 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 omitte= d, @@ -153,7 +193,9 @@ static void send_9p(struct dev_9pfs *dev, struct req *r= eq, const char *fmt, ...) va_list ap, aq; const char *f; uint32_t intval; + uint16_t shortval; uint16_t len; + uint8_t byte; char *strval; =20 hdr.size =3D 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 +=3D 1; + byte =3D va_arg(aq, unsigned int); + break; + case 'u': + hdr.size +=3D 2; + shortval =3D va_arg(aq, unsigned int); + break; case 'U': hdr.size +=3D 4; intval =3D 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 =3D va_arg(ap, unsigned int); + copy_to_ring(dev, &byte, sizeof(byte)); + break; + case 'u': + shortval =3D va_arg(ap, unsigned int); + copy_to_ring(dev, &shortval, sizeof(shortval)); + break; case 'U': intval =3D 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 re= q *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 r= eq *req, { switch ( *f ) { + case 'u': + shortval =3D va_arg(ap, uint16_t *); + copy_bufs(&buf1, &buf2, &len1, &len2, shortval, sizeof(*shortv= al)); + break; case 'U': val =3D 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; } =20 +static int p9_clunk(struct dev_9pfs *dev, uint32_t fid) +{ + struct req *req =3D get_free_req(dev); + int ret; + + if ( !req ) + return EAGAIN; + + req->cmd =3D P9_CMD_CLUNK; + send_9p(dev, req, "U", fid); + rcv_9p(dev, req, ""); + ret =3D 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 =3D get_free_req(dev); + int ret; + uint16_t nqid; + uint8_t qid[P9_QID_SIZE]; + + if ( !req ) + return EAGAIN; + + req->cmd =3D 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 =3D 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 =3D get_free_req(dev); + int ret; + uint8_t qid[P9_QID_SIZE]; + uint32_t iounit; + + if ( !req ) + return EAGAIN; + + req->cmd =3D P9_CMD_OPEN; + send_9p(dev, req, "Ub", fid, omode); + rcv_9p(dev, req, "QU", qid, &iounit); + + ret =3D 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 =3D get_free_req(dev); + int ret; + uint8_t qid[P9_QID_SIZE]; + uint32_t iounit; + + if ( !req ) + return EAGAIN; + + req->cmd =3D P9_CMD_CREATE; + send_9p(dev, req, "USUbS", fid, path, mode, omode, ""); + rcv_9p(dev, req, "QU", qid, &iounit); + + ret =3D 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 =3D P9_ROOT_FID; + int ret; + + while ( steps-- ) + { + ret =3D p9_walk(dev, curr_fid, fid, *paths); + if ( ret ) + return steps + 1; + curr_fid =3D fid; + *paths +=3D strlen(*paths) + 1; + } + + return 0; +} + +static unsigned int split_path(const char *pathname, char **split_ptr) +{ + unsigned int parts =3D 1; + char *p; + + *split_ptr =3D strdup(pathname); + + for ( p =3D strchr(*split_ptr, '/'); p; p =3D strchr(p + 1, '/') ) + { + *p =3D 0; + parts++; + } + + return parts; +} + +static bool path_canonical(const char *pathname) +{ + unsigned int len =3D strlen(pathname); + const char *c; + + /* Empty path is allowed. */ + if ( !len ) + return true; + + /* No trailing '/'. */ + if ( pathname[len - 1] =3D=3D '/' ) + return false; + + /* No self or parent references. */ + c =3D pathname; + while ( (c =3D strstr(c, "/.")) !=3D NULL ) + { + if ( c[2] =3D=3D '.' ) + c++; + if ( c[2] =3D=3D 0 || c[2] =3D=3D '/' ) + return false; + c +=3D 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); } =20 +static int close_9pfs(struct file *file) +{ + struct file_9pfs *f9pfs =3D file->filedata; + + if ( f9pfs->fid !=3D 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 fl= ags, mode_t mode) { - errno =3D ENOSYS; + int fd; + char *path =3D 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 =3D calloc(1, sizeof(*f9pfs)); + f9pfs->dev =3D mnt->dev; + f9pfs->fid =3D P9_ROOT_FID; + + fd =3D alloc_fd(ftype_9pfs); + file =3D get_file_from_fd(fd); + file->filedata =3D f9pfs; + + switch ( flags & O_ACCMODE ) + { + case O_RDONLY: + omode =3D P9_OREAD; + break; + case O_WRONLY: + omode =3D P9_OWRITE; + break; + case O_RDWR: + omode =3D P9_ORDWR; + break; + default: + ret =3D EINVAL; + goto err; + } + + if ( flags & O_TRUNC ) + omode |=3D P9_OTRUNC; + f9pfs->append =3D flags & O_APPEND; + + nwalk =3D split_path(pathname, &path); + + f9pfs->fid =3D get_fid(mnt->dev); + if ( !f9pfs->fid ) + { + ret =3D ENFILE; + goto err; + } + p =3D path; + nwalk =3D walk_9pfs(mnt->dev, f9pfs->fid, nwalk, &p); + if ( nwalk ) + { + if ( nwalk > 1 || !(flags & O_CREAT) ) + { + ret =3D ENOENT; + goto err; + } + + ret =3D p9_create(mnt->dev, f9pfs->fid, p, mode, omode); + if ( ret ) + goto err; + goto out; + } + + ret =3D p9_open(mnt->dev, f9pfs->fid, omode); + if ( ret ) + goto err; + + out: + free(path); + + return fd; + + err: + free(path); + close(fd); + errno =3D ret; =20 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 =3D ~0ULL; =20 for ( i =3D 0; i < N_REQS; i++ ) { @@ -753,6 +1072,7 @@ void shutdown_9pfront(void *dev) =20 static const struct file_ops ops_9pfs =3D { .name =3D "9pfs", + .close =3D close_9pfs, }; =20 __attribute__((constructor)) --=20 2.35.3