Exemple #1
0
/*===========================================================================*
 *				fs_readwrite				     *
 *===========================================================================*/
PUBLIC int fs_readwrite(void)
{
  int r, rw_flag, block_spec;
  int regular;
  cp_grant_id_t gid;
  off_t position, f_size, bytes_left;
  unsigned int off, cum_io, block_size, chunk;
  mode_t mode_word;
  int completed;
  struct inode *rip;
  size_t nrbytes;
  
  r = OK;
  
  /* Find the inode referred */
  if ((rip = find_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
	return(EINVAL);

  mode_word = rip->i_mode & I_TYPE;
  regular = (mode_word == I_REGULAR || mode_word == I_NAMED_PIPE);
  block_spec = (mode_word == I_BLOCK_SPECIAL ? 1 : 0);
  
  /* Determine blocksize */
  if (block_spec) {
	block_size = get_block_size( (dev_t) rip->i_zone[0]);
	f_size = MAX_FILE_POS;
  } else {
  	block_size = rip->i_sp->s_block_size;
  	f_size = rip->i_size;
  }

  /* Get the values from the request message */ 
  rw_flag = (fs_m_in.m_type == REQ_READ ? READING : WRITING);
  gid = (cp_grant_id_t) fs_m_in.REQ_GRANT;
  position = (off_t) fs_m_in.REQ_SEEK_POS_LO;
  nrbytes = (size_t) fs_m_in.REQ_NBYTES;
  
  rdwt_err = OK;		/* set to EIO if disk error occurs */

  /* If this is file i/o, check we can write */
  if (rw_flag == WRITING && !block_spec) {
  	  if(rip->i_sp->s_rd_only) 
		  return EROFS;

	  /* Check in advance to see if file will grow too big. */
	  if (position > (off_t) (rip->i_sp->s_max_size - nrbytes))
		  return(EFBIG);

	  /* Clear the zone containing present EOF if hole about
	   * to be created.  This is necessary because all unwritten
	   * blocks prior to the EOF must read as zeros.
	   */
	  if(position > f_size) clear_zone(rip, f_size, 0);
  }

  /* If this is block i/o, check we can write */
  if(block_spec && rw_flag == WRITING &&
  	(dev_t) rip->i_zone[0] == superblock.s_dev && superblock.s_rd_only)
		return EROFS;
	      
  cum_io = 0;
  /* Split the transfer into chunks that don't span two blocks. */
  while (nrbytes > 0) {
	  off = ((unsigned int) position) % block_size; /* offset in blk*/
	  chunk = min(nrbytes, block_size - off);

	  if (rw_flag == READING) {
		  bytes_left = f_size - position;
		  if (position >= f_size) break;	/* we are beyond EOF */
		  if (chunk > (unsigned int) bytes_left) chunk = bytes_left;
	  }
	  
	  /* Read or write 'chunk' bytes. */
	  r = rw_chunk(rip, cvul64((unsigned long) position), off, chunk,
	  	       nrbytes, rw_flag, gid, cum_io, block_size, &completed);

	  if (r != OK) break;	/* EOF reached */
	  if (rdwt_err < 0) break;

	  /* Update counters and pointers. */
	  nrbytes -= chunk;	/* bytes yet to be read */
	  cum_io += chunk;	/* bytes read so far */
	  position += (off_t) chunk;	/* position within the file */
  }

  fs_m_out.RES_SEEK_POS_LO = position; /* It might change later and the VFS
					   has to know this value */
  
  /* On write, update file size and access time. */
  if (rw_flag == WRITING) {
	  if (regular || mode_word == I_DIRECTORY) {
		  if (position > f_size) rip->i_size = position;
	  }
  } 

  rip->i_seek = NO_SEEK;

  if (rdwt_err != OK) r = rdwt_err;	/* check for disk error */
  if (rdwt_err == END_OF_FILE) r = OK;

  /* even on a ROFS, writing to a device node on it is fine, 
   * just don't update the inode stats for it. And dito for reading.
   */
  if (r == OK && !rip->i_sp->s_rd_only) {
	  if (rw_flag == READING) rip->i_update |= ATIME;
	  if (rw_flag == WRITING) rip->i_update |= CTIME | MTIME;
	  IN_MARKDIRTY(rip);		/* inode is thus now dirty */
  }
  
  fs_m_out.RES_NBYTES = cum_io;
  
  return(r);
}
Exemple #2
0
/*===========================================================================*
 *				fs_readwrite				     *
 *===========================================================================*/
PUBLIC int fs_readwrite(void)
{
  int r, rw_flag, block_spec;
  int regular;
  cp_grant_id_t gid;
  off_t position, f_size, bytes_left;
  unsigned int off, cum_io, block_size, chunk;
  mode_t mode_word;
  int completed;
  struct inode *rip;
  size_t nrbytes;
  
  r = OK;
  
  /* Find the inode referred */
  if ((rip = find_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
	return(EINVAL);

  mode_word = rip->i_mode & I_TYPE;
  /* immediate files are regular files too! */
  regular = (mode_word == I_REGULAR || mode_word == I_IMMEDIATE || mode_word == I_NAMED_PIPE);
  block_spec = (mode_word == I_BLOCK_SPECIAL ? 1 : 0);
  
  /* Determine blocksize */
  if (block_spec) {
	block_size = get_block_size( (dev_t) rip->i_zone[0]);
	f_size = MAX_FILE_POS;
  } else {
  	block_size = rip->i_sp->s_block_size;
  	f_size = rip->i_size;
  }

  /* Get the values from the request message */ 
  rw_flag = (fs_m_in.m_type == REQ_READ ? READING : WRITING);
  gid = (cp_grant_id_t) fs_m_in.REQ_GRANT;
  position = (off_t) fs_m_in.REQ_SEEK_POS_LO;
  nrbytes = (size_t) fs_m_in.REQ_NBYTES;
  
  rdwt_err = OK;		/* set to EIO if disk error occurs */

  if (rw_flag == WRITING && !block_spec && (rip->i_mode & I_TYPE) != I_IMMEDIATE) {
	  /* Check in advance to see if file will grow too big. */
	  if (position > (off_t) (rip->i_sp->s_max_size - nrbytes))
		  return(EFBIG);

	  /* Clear the zone containing present EOF if hole about
	   * to be created.  This is necessary because all unwritten
	   * blocks prior to the EOF must read as zeros.
	   */
	  if(position > f_size) clear_zone(rip, f_size, 0);
  }
  
  cum_io = 0;
	
	if((rip->i_mode & I_TYPE) == I_IMMEDIATE)
	{
    int sanity = 0;
    if(f_size > 40) printf("Immediate file is %d bytes!\n", f_size);
    
    if(rw_flag == WRITING)
    {  
      /* printf("fs_readwrite() WRITING to immediate file\n"); */
        
      /* is the file going to need to be upconverted from immediate to regular? */
      if((f_size + nrbytes) > 40 || position > 40)
      {
        char tmp[40];
        register int i;
        register struct buf *bp;
        
        for(i = 0; i < f_size; i++)
        {
          tmp[i] = *(((char *)rip->i_zone) + i);
        }
        
        /* clear inode since it will now hold pointers rather than data (copied from wipe_inode()) */
        rip->i_size = 0;
        rip->i_update = ATIME | CTIME | MTIME;	/* update all times later */
        rip->i_dirt = DIRTY;
        for (i = 0; i < V2_NR_TZONES; i++) rip->i_zone[i] = NO_ZONE;
        
        /* Writing to a nonexistent block. Create and enter in inode.*/
    		if ((bp = new_block(rip, (off_t) 0)) == NULL)
    			panic("bp not valid in fs_readwrite immediate growth; this can't be happening!");
    		
    		/* copy data to bp->data */
    		for(i = 0; i < f_size; i++)
        {
          bp->b_data[i] = tmp[i];
        }
    		
        bp->b_dirt = DIRTY;
    		
        put_block(bp, PARTIAL_DATA_BLOCK);	
    		
        position += f_size;
        f_size = rip->i_size;
        rip->i_mode = (I_REGULAR | (rip->i_mode & ALL_MODES));
      }
      /* the file will not grow over 40 bytes */
      else
      {
        sanity = 1;
      }
    }
    else
    {
      /* printf("fs_readwrite() READING from immediate file\n"); */
      
      bytes_left = f_size - position;
      /* if the position is past the end of the file, it is already too late... */
      if(bytes_left > 0)
      {
        sanity = 1;
        /* don't read past the EOF, just right up to it */
        if(nrbytes > bytes_left) nrbytes = bytes_left;
      }
    }
    
    if(sanity)
    {
      r = rw_immed(rip, position, nrbytes, rw_flag, gid, cum_io);
      if(r == OK)
      {
        cum_io += nrbytes;
        position += nrbytes;
        /* no more bytes left to read */
        nrbytes = 0;
      }
    }
	}
	
  /* Split the transfer into chunks that don't span two blocks. */
  while (nrbytes > 0) {
	  off = ((unsigned int) position) % block_size; /* offset in blk*/
	  chunk = min(nrbytes, block_size - off);

	  if (rw_flag == READING) {
		  bytes_left = f_size - position;
		  if (position >= f_size) break;	/* we are beyond EOF */
		  if (chunk > (unsigned int) bytes_left) chunk = bytes_left;
	  }
	  
	  /* Read or write 'chunk' bytes. */
	  r = rw_chunk(rip, cvul64((unsigned long) position), off, chunk,
	  	       nrbytes, rw_flag, gid, cum_io, block_size, &completed);

	  if (r != OK) break;	/* EOF reached */
	  if (rdwt_err < 0) break;

	  /* Update counters and pointers. */
	  nrbytes -= chunk;	/* bytes yet to be read */
	  cum_io += chunk;	/* bytes read so far */
	  position += (off_t) chunk;	/* position within the file */
  }

  fs_m_out.RES_SEEK_POS_LO = position; /* It might change later and the VFS
					   has to know this value */
  
  /* On write, update file size and access time. */
  if (rw_flag == WRITING) {
	  if (regular || mode_word == I_DIRECTORY) {
		  if (position > f_size) rip->i_size = position;
	  }
  }

  /* Check to see if read-ahead is called for, and if so, set it up. */
  if(rw_flag == READING && rip->i_seek == NO_SEEK &&
     (unsigned int) position % block_size == 0 &&
     (regular || mode_word == I_DIRECTORY)) {
	  rdahed_inode = rip;
	  rdahedpos = position;
  } 

  rip->i_seek = NO_SEEK;

  if (rdwt_err != OK) r = rdwt_err;	/* check for disk error */
  if (rdwt_err == END_OF_FILE) r = OK;

  if (r == OK) {
	  if (rw_flag == READING) rip->i_update |= ATIME;
	  if (rw_flag == WRITING) rip->i_update |= CTIME | MTIME;
	  rip->i_dirt = DIRTY;		/* inode is thus now dirty */
  }
  
  fs_m_out.RES_NBYTES = cum_io;
  
  return(r);
}
Exemple #3
0
/*===========================================================================*
 *				fs_readwrite_o				     *
 *===========================================================================*/
PUBLIC int fs_readwrite_o(void)
{
  int r, usr, seg, rw_flag, chunk, block_size, block_spec;
  int partial_cnt, regular, partial_pipe, nrbytes;
  off_t position, f_size, bytes_left;
  unsigned int off, cum_io;
  mode_t mode_word;
  int completed, r2 = OK;
  char *user_addr;
  struct inode *rip;
  
  partial_pipe = 0;
  r = OK;
  
  /* Try to get inode according to its index */
  if (fs_m_in.REQ_FD_INODE_INDEX >= 0 && 
          fs_m_in.REQ_FD_INODE_INDEX < NR_INODES &&
          inode[fs_m_in.REQ_FD_INODE_INDEX].i_num == fs_m_in.REQ_FD_INODE_NR) {
      rip = &inode[fs_m_in.REQ_FD_INODE_INDEX];
  }
  else { 
      /* Find the inode referred */
      rip = find_inode(fs_dev, fs_m_in.REQ_FD_INODE_NR);
      if (!rip) {
          printf("FS: unavaliable inode by fs_readwrite(), nr: %d\n", 
                  fs_m_in.REQ_FD_INODE_NR);
          return EINVAL; 
      }
  }

  mode_word = rip->i_mode & I_TYPE;
  regular = (mode_word == I_REGULAR || mode_word == I_NAMED_PIPE);
  block_spec = (mode_word == I_BLOCK_SPECIAL ? 1 : 0);
  
  /* Determine blocksize */
  block_size = (block_spec ? get_block_size(rip->i_zone[0]) 
      : rip->i_sp->s_block_size);

  f_size = (block_spec ? ULONG_MAX : rip->i_size);
  
  /* Get the values from the request message */ 
  rw_flag = (fs_m_in.m_type == REQ_READ_O ? READING : WRITING);
  usr = fs_m_in.REQ_FD_WHO_E;
  seg = fs_m_in.REQ_FD_SEG;
  position = fs_m_in.REQ_FD_POS;
  nrbytes = (unsigned) fs_m_in.REQ_FD_NBYTES;
  /*partial_cnt = fs_m_in.REQ_FD_PARTIAL;*/
  user_addr = fs_m_in.REQ_FD_USER_ADDR;

  /*if (partial_cnt > 0) partial_pipe = 1;*/
  
  rdwt_err = OK;		/* set to EIO if disk error occurs */
  
  if (rw_flag == WRITING && block_spec == 0) {
      /* Clear the zone containing present EOF if hole about
       * to be created.  This is necessary because all unwritten
       * blocks prior to the EOF must read as zeros.
       */
      if (position > f_size) clear_zone(rip, f_size, 0);
  }
	      
  cum_io = 0;
  /* Split the transfer into chunks that don't span two blocks. */
  while (nrbytes != 0) {
      off = (unsigned int) (position % block_size);/* offset in blk*/
          
      chunk = MIN(nrbytes, block_size - off);
      if (chunk < 0) chunk = block_size - off;

      if (rw_flag == READING) {
          bytes_left = f_size - position;
          if (position >= f_size) break;	/* we are beyond EOF */
          if (chunk > bytes_left) chunk = (int) bytes_left;
      }

      /* Read or write 'chunk' bytes. */
      r = rw_chunk(rip, cvul64(position), off, chunk, (unsigned) nrbytes,
              rw_flag, user_addr, seg, usr, block_size, &completed);

      if (r != OK) break;	/* EOF reached */
      if (rdwt_err < 0) break;

      /* Update counters and pointers. */
      user_addr += chunk;	/* user buffer address */
      nrbytes -= chunk;	/* bytes yet to be read */
      cum_io += chunk;	/* bytes read so far */
      position += chunk;	/* position within the file */
  }

  fs_m_out.RES_FD_POS = position; /* It might change later and the VFS has
				     to know this value */
  
  /* On write, update file size and access time. */
  if (rw_flag == WRITING) {
	if (regular || mode_word == I_DIRECTORY) {
		if (position > f_size) rip->i_size = position;
	}
  } 
  else {
	if (rip->i_pipe == I_PIPE) {
		if ( position >= rip->i_size) {
			/* Reset pipe pointers. */
			rip->i_size = 0;	/* no data left */
			position = 0;		/* reset reader(s) */
		}
	}
  }

  /* Check to see if read-ahead is called for, and if so, set it up. */
  if (rw_flag == READING && rip->i_seek == NO_SEEK && position % block_size == 0
		&& (regular || mode_word == I_DIRECTORY)) {
	rdahed_inode = rip;
	rdahedpos = position;
  }
  rip->i_seek = NO_SEEK;

  if (rdwt_err != OK) r = rdwt_err;	/* check for disk error */
  if (rdwt_err == END_OF_FILE) r = OK;

  /* if user-space copying failed, read/write failed. */
  if (r == OK && r2 != OK) {
	r = r2;
  }
  
  if (r == OK) {
	if (rw_flag == READING) rip->i_update |= ATIME;
	if (rw_flag == WRITING) rip->i_update |= CTIME | MTIME;
	rip->i_dirt = DIRTY;		/* inode is thus now dirty */
  }
  
  fs_m_out.RES_FD_CUM_IO = cum_io;
  fs_m_out.RES_FD_SIZE = rip->i_size;
  
  return(r);
}
Exemple #4
0
/*===========================================================================*
 *				fs_readwrite				     *
 *===========================================================================*/
ssize_t fs_readwrite(ino_t ino_nr, struct fsdriver_data *data, size_t nrbytes,
	off_t position, int call)
{
  int r;
  int regular;
  off_t f_size, bytes_left;
  size_t off, cum_io, block_size, chunk;
  mode_t mode_word;
  int completed;
  struct inode *rip;
  
  r = OK;
  
  /* Find the inode referred */
  if ((rip = find_inode(fs_dev, ino_nr)) == NULL)
	return(EINVAL);

  mode_word = rip->i_mode & I_TYPE;
  regular = (mode_word == I_REGULAR);
  
  /* Determine blocksize */
  block_size = rip->i_sp->s_block_size;
  f_size = rip->i_size;

  lmfs_reset_rdwt_err();

  /* If this is file i/o, check we can write */
  if (call == FSC_WRITE) {
  	  if(rip->i_sp->s_rd_only) 
		  return EROFS;

	  /* Check in advance to see if file will grow too big. */
	  if (position > (off_t) (rip->i_sp->s_max_size - nrbytes))
		  return(EFBIG);

	  /* Clear the zone containing present EOF if hole about
	   * to be created.  This is necessary because all unwritten
	   * blocks prior to the EOF must read as zeros.
	   */
	  if(position > f_size) clear_zone(rip, f_size, 0);
  }

  cum_io = 0;
  /* Split the transfer into chunks that don't span two blocks. */
  while (nrbytes > 0) {
	  off = ((unsigned int) position) % block_size; /* offset in blk*/
	  chunk = block_size - off;
	  if (chunk > nrbytes)
		chunk = nrbytes;

	  if (call == FSC_READ) {
		  bytes_left = f_size - position;
		  if (position >= f_size) break;	/* we are beyond EOF */
		  if (chunk > (unsigned int) bytes_left) chunk = bytes_left;
	  }
	  
	  /* Read or write 'chunk' bytes. */
	  r = rw_chunk(rip, ((u64_t)((unsigned long)position)), off, chunk,
		nrbytes, call, data, cum_io, block_size, &completed);

	  if (r != OK) break;	/* EOF reached */
	  if (lmfs_rdwt_err() < 0) break;

	  /* Update counters and pointers. */
	  nrbytes -= chunk;	/* bytes yet to be read */
	  cum_io += chunk;	/* bytes read so far */
	  position += (off_t) chunk;	/* position within the file */
  }

  /* On write, update file size and access time. */
  if (call == FSC_WRITE) {
	  if (regular || mode_word == I_DIRECTORY) {
		  if (position > f_size) rip->i_size = position;
	  }
  } 

  rip->i_seek = NO_SEEK;

  if (lmfs_rdwt_err() != OK) r = lmfs_rdwt_err(); /* check for disk error */
  if (lmfs_rdwt_err() == END_OF_FILE) r = OK;

  if (r != OK)
	return r;

  /* even on a ROFS, writing to a device node on it is fine, 
   * just don't update the inode stats for it. And dito for reading.
   */
  if (!rip->i_sp->s_rd_only) {
	  if (call == FSC_READ) rip->i_update |= ATIME;
	  if (call == FSC_WRITE) rip->i_update |= CTIME | MTIME;
	  IN_MARKDIRTY(rip);		/* inode is thus now dirty */
  }
  
  return cum_io;
}