/*===========================================================================* * read_block * *===========================================================================*/ static void read_block( struct buf *bp /* buffer pointer */ ) { /* Read or write a disk block. This is the only routine in which actual disk * I/O is invoked. If an error occurs, a message is printed here, but the error * is not reported to the caller. If the error occurred while purging a block * from the cache, it is not clear what the caller could do about it anyway. */ int r, op_failed; off_t pos; dev_t dev = bp->lmfs_dev; op_failed = 0; assert(dev != NO_DEV); ASSERT(bp->lmfs_bytes == fs_block_size); ASSERT(fs_block_size > 0); pos = (off_t)bp->lmfs_blocknr * fs_block_size; if(fs_block_size > PAGE_SIZE) { #define MAXPAGES 20 vir_bytes blockrem, vaddr = (vir_bytes) bp->data; int p = 0; static iovec_t iovec[MAXPAGES]; blockrem = fs_block_size; while(blockrem > 0) { vir_bytes chunk = blockrem >= PAGE_SIZE ? PAGE_SIZE : blockrem; iovec[p].iov_addr = vaddr; iovec[p].iov_size = chunk; vaddr += chunk; blockrem -= chunk; p++; } r = bdev_gather(dev, pos, iovec, p, BDEV_NOFLAGS); } else { r = bdev_read(dev, pos, bp->data, fs_block_size, BDEV_NOFLAGS); } if (r < 0) { printf("fs cache: I/O error on device %d/%d, block %u\n", major(dev), minor(dev), bp->lmfs_blocknr); op_failed = 1; } else if (r != (ssize_t) fs_block_size) { r = END_OF_FILE; op_failed = 1; } if (op_failed) { bp->lmfs_dev = NO_DEV; /* invalidate block */ /* Report read errors to interested parties. */ rdwt_err = r; } }
/*===========================================================================* * read_block * *===========================================================================*/ static int read_block(struct buf *bp, size_t block_size) { /* Read a disk block of 'size' bytes. The given size is always the FS block * size, except for the last block of a device. If an I/O error occurs, * invalidate the block and return an error code. */ ssize_t r; off_t pos; dev_t dev = bp->lmfs_dev; assert(dev != NO_DEV); ASSERT(bp->lmfs_bytes == block_size); ASSERT(fs_block_size > 0); pos = (off_t)bp->lmfs_blocknr * fs_block_size; if (block_size > PAGE_SIZE) { #define MAXPAGES 20 vir_bytes blockrem, vaddr = (vir_bytes) bp->data; int p = 0; static iovec_t iovec[MAXPAGES]; blockrem = block_size; while(blockrem > 0) { vir_bytes chunk = blockrem >= PAGE_SIZE ? PAGE_SIZE : blockrem; iovec[p].iov_addr = vaddr; iovec[p].iov_size = chunk; vaddr += chunk; blockrem -= chunk; p++; } r = bdev_gather(dev, pos, iovec, p, BDEV_NOFLAGS); } else { r = bdev_read(dev, pos, bp->data, block_size, BDEV_NOFLAGS); } if (r != (ssize_t)block_size) { /* Aesthetics: do not report EOF errors on superblock reads, because * this is a fairly common occurrence, e.g. during system installation. */ if (bp->lmfs_blocknr != 0 /*first block*/ || r != 0 /*EOF*/) printf("fs cache: I/O error on device %d/%d, block %"PRIu64 " (%zd)\n", major(dev), minor(dev), bp->lmfs_blocknr, r); if (r >= 0) r = EIO; /* TODO: retry retrieving (just) the remaining part */ bp->lmfs_dev = NO_DEV; /* invalidate block */ return r; } return OK; }
/*===========================================================================* * rw_block * *===========================================================================*/ static void rw_block( register struct buf *bp, /* buffer pointer */ int rw_flag /* READING or WRITING */ ) { /* Read or write a disk block. This is the only routine in which actual disk * I/O is invoked. If an error occurs, a message is printed here, but the error * is not reported to the caller. If the error occurred while purging a block * from the cache, it is not clear what the caller could do about it anyway. */ int r, op_failed = 0; u64_t pos; dev_t dev; if ( (dev = bp->b_dev) != NO_DEV) { pos = mul64u(bp->b_blocknr, fs_block_size); if (rw_flag == READING) r = bdev_read(dev, pos, bp->b_data, fs_block_size, BDEV_NOFLAGS); else r = bdev_write(dev, pos, bp->b_data, fs_block_size, BDEV_NOFLAGS); if (r < 0) { printf("Ext2(%d) I/O error on device %d/%d, block %u\n", SELF_E, major(dev), minor(dev), bp->b_blocknr); op_failed = 1; } else if (r != (ssize_t) fs_block_size) { r = END_OF_FILE; op_failed = 1; } if (op_failed) { bp->b_dev = NO_DEV; /* invalidate block */ /* Report read errors to interested parties. */ if (rw_flag == READING) rdwt_err = r; } } bp->b_dirt = CLEAN; }
/* * Reads from a file. */ PUBLIC ssize_t sys_read(int fd, void *buf, size_t n) { dev_t dev; /* Device number. */ struct file *f; /* File. */ struct inode *i; /* Inode. */ ssize_t count; /* Bytes actually read. */ /* Invalid file descriptor. */ if ((fd < 0) || (fd >= OPEN_MAX) || ((f = curr_proc->ofiles[fd]) == NULL)) return (-EBADF); /* File not opened for reading. */ if (ACCMODE(f->oflag) == O_WRONLY) return (-EBADF); #if (EDUCATIONAL_KERNEL == 0) /* Invalid buffer. */ if (!chkmem(buf, n, MAY_WRITE)) return (-EINVAL); #endif /* Nothing to do. */ if (n == 0) return (0); i = f->inode; /* Character special file. */ if (S_ISCHR(i->mode)) { dev = i->blocks[0]; count = cdev_read(dev, buf, n); return (count); } /* Block special file. */ else if (S_ISBLK(i->mode)) { dev = i->blocks[0]; count = bdev_read(dev, buf, n, f->pos); } /* Pipe file. */ else if (S_ISFIFO(i->mode)) { kprintf("read from pipe"); count = pipe_read(i, buf, n); } /* Regular file/directory. */ else if ((S_ISDIR(i->mode)) || (S_ISREG(i->mode))) count = file_read(i, buf, n, f->pos); /* Unknown file type. */ else return (-EINVAL); /* Failed to read. */ if (count < 0) return (curr_proc->errno); inode_touch(i); f->pos += count; return (count); }