/*===========================================================================* * 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); }
/*===========================================================================* * 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); }
/*===========================================================================* * 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); }
/*===========================================================================* * 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; }