⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 read.c

📁 一个简单的操作系统minix的核心代码
💻 C
📖 第 1 页 / 共 2 页
字号:
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 + -