From 8ce769cc52e91ff3cdb8eda4b1f5d8fe58241688 Mon Sep 17 00:00:00 2001 From: Minep Date: Fri, 11 Nov 2022 21:45:16 +0000 Subject: [PATCH] feat: (iso9660) implement file read (for both interleaved and non-interleaved mode) fix: (blkio) race condition between blkio_commit and pwait fix: regression chore: clean up --- lunaix-os/includes/lunaix/blkio.h | 4 +- lunaix-os/includes/lunaix/fs.h | 3 +- lunaix-os/kernel/block/blkio.c | 22 ++++++++- lunaix-os/kernel/block/block.c | 17 ++----- lunaix-os/kernel/fs/iso9660/directory.c | 7 ++- lunaix-os/kernel/fs/iso9660/file.c | 63 +++++++++++++++++++++++-- 6 files changed, 92 insertions(+), 24 deletions(-) diff --git a/lunaix-os/includes/lunaix/blkio.h b/lunaix-os/includes/lunaix/blkio.h index 07b53ac..a189a4d 100644 --- a/lunaix-os/includes/lunaix/blkio.h +++ b/lunaix-os/includes/lunaix/blkio.h @@ -12,6 +12,8 @@ #define BLKIO_BUSY 0x4 #define BLKIO_PENDING 0x8 +#define BLKIO_WAIT 0x1 + // Free on complete #define BLKIO_FOC 0x10 @@ -96,7 +98,7 @@ blkio_free_req(struct blkio_req* req); * @param req */ void -blkio_commit(struct blkio_context* ctx, struct blkio_req* req); +blkio_commit(struct blkio_context* ctx, struct blkio_req* req, int options); /** * @brief Schedule an IO request to be handled. diff --git a/lunaix-os/includes/lunaix/fs.h b/lunaix-os/includes/lunaix/fs.h index cc850ad..f6a2e62 100644 --- a/lunaix-os/includes/lunaix/fs.h +++ b/lunaix-os/includes/lunaix/fs.h @@ -173,7 +173,8 @@ struct v_fd int flags; }; -// FIXME how do we invalidate corresponding v_dnodes given the v_inode? +// [v_inode::aka_nodes] +// how do we invalidate corresponding v_dnodes given the v_inode? /* Consider taskfs, which is Lunaix's speak of Linux's procfs, that allow info of every process being accessible via file system. Each process's diff --git a/lunaix-os/kernel/block/blkio.c b/lunaix-os/kernel/block/blkio.c index c5d688f..0427622 100644 --- a/lunaix-os/kernel/block/blkio.c +++ b/lunaix-os/kernel/block/blkio.c @@ -2,6 +2,8 @@ #include #include +#include + static struct cake_pile* blkio_reqpile; void @@ -70,7 +72,7 @@ blkio_newctx(req_handler handler) } void -blkio_commit(struct blkio_context* ctx, struct blkio_req* req) +blkio_commit(struct blkio_context* ctx, struct blkio_req* req, int options) { req->flags |= BLKIO_PENDING; req->io_ctx = ctx; @@ -78,8 +80,25 @@ blkio_commit(struct blkio_context* ctx, struct blkio_req* req) // if the pipeline is not running (e.g., stalling). Then we should schedule // one immediately and kick it started. + // NOTE: Possible race condition between blkio_commit and pwait. + // Consider: what if scheduler complete the request before pwait even get + // called? + // Two possible work around: + // #1. we disable the interrupt before schedule the request. + // #2. we do scheduling within interrupt context (e.g., attach a timer) + // As we don't want to overwhelming the interrupt context and also keep the + // request RTT as small as possible, hence #1 is preferred. + if (!ctx->busy) { + if ((options & BLKIO_WAIT)) { + cpu_disable_interrupt(); + blkio_schedule(ctx); + pwait(&req->wait); + return; + } blkio_schedule(ctx); + } else if ((options & BLKIO_WAIT)) { + pwait(&req->wait); } } @@ -108,7 +127,6 @@ blkio_complete(struct blkio_req* req) req->completed(req); } - // FIXME Not working in first process! Need a dummy process. // Wake all blocked processes on completion, // albeit should be no more than one process in everycase (by design) pwake_all(&req->wait); diff --git a/lunaix-os/kernel/block/block.c b/lunaix-os/kernel/block/block.c index 494a977..6203fc7 100644 --- a/lunaix-os/kernel/block/block.c +++ b/lunaix-os/kernel/block/block.c @@ -74,9 +74,7 @@ __block_read(struct device* dev, void* buf, size_t offset, size_t len) } req = blkio_vrd(vbuf, rd_block, NULL, NULL, 0); - blkio_commit(bdev->blkio, req); - - pwait(&req->wait); + blkio_commit(bdev->blkio, req, BLKIO_WAIT); if (!(errno = req->errcode)) { memcpy(buf, head_buf + r, rd_size); @@ -123,13 +121,8 @@ __block_write(struct device* dev, void* buf, size_t offset, size_t len) vbuf_alloc(&vbuf, buf + wr_size, llen); } - // FIXME race condition between blkio_commit and pwait. - // Consider: what if scheduler complete the request before process enter - // wait state? req = blkio_vwr(vbuf, wr_block, NULL, NULL, 0); - blkio_commit(bdev->blkio, req); - - pwait(&req->wait); + blkio_commit(bdev->blkio, req, BLKIO_WAIT); int errno = req->errcode; if (!errno) { @@ -154,8 +147,7 @@ __block_rd_lb(struct block_dev* bdev, void* buf, u64_t start, size_t count) vbuf_alloc(&vbuf, buf, bdev->blk_size * count); struct blkio_req* req = blkio_vrd(vbuf, start, NULL, NULL, 0); - blkio_commit(bdev->blkio, req); - pwait(&req->wait); + blkio_commit(bdev->blkio, req, BLKIO_WAIT); int errno = req->errcode; if (!errno) { @@ -177,8 +169,7 @@ __block_wr_lb(struct block_dev* bdev, void* buf, u64_t start, size_t count) vbuf_alloc(&vbuf, buf, bdev->blk_size * count); struct blkio_req* req = blkio_vwr(vbuf, start, NULL, NULL, 0); - blkio_commit(bdev->blkio, req); - pwait(&req->wait); + blkio_commit(bdev->blkio, req, BLKIO_WAIT); int errno = req->errcode; if (!errno) { diff --git a/lunaix-os/kernel/fs/iso9660/directory.c b/lunaix-os/kernel/fs/iso9660/directory.c index d240e1f..71244a9 100644 --- a/lunaix-os/kernel/fs/iso9660/directory.c +++ b/lunaix-os/kernel/fs/iso9660/directory.c @@ -32,7 +32,8 @@ int iso9660_setup_dnode(struct v_dnode* dnode, struct v_inode* inode) { if (!(inode->itype & VFS_IFDIR)) { - return; + vfs_assign_inode(dnode, inode); + return 0; } int errno = 0; @@ -113,9 +114,7 @@ found: vfs_i_addhash(inode); } - iso9660_setup_dnode(dnode, inode); - - return 0; + return iso9660_setup_dnode(dnode, inode); } static int diff --git a/lunaix-os/kernel/fs/iso9660/file.c b/lunaix-os/kernel/fs/iso9660/file.c index 6813c22..34d3b47 100644 --- a/lunaix-os/kernel/fs/iso9660/file.c +++ b/lunaix-os/kernel/fs/iso9660/file.c @@ -1,5 +1,9 @@ #include #include +#include +#include + +#include int iso9660_open(struct v_inode* this, struct v_file* file) @@ -18,15 +22,68 @@ iso9660_close(struct v_file* file) int iso9660_read(struct v_inode* inode, void* buffer, size_t len, size_t fpos) { - // TODO - return 0; + // This read implementation handle both interleaved and non-interleaved + // structuring + + struct iso_inode* isoino = inode->data; + struct device* bdev = inode->sb->dev; + + len = MIN(fpos + len, inode->fsize); + if (len <= fpos) { + return 0; + } + + len -= fpos; + + size_t fu_len = isoino->fu_size * ISO9660_BLKSZ; + // if fpos is not FU aligned, then we must do an extra read. + size_t fu_to_read = + ICEIL(len, fu_len) + (fpos > fu_len && (fpos % fu_len) != 0); + size_t sec = (fpos % fu_len) / ISO9660_BLKSZ; + size_t wd_start = fpos % ISO9660_BLKSZ, + wd_len = MIN(len, ISO9660_BLKSZ - wd_start), i = 0; + + // how many blocks (file unit + gaps) before of our current read position + size_t true_offset = (fpos / fu_len); + true_offset = true_offset * (isoino->fu_size + isoino->gap_size); + + void* rd_buffer = valloc(ISO9660_BLKSZ); + + true_offset += sec + inode->lb_addr; + + int errno = 0; + while (fu_to_read) { + for (; sec < isoino->fu_size && i < len; sec++) { + errno = bdev->read( + bdev, rd_buffer, true_offset * ISO9660_BLKSZ, ISO9660_BLKSZ); + + if (errno < 0) { + errno = EIO; + goto done; + } + + memcpy(buffer + i, rd_buffer + wd_start, wd_len); + + i += wd_len; + true_offset++; + wd_start = 0; + wd_len = MIN(len - i, ISO9660_BLKSZ); + } + sec = 0; + fu_to_read--; + } + errno = i; + +done: + vfree(rd_buffer); + return errno; } int iso9660_write(struct v_inode* inode, void* buffer, size_t len, size_t fpos) { // TODO - return EROFS; + return ENOTSUP; } int -- 2.27.0