📄 read.c
字号:
23656 * the cache, acquire it, otherwise just acquire a free buffer.
23657 */
23658 n = (chunk == BLOCK_SIZE ? NO_READ : NORMAL);
23659 if (!block_spec && off == 0 && position >= rip->i_size) n = NO_READ;
23660 bp = get_block(dev, b, n);
23661 }
23662
23663 /* In all cases, bp now points to a valid buffer. */
23664 if (rw_flag == WRITING && chunk != BLOCK_SIZE && !block_spec &&
23665 position >= rip->i_size && off == 0) {
23666 zero_block(bp);
23667 }
23668 if (rw_flag == READING) {
23669 /* Copy a chunk from the block buffer to user space. */
23670 r = sys_copy(FS_PROC_NR, D, (phys_bytes) (bp->b_data+off),
23671 usr, seg, (phys_bytes) buff,
23672 (phys_bytes) chunk);
23673 } else {
23674 /* Copy a chunk from user space to the block buffer. */
23675 r = sys_copy(usr, seg, (phys_bytes) buff,
23676 FS_PROC_NR, D, (phys_bytes) (bp->b_data+off),
23677 (phys_bytes) chunk);
23678 bp->b_dirt = DIRTY;
23679 }
23680 n = (off + chunk == BLOCK_SIZE ? FULL_DATA_BLOCK : PARTIAL_DATA_BLOCK);
23681 put_block(bp, n);
23682 return(r);
23683 }
23686 /*===========================================================================*
23687 * read_map *
23688 *===========================================================================*/
23689 PUBLIC block_t read_map(rip, position)
23690 register struct inode *rip; /* ptr to inode to map from */
23691 off_t position; /* position in file whose blk wanted */
23692 {
23693 /* Given an inode and a position within the corresponding file, locate the
23694 * block (not zone) number in which that position is to be found and return it.
23695 */
23696
23697 register struct buf *bp;
23698 register zone_t z;
23699 int scale, boff, dzones, nr_indirects, index, zind, ex;
23700 block_t b;
23701 long excess, zone, block_pos;
23702
23703 scale = rip->i_sp->s_log_zone_size; /* for block-zone conversion */
23704 block_pos = position/BLOCK_SIZE; /* relative blk # in file */
23705 zone = block_pos >> scale; /* position's zone */
23706 boff = (int) (block_pos - (zone << scale) ); /* relative blk # within zone */
23707 dzones = rip->i_ndzones;
23708 nr_indirects = rip->i_nindirs;
23709
23710 /* Is 'position' to be found in the inode itself? */
23711 if (zone < dzones) {
23712 zind = (int) zone; /* index should be an int */
23713 z = rip->i_zone[zind];
23714 if (z == NO_ZONE) return(NO_BLOCK);
23715 b = ((block_t) z << scale) + boff;
23716 return(b);
23717 }
23718
23719 /* It is not in the inode, so it must be single or double indirect. */
23720 excess = zone - dzones; /* first Vx_NR_DZONES don't count */
23721
23722 if (excess < nr_indirects) {
23723 /* 'position' can be located via the single indirect block. */
23724 z = rip->i_zone[dzones];
23725 } else {
23726 /* 'position' can be located via the double indirect block. */
23727 if ( (z = rip->i_zone[dzones+1]) == NO_ZONE) return(NO_BLOCK);
23728 excess -= nr_indirects; /* single indir doesn't count*/
23729 b = (block_t) z << scale;
23730 bp = get_block(rip->i_dev, b, NORMAL); /* get double indirect block */
23731 index = (int) (excess/nr_indirects);
23732 z = rd_indir(bp, index); /* z= zone for single*/
23733 put_block(bp, INDIRECT_BLOCK); /* release double ind block */
23734 excess = excess % nr_indirects; /* index into single ind blk */
23735 }
23736
23737 /* 'z' is zone num for single indirect block; 'excess' is index into it. */
23738 if (z == NO_ZONE) return(NO_BLOCK);
23739 b = (block_t) z << scale; /* b is blk # for single ind */
23740 bp = get_block(rip->i_dev, b, NORMAL); /* get single indirect block */
23741 ex = (int) excess; /* need an integer */
23742 z = rd_indir(bp, ex); /* get block pointed to */
23743 put_block(bp, INDIRECT_BLOCK); /* release single indir blk */
23744 if (z == NO_ZONE) return(NO_BLOCK);
23745 b = ((block_t) z << scale) + boff;
23746 return(b);
23747 }
23750 /*===========================================================================*
23751 * rd_indir *
23752 *===========================================================================*/
23753 PUBLIC zone_t rd_indir(bp, index)
23754 struct buf *bp; /* pointer to indirect block */
23755 int index; /* index into *bp */
23756 {
23757 /* Given a pointer to an indirect block, read one entry. The reason for
23758 * making a separate routine out of this is that there are four cases:
23759 * V1 (IBM and 68000), and V2 (IBM and 68000).
23760 */
23761
23762 struct super_block *sp;
23763 zone_t zone; /* V2 zones are longs (shorts in V1) */
23764
23765 sp = get_super(bp->b_dev); /* need super block to find file sys type */
23766
23767 /* read a zone from an indirect block */
23768 if (sp->s_version == V1)
23769 zone = (zone_t) conv2(sp->s_native, (int) bp->b_v1_ind[index]);
23770 else
23771 zone = (zone_t) conv4(sp->s_native, (long) bp->b_v2_ind[index]);
23772
23773 if (zone != NO_ZONE &&
23774 (zone < (zone_t) sp->s_firstdatazone || zone >= sp->s_zones)) {
23775 printf("Illegal zone number %ld in indirect block, index %d\n",
23776 (long) zone, index);
23777 panic("check file system", NO_NUM);
23778 }
23779 return(zone);
23780 }
23783 /*===========================================================================*
23784 * read_ahead *
23785 *===========================================================================*/
23786 PUBLIC void read_ahead()
23787 {
23788 /* Read a block into the cache before it is needed. */
23789
23790 register struct inode *rip;
23791 struct buf *bp;
23792 block_t b;
23793
23794 rip = rdahed_inode; /* pointer to inode to read ahead from */
23795 rdahed_inode = NIL_INODE; /* turn off read ahead */
23796 if ( (b = read_map(rip, rdahedpos)) == NO_BLOCK) return; /* at EOF */
23797 bp = rahead(rip, b, rdahedpos, BLOCK_SIZE);
23798 put_block(bp, PARTIAL_DATA_BLOCK);
23799 }
23802 /*===========================================================================*
23803 * rahead *
23804 *===========================================================================*/
23805 PUBLIC struct buf *rahead(rip, baseblock, position, bytes_ahead)
23806 register struct inode *rip; /* pointer to inode for file to be read */
23807 block_t baseblock; /* block at current position */
23808 off_t position; /* position within file */
23809 unsigned bytes_ahead; /* bytes beyond position for immediate use */
23810 {
23811 /* Fetch a block from the cache or the device. If a physical read is
23812 * required, prefetch as many more blocks as convenient into the cache.
23813 * This usually covers bytes_ahead and is at least BLOCKS_MINIMUM.
23814 * The device driver may decide it knows better and stop reading at a
23815 * cylinder boundary (or after an error). Rw_scattered() puts an optional
23816 * flag on all reads to allow this.
23817 */
23818
23819 /* Minimum number of blocks to prefetch. */
23820 # define BLOCKS_MINIMUM (NR_BUFS < 50 ? 18 : 32)
23821
23822 int block_spec, scale, read_q_size;
23823 unsigned int blocks_ahead, fragment;
23824 block_t block, blocks_left;
23825 off_t ind1_pos;
23826 dev_t dev;
23827 struct buf *bp;
23828 static struct buf *read_q[NR_BUFS];
23829
23830 block_spec = (rip->i_mode & I_TYPE) == I_BLOCK_SPECIAL;
23831 if (block_spec) {
23832 dev = (dev_t) rip->i_zone[0];
23833 } else {
23834 dev = rip->i_dev;
23835 }
23836
23837 block = baseblock;
23838 bp = get_block(dev, block, PREFETCH);
23839 if (bp->b_dev != NO_DEV) return(bp);
23840
23841 /* The best guess for the number of blocks to prefetch: A lot.
23842 * It is impossible to tell what the device looks like, so we don't even
23843 * try to guess the geometry, but leave it to the driver.
23844 *
23845 * The floppy driver can read a full track with no rotational delay, and it
23846 * avoids reading partial tracks if it can, so handing it enough buffers to
23847 * read two tracks is perfect. (Two, because some diskette types have
23848 * an odd number of sectors per track, so a block may span tracks.)
23849 *
23850 * The disk drivers don't try to be smart. With todays disks it is
23851 * impossible to tell what the real geometry looks like, so it is best to
23852 * read as much as you can. With luck the caching on the drive allows
23853 * for a little time to start the next read.
23854 *
23855 * The current solution below is a bit of a hack, it just reads blocks from
23856 * the current file position hoping that more of the file can be found. A
23857 * better solution must look at the already available zone pointers and
23858 * indirect blocks (but don't call read_map!).
23859 */
23860
23861 fragment = position % BLOCK_SIZE;
23862 position -= fragment;
23863 bytes_ahead += fragment;
23864
23865 blocks_ahead = (bytes_ahead + BLOCK_SIZE - 1) / BLOCK_SIZE;
23866
23867 if (block_spec && rip->i_size == 0) {
23868 blocks_left = NR_IOREQS;
23869 } else {
23870 blocks_left = (rip->i_size - position + BLOCK_SIZE - 1) / BLOCK_SIZE;
23871
23872 /* Go for the first indirect block if we are in its neighborhood. */
23873 if (!block_spec) {
23874 scale = rip->i_sp->s_log_zone_size;
23875 ind1_pos = (off_t) rip->i_ndzones * (BLOCK_SIZE << scale);
23876 if (position <= ind1_pos && rip->i_size > ind1_pos) {
23877 blocks_ahead++;
23878 blocks_left++;
23879 }
23880 }
23881 }
23882
23883 /* No more than the maximum request. */
23884 if (blocks_ahead > NR_IOREQS) blocks_ahead = NR_IOREQS;
23885
23886 /* Read at least the minimum number of blocks, but not after a seek. */
23887 if (blocks_ahead < BLOCKS_MINIMUM && rip->i_seek == NO_SEEK)
23888 blocks_ahead = BLOCKS_MINIMUM;
23889
23890 /* Can't go past end of file. */
23891 if (blocks_ahead > blocks_left) blocks_ahead = blocks_left;
23892
23893 read_q_size = 0;
23894
23895 /* Acquire block buffers. */
23896 for (;;) {
23897 read_q[read_q_size++] = bp;
23898
23899 if (--blocks_ahead == 0) break;
23900
23901 /* Don't trash the cache, leave 4 free. */
23902 if (bufs_in_use >= NR_BUFS - 4) break;
23903
23904 block++;
23905
23906 bp = get_block(dev, block, PREFETCH);
23907 if (bp->b_dev != NO_DEV) {
23908 /* Oops, block already in the cache, get out. */
23909 put_block(bp, FULL_DATA_BLOCK);
23910 break;
23911 }
23912 }
23913 rw_scattered(dev, read_q, read_q_size, READING);
23914 return(get_block(dev, baseblock, NORMAL));
23915 }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -