From patchwork Fri Apr 3 14:04:39 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 2102 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775225180; bh=6I6DLYePF9HbRn2vgOoe2amAEyZcloS7Q1QfYa5+/cs=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=fXcmqWruutSjJGiicbnUmQ3kuXzbDIPT8iDvwEan2gAtjK8Nydp9oC4n4xu8W+bs+ sfePRQyfYDAGLcPz+UQtxj6ssogxuaQNXz8zFKwIO5LNCQnL07y23ApAoLd0Cryatk W63C2Xmg4uWgqgPKTjK8yvxJwZDNMO4yHwvV5t8gLkKHqPLhgj7QTzk/6l2yIHFyc8 Yk9BEwPbhK0Utp1ydobGFQDIlmwwFDF1z01dp/M7iA0kvDCujuwtkDkkgneyTta7c1 dZBbA8OsZzdnneVcO8v6n31cPBqG/nYYqmQWprMUnyS2qtB4rNAxbfd1VDWpbgoW8N GsUnfHkpMOYZw== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id A03036A34C for ; Fri, 3 Apr 2026 08:06:20 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id E6TL71wrMFL0 for ; Fri, 3 Apr 2026 08:06:20 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775225178; bh=6I6DLYePF9HbRn2vgOoe2amAEyZcloS7Q1QfYa5+/cs=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=wXvZqNwpwnFKdk8Agqiokd+zkOp0zeSspsOmQ0eTrAWNrjC7lhH1ClfhfLeroW292 aQsYNuI/wi945AWiLAZppMsTCpdHZya0oeF4aARGWryzw+CoEo0Fdu8QzurFuUIqLk IXDZQWtq3zuH9Djf6fkmohguy+FSwIVxP8gPgB/Ni3F2Wi0qd+5A6ahbfqJCMKKfAF vx58/liwsPuc1jT1flHqrOfvNF4+oPfJ0NtFbM6MoXU4CVN4RuQ47SXeiHDpNWf3ye SrFDBWA9+GEjOkeptHHgqXXF06tcBv1QWDDR8ntzXAjp2hoiy93by3LQ3QhUQh0PoX LuNG9uen1Tg8g== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id B37A36A34E for ; Fri, 3 Apr 2026 08:06:18 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775225177; bh=YntwcLXn94XTuGLrOb7MHlMG+N0bOihuidTQL9GyhUY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=lWVtBt2pefaGmMU/WuLo8MGTfuYgftyBB4MQeG5JnGb/8IXmwAX8o1cmp9UzuyT06 VhTdWui/G+fJY4w6PN4CWGjcQFe9pbWaHTEeN+0dni2r6rmi2olzOYtbAYn9kaX2qI Tw97YN3HjxfdDHO//4tISFHOdCIpr1Pp32Xn5yl8P5TRnurW/b0Bx+0rQ7TbLflk6n hopMn4ckc8uwn20F2BvLZ2NHpcHt+L8xqKfYLTCglv2XH2T0Cfm1Nmnx5y3usGXquG rpZ4voZ13k3rFRVSkbisdTrbTavy4uT9e+zSVnMqThT+/hX/wjEKj7WKTApdtSpE7W USNqIe4MoVzeA== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id B77D66A34F; Fri, 3 Apr 2026 08:06:17 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id JzKwwcDAIYC5; Fri, 3 Apr 2026 08:06:17 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775225168; bh=LHPjf8A0rQuQCzuYvMgU4NgChKqGnjY+fvxa+KCi2Ms=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=uYoawkVHEkW+km4LRCm0CxB2nquST33eKuGQDX7YdVUpcCw6n43ILVD3+fyyE7lLm nZmQq7aDfd+d0ohSsenCCYaKhOPus00jYt91Cop9IkvHV3TxIENtAo/7yC+UFGyPyw jz8WOjzkIrD80gem7hpG231KEwAoIiygFWB/f5P9sbONQk+zZsWI7DKYVQWjhuDf7m HQVBtajeIxZJ/j2aTXax4HCMexjzEVevs89so8I7QLg72NU05Gtqy4eZHFw6zblIgB fbt/EuXa7f8RswfYK0vv5MztPLqHmQY+KaBe/7o8fz6XNUpOdx/cHrlUpiiWB5iTbW SrvgDhTo6fVxg== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id B1C6B6A34C; Fri, 3 Apr 2026 08:06:08 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Fri, 3 Apr 2026 08:04:39 -0600 Message-ID: <20260403140523.1998228-18-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260403140523.1998228-1-sjg@u-boot.org> References: <20260403140523.1998228-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: XWDZJGJIBFYKA6CJLORFMXYB3PAND6VG X-Message-ID-Hash: XWDZJGJIBFYKA6CJLORFMXYB3PAND6VG X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Simon Glass X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 17/34] vfs: Add support for writing files List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass The FILE uclass currently only supports reading. Add file_write_at() and write_iter() operations so that files can be written using driver model. Provide a sandbox implementation (sandbox_write_iter) and allow sandbox_dir_open_file() to create new files when opened for writing. Also add a simple test. Signed-off-by: Simon Glass --- fs/file-uclass.c | 21 +++++++++++++++++++++ fs/sandbox/sandboxfs.c | 30 +++++++++++++++++++++++++++--- include/file.h | 23 +++++++++++++++++++++++ test/dm/fs.c | 30 ++++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+), 3 deletions(-) diff --git a/fs/file-uclass.c b/fs/file-uclass.c index 91ced31a94e..58d0a75f0c3 100644 --- a/fs/file-uclass.c +++ b/fs/file-uclass.c @@ -96,6 +96,27 @@ long file_read_at(struct udevice *dev, void *buf, loff_t offset, long len) return ret; } +long file_write_at(struct udevice *dev, const void *buf, loff_t offset, + long len) +{ + struct file_uc_priv *uc_priv = dev_get_uclass_priv(dev); + struct file_ops *ops = file_get_ops(dev); + struct iov_iter iter; + ssize_t ret; + + if (!ops->write_iter) + return log_msg_ret("fwn", -ENOSYS); + + iter_ubuf(&iter, false, (void *)buf, len); + + ret = ops->write_iter(dev, &iter, offset); + if (ret < 0) + return log_msg_ret("fww", ret); + uc_priv->pos = offset + ret; + + return ret; +} + UCLASS_DRIVER(file) = { .name = "file", .id = UCLASS_FILE, diff --git a/fs/sandbox/sandboxfs.c b/fs/sandbox/sandboxfs.c index 494af0d373a..70fb829ae67 100644 --- a/fs/sandbox/sandboxfs.c +++ b/fs/sandbox/sandboxfs.c @@ -277,8 +277,29 @@ static ssize_t sandbox_read_iter(struct udevice *dev, struct iov_iter *iter, return ret; } +static ssize_t sandbox_write_iter(struct udevice *dev, struct iov_iter *iter, + loff_t pos) +{ + struct file_priv *priv = dev_get_priv(dev); + ssize_t ret; + + log_debug("start dev '%s' len %lx\n", dev->name, iter->count); + ret = os_lseek(priv->fd, pos, OS_SEEK_SET); + if (ret < 0) + return log_msg_ret("vfs", ret); + + ret = os_write(priv->fd, iter_iov_ptr(iter), iter_iov_avail(iter)); + if (ret < 0) + return log_msg_ret("vfw", ret); + iter_advance(iter, ret); + log_debug("wrote %lx bytes\n", ret); + + return ret; +} + static struct file_ops sandbox_file_ops = { .read_iter = sandbox_read_iter, + .write_iter = sandbox_write_iter, }; static const struct udevice_id file_ids[] = { @@ -309,10 +330,13 @@ static int sandbox_dir_open_file(struct udevice *dir, const char *leaf, snprintf(pathname, sizeof(pathname), "%s/%s", *uc_priv->path ? uc_priv->path: ".", leaf); ftype = os_get_filetype(pathname); - if (ftype < 0) - return log_msg_ret("soF", ftype); - if (ftype != OS_FILET_REG) + if (ftype < 0) { + /* Allow creating new files for write modes */ + if (oflags == DIR_O_RDONLY) + return log_msg_ret("soF", ftype); + } else if (ftype != OS_FILET_REG) { return log_msg_ret("sOf", -EINVAL); + } if (oflags == DIR_O_RDONLY) mode = OS_O_RDONLY; diff --git a/include/file.h b/include/file.h index d1fdf3c13f1..051e5e37549 100644 --- a/include/file.h +++ b/include/file.h @@ -43,6 +43,17 @@ struct file_ops { */ ssize_t (*read_iter)(struct udevice *dev, struct iov_iter *iter, loff_t pos); + + /** + * write_iter() - Write data to a file + * + * @dev: File to write to + * @iter: Iterator providing the data to write + * @pos: File position to write at + * Return: number of bytes written, or -ve error code + */ + ssize_t (*write_iter)(struct udevice *dev, struct iov_iter *iter, + loff_t pos); }; /* Get access to a file's operations */ @@ -69,6 +80,18 @@ long file_read(struct udevice *dev, void *buf, long len); */ long file_read_at(struct udevice *dev, void *buf, loff_t offset, long len); +/** + * file_write_at() - Write data to a file at a particular position + * + * @dev: File to write to + * @buf: Buffer containing data to write + * @offset: Offset within the file to start writing + * @len: Number of bytes to write + * Return: number of bytes written, or -ve error code + */ +long file_write_at(struct udevice *dev, const void *buf, loff_t offset, + long len); + /** * file_add_probe() - Create a new file device for a file * diff --git a/test/dm/fs.c b/test/dm/fs.c index e45441e5241..f42604fb097 100644 --- a/test/dm/fs.c +++ b/test/dm/fs.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -107,6 +108,35 @@ static int dm_test_fs_file(struct unit_test_state *uts) } DM_TEST(dm_test_fs_file, UTF_SCAN_FDT); +/* Test writing a file */ +static int dm_test_fs_file_write(struct unit_test_state *uts) +{ + struct udevice *fsdev, *dir, *fil; + static const char data[] = "hello world\n"; + char buf[32]; + + ut_assertok(uclass_first_device_err(UCLASS_FS, &fsdev)); + ut_assertok(fs_mount(fsdev)); + ut_assertok(fs_lookup_dir(fsdev, "", &dir)); + + /* Write a new file */ + ut_assertok(dir_open_file(dir, "_test_write.tmp", DIR_O_WRONLY, &fil)); + ut_asserteq(sizeof(data) - 1, + file_write_at(fil, data, 0, sizeof(data) - 1)); + + /* Read it back */ + ut_assertok(dir_open_file(dir, "_test_write.tmp", DIR_O_RDONLY, &fil)); + memset(buf, '\0', sizeof(buf)); + ut_asserteq(sizeof(data) - 1, file_read(fil, buf, sizeof(buf))); + ut_asserteq_str("hello world\n", buf); + + /* Clean up */ + os_unlink("_test_write.tmp"); + + return 0; +} +DM_TEST(dm_test_fs_file_write, UTF_SCAN_FDT); + #if IS_ENABLED(CONFIG_VFS) /* Test VFS init and root directory operations */ static int dm_test_vfs_init(struct unit_test_state *uts)