#define BLKIO_BUSY 0x4
#define BLKIO_PENDING 0x8
+#define BLKIO_WAIT 0x1
+
// Free on complete
#define BLKIO_FOC 0x10
* @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.
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
#include <lunaix/mm/cake.h>
#include <lunaix/mm/valloc.h>
+#include <hal/cpu.h>
+
static struct cake_pile* blkio_reqpile;
void
}
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;
// 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);
}
}
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);
}
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);
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) {
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) {
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) {
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;
vfs_i_addhash(inode);
}
- iso9660_setup_dnode(dnode, inode);
-
- return 0;
+ return iso9660_setup_dnode(dnode, inode);
}
static int
#include <lunaix/fs.h>
#include <lunaix/fs/iso9660.h>
+#include <lunaix/mm/valloc.h>
+#include <lunaix/spike.h>
+
+#include <klibc/string.h>
int
iso9660_open(struct v_inode* this, 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