/*===========================================================================* * rw_scattered * *===========================================================================*/ PUBLIC void rw_scattered( dev_t dev, /* major-minor device number */ struct buf **bufq, /* pointer to array of buffers */ int bufqsize, /* number of buffers */ int rw_flag /* READING or WRITING */ ) { /* Read or write scattered data from a device. */ register struct buf *bp; int gap; register int i; register iovec_t *iop; static iovec_t *iovec = NULL; int j, r; STATICINIT(iovec, NR_IOREQS); /* (Shell) sort buffers on b_blocknr. */ gap = 1; do gap = 3 * gap + 1; while (gap <= bufqsize); while (gap != 1) { gap /= 3; for (j = gap; j < bufqsize; j++) { for (i = j - gap; i >= 0 && bufq[i]->b_blocknr > bufq[i + gap]->b_blocknr; i -= gap) { bp = bufq[i]; bufq[i] = bufq[i + gap]; bufq[i + gap] = bp; } } } /* Set up I/O vector and do I/O. The result of dev_io is OK if everything * went fine, otherwise the error code for the first failed transfer. */ while (bufqsize > 0) { for (j = 0, iop = iovec; j < NR_IOREQS && j < bufqsize; j++, iop++) { bp = bufq[j]; if (bp->b_blocknr != (block_t) bufq[0]->b_blocknr + j) break; iop->iov_addr = (vir_bytes) bp->b_data; iop->iov_size = (vir_bytes) fs_block_size; } r = block_dev_io(rw_flag == WRITING ? MFS_DEV_SCATTER : MFS_DEV_GATHER, dev, SELF_E, iovec, mul64u(bufq[0]->b_blocknr, fs_block_size), j); /* Harvest the results. Dev_io reports the first error it may have * encountered, but we only care if it's the first block that failed. */ for (i = 0, iop = iovec; i < j; i++, iop++) { bp = bufq[i]; if (iop->iov_size != 0) { /* Transfer failed. An error? Do we care? */ if (r != OK && i == 0) { printf( "fs: I/O error on device %d/%d, block %lu\n", major(dev), minor(dev), bp->b_blocknr); bp->b_dev = NO_DEV; /* invalidate block */ vm_forgetblocks(); } break; } if (rw_flag == READING) { bp->b_dev = dev; /* validate block */ put_block(bp, PARTIAL_DATA_BLOCK); } else { bp->b_dirt = CLEAN; } } bufq += i; bufqsize -= i; if (rw_flag == READING) { /* Don't bother reading more than the device is willing to * give at this time. Don't forget to release those extras. */ while (bufqsize > 0) { put_block(*bufq++, PARTIAL_DATA_BLOCK); bufqsize--; } } if (rw_flag == WRITING && i == 0) { /* We're not making progress, this means we might keep * looping. Buffers remain dirty if un-written. Buffers are * lost if invalidate()d or LRU-removed while dirty. This * is better than keeping unwritable blocks around forever.. */ break; } } }
/*===========================================================================* * fs_readsuper * *===========================================================================*/ PUBLIC int fs_readsuper() { /* This function reads the superblock of the partition, gets the root inode * and sends back the details of them. Note, that the FS process does not * know the index of the vmnt object which refers to it, whenever the pathname * lookup leaves a partition an ELEAVEMOUNT error is transferred back * so that the VFS knows that it has to find the vnode on which this FS * process' partition is mounted on. */ struct inode *root_ip; cp_grant_id_t label_gid; size_t label_len; int r = OK; int readonly, isroot; u32_t mask; fs_dev = fs_m_in.REQ_DEV; label_gid = fs_m_in.REQ_GRANT; label_len = fs_m_in.REQ_PATH_LEN; readonly = (fs_m_in.REQ_FLAGS & REQ_RDONLY) ? 1 : 0; isroot = (fs_m_in.REQ_FLAGS & REQ_ISROOT) ? 1 : 0; if (label_len > sizeof(fs_dev_label)) return(EINVAL); r = sys_safecopyfrom(fs_m_in.m_source, label_gid, 0, (vir_bytes)fs_dev_label, label_len, D); if (r != OK) { printf("%s:%d fs_readsuper: safecopyfrom failed: %d\n", __FILE__, __LINE__, r); return(EINVAL); } /* Map the driver label for this major. */ bdev_driver(fs_dev, fs_dev_label); /* Open the device the file system lives on. */ if (bdev_open(fs_dev, readonly ? R_BIT : (R_BIT|W_BIT)) != OK) { return(EINVAL); } /* Fill in the super block. */ STATICINIT(superblock, 1); if (!superblock) panic("Can't allocate memory for superblock."); superblock->s_dev = fs_dev; /* read_super() needs to know which dev */ r = read_super(superblock); /* Is it recognized as a Minix filesystem? */ if (r != OK) { superblock->s_dev = NO_DEV; bdev_close(fs_dev); return(r); } if (superblock->s_rev_level != EXT2_GOOD_OLD_REV) { struct super_block *sp = superblock; /* just shorter name */ mask = ~SUPPORTED_INCOMPAT_FEATURES; if (HAS_INCOMPAT_FEATURE(sp, mask)) { if (HAS_INCOMPAT_FEATURE(sp, INCOMPAT_COMPRESSION & mask)) printf("ext2: fs compression is not supported by server\n"); if (HAS_INCOMPAT_FEATURE(sp, INCOMPAT_FILETYPE & mask)) printf("ext2: fs in dir filetype is not supported by server\n"); if (HAS_INCOMPAT_FEATURE(sp, INCOMPAT_RECOVER & mask)) printf("ext2: fs recovery is not supported by server\n"); if (HAS_INCOMPAT_FEATURE(sp, INCOMPAT_JOURNAL_DEV & mask)) printf("ext2: fs journal dev is not supported by server\n"); if (HAS_INCOMPAT_FEATURE(sp, INCOMPAT_META_BG & mask)) printf("ext2: fs meta bg is not supported by server\n"); return(EINVAL); } mask = ~SUPPORTED_RO_COMPAT_FEATURES; if (HAS_RO_COMPAT_FEATURE(sp, mask)) { if (HAS_RO_COMPAT_FEATURE(sp, RO_COMPAT_SPARSE_SUPER & mask)) { printf("ext2: sparse super is not supported by server, \ remount read-only\n"); } if (HAS_RO_COMPAT_FEATURE(sp, RO_COMPAT_LARGE_FILE & mask)) { printf("ext2: large files are not supported by server, \ remount read-only\n"); } if (HAS_RO_COMPAT_FEATURE(sp, RO_COMPAT_BTREE_DIR & mask)) { printf("ext2: dir's btree is not supported by server, \ remount read-only\n"); } return(EINVAL); } } if (superblock->s_state == EXT2_ERROR_FS) { printf("ext2: filesystem wasn't cleanly unmounted previous time\n"); superblock->s_dev = NO_DEV; bdev_close(fs_dev); return(EINVAL); } set_blocksize(superblock->s_block_size, superblock->s_blocks_count, superblock->s_free_blocks_count, major(fs_dev)); /* Get the root inode of the mounted file system. */ if ( (root_ip = get_inode(fs_dev, ROOT_INODE)) == NULL) { printf("ext2: couldn't get root inode\n"); superblock->s_dev = NO_DEV; bdev_close(fs_dev); return(EINVAL); } if (root_ip != NULL && root_ip->i_mode == 0) { printf("%s:%d zero mode for root inode?\n", __FILE__, __LINE__); put_inode(root_ip); superblock->s_dev = NO_DEV; bdev_close(fs_dev); return(EINVAL); } if (root_ip != NULL && (root_ip->i_mode & I_TYPE) != I_DIRECTORY) { printf("%s:%d root inode has wrong type, it's not a DIR\n", __FILE__, __LINE__); put_inode(root_ip); superblock->s_dev = NO_DEV; bdev_close(fs_dev); return(EINVAL); } superblock->s_rd_only = readonly; superblock->s_is_root = isroot; if (!readonly) { superblock->s_state = EXT2_ERROR_FS; superblock->s_mnt_count++; superblock->s_mtime = clock_time(); write_super(superblock); /* Commit info, we just set above */ } /* Root inode properties */ fs_m_out.RES_INODE_NR = root_ip->i_num; fs_m_out.RES_MODE = root_ip->i_mode; fs_m_out.RES_FILE_SIZE_LO = root_ip->i_size; fs_m_out.RES_UID = root_ip->i_uid; fs_m_out.RES_GID = root_ip->i_gid; fs_m_out.RES_CONREQS = 1; /* We can handle only 1 request at a time */ return(r); }
/*===========================================================================* * rw_scattered * *===========================================================================*/ void rw_scattered( dev_t dev, /* major-minor device number */ struct buf **bufq, /* pointer to array of buffers */ int bufqsize, /* number of buffers */ int rw_flag /* READING or WRITING */ ) { /* Read or write scattered data from a device. */ register struct buf *bp; int gap; register int i; register iovec_t *iop; static iovec_t *iovec = NULL; u64_t pos; int j, r; STATICINIT(iovec, NR_IOREQS); assert(bufq != NULL); /* (Shell) sort buffers on b_blocknr. */ gap = 1; do gap = 3 * gap + 1; while (gap <= bufqsize); while (gap != 1) { gap /= 3; for (j = gap; j < bufqsize; j++) { for (i = j - gap; i >= 0 && bufq[i]->b_blocknr > bufq[i + gap]->b_blocknr; i -= gap) { bp = bufq[i]; bufq[i] = bufq[i + gap]; bufq[i + gap] = bp; } } } /* Set up I/O vector and do I/O. The result of dev_io is OK if everything * went fine, otherwise the error code for the first failed transfer. */ while (bufqsize > 0) { for (j = 0, iop = iovec; j < NR_IOREQS && j < bufqsize; j++, iop++) { bp = bufq[j]; if (bp->b_blocknr != (block_t) bufq[0]->b_blocknr + j) break; iop->iov_addr = (vir_bytes) bp->b_data; iop->iov_size = (vir_bytes) fs_block_size; } pos = mul64u(bufq[0]->b_blocknr, fs_block_size); if (rw_flag == READING) r = bdev_gather(dev, pos, iovec, j, BDEV_NOFLAGS); else r = bdev_scatter(dev, pos, iovec, j, BDEV_NOFLAGS); /* Harvest the results. The driver may have returned an error, or it * may have done less than what we asked for. */ if (r < 0) { printf("ext2: I/O error %d on device %d/%d, block %u\n", r, major(dev), minor(dev), bufq[0]->b_blocknr); } for (i = 0; i < j; i++) { bp = bufq[i]; if (r < (ssize_t) fs_block_size) { /* Transfer failed. */ if (i == 0) { bp->b_dev = NO_DEV; /* invalidate block */ vm_forgetblocks(); } break; } if (rw_flag == READING) { bp->b_dev = dev; /* validate block */ put_block(bp, PARTIAL_DATA_BLOCK); } else { bp->b_dirt = CLEAN; } r -= fs_block_size; } bufq += i; bufqsize -= i; if (rw_flag == READING) { /* Don't bother reading more than the device is willing to * give at this time. Don't forget to release those extras. */ while (bufqsize > 0) { put_block(*bufq++, PARTIAL_DATA_BLOCK); bufqsize--; } } if (rw_flag == WRITING && i == 0) { /* We're not making progress, this means we might keep * looping. Buffers remain dirty if un-written. Buffers are * lost if invalidate()d or LRU-removed while dirty. This * is better than keeping unwritable blocks around forever.. */ break; } } }