Make use of vectored virtual copy system call
This commit is contained in:
parent
4e155167c8
commit
6ea72ca1ee
@ -24,7 +24,9 @@
|
|||||||
|
|
||||||
FORWARD _PROTOTYPE( int rw_chunk, (struct inode *rip, off_t position,
|
FORWARD _PROTOTYPE( int rw_chunk, (struct inode *rip, off_t position,
|
||||||
unsigned off, int chunk, unsigned left, int rw_flag,
|
unsigned off, int chunk, unsigned left, int rw_flag,
|
||||||
char *buff, int seg, int usr, int block_size) );
|
char *buff, int seg, int usr, int block_size, int *completed) );
|
||||||
|
|
||||||
|
FORWARD _PROTOTYPE( int rw_chunk_finish, (int *) );
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* do_read *
|
* do_read *
|
||||||
@ -34,6 +36,24 @@ PUBLIC int do_read()
|
|||||||
return(read_write(READING));
|
return(read_write(READING));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The following data is shared between rw_chunk() and rw_chunk_finish().
|
||||||
|
* It saves up the copying operations that have to be done between user
|
||||||
|
* space and the file system. After every (set of) rw_chunk()s,
|
||||||
|
* rw_chunk_finish() has to be called immediately (before the FS call returns)
|
||||||
|
* so the actual data copying is done.
|
||||||
|
*
|
||||||
|
* The point of this is to save on the number of copy system calls.
|
||||||
|
*/
|
||||||
|
#define COPY_QUEUE_LEN CPVEC_NR
|
||||||
|
PRIVATE struct copy_queue_entry {
|
||||||
|
struct buf *bp; /* buf to put_block after copying */
|
||||||
|
int user_seg, user_proc; /* user space data */
|
||||||
|
phys_bytes user_offset, fs_offset;
|
||||||
|
int blocktype;
|
||||||
|
int chunk;
|
||||||
|
int op;
|
||||||
|
} copy_queue[COPY_QUEUE_LEN];
|
||||||
|
PRIVATE int copy_queue_used = 0;
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* read_write *
|
* read_write *
|
||||||
@ -52,6 +72,16 @@ int rw_flag; /* READING or WRITING */
|
|||||||
mode_t mode_word;
|
mode_t mode_word;
|
||||||
struct filp *wf;
|
struct filp *wf;
|
||||||
int block_size;
|
int block_size;
|
||||||
|
int completed, r2 = OK;
|
||||||
|
phys_bytes p;
|
||||||
|
|
||||||
|
/* left unfinished rw_chunk()s from previous call! this can't happen.
|
||||||
|
* it means something has gone wrong we can't repair now.
|
||||||
|
*/
|
||||||
|
if(copy_queue_used != 0) {
|
||||||
|
panic("copy queue size nonzero when entering read_write().",
|
||||||
|
copy_queue_used);
|
||||||
|
}
|
||||||
|
|
||||||
/* MM loads segments by putting funny things in upper 10 bits of 'fd'. */
|
/* MM loads segments by putting funny things in upper 10 bits of 'fd'. */
|
||||||
if (who == PM_PROC_NR && (m_in.fd & (~BYTE)) ) {
|
if (who == PM_PROC_NR && (m_in.fd & (~BYTE)) ) {
|
||||||
@ -70,6 +100,13 @@ int rw_flag; /* READING or WRITING */
|
|||||||
return(f->filp_mode == FILP_CLOSED ? EIO : EBADF);
|
return(f->filp_mode == FILP_CLOSED ? EIO : EBADF);
|
||||||
}
|
}
|
||||||
if (m_in.nbytes == 0) return(0); /* so char special files need not check for 0*/
|
if (m_in.nbytes == 0) return(0); /* so char special files need not check for 0*/
|
||||||
|
|
||||||
|
/* check if user process has the memory it needs.
|
||||||
|
* if not, copying will fail later.
|
||||||
|
* do this after 0-check above because umap doesn't want to map 0 bytes.
|
||||||
|
*/
|
||||||
|
if ((r = sys_umap(usr, seg, (vir_bytes) m_in.buffer, m_in.nbytes, &p)) != OK)
|
||||||
|
return r;
|
||||||
position = f->filp_pos;
|
position = f->filp_pos;
|
||||||
oflags = f->filp_flags;
|
oflags = f->filp_flags;
|
||||||
rip = f->filp_ino;
|
rip = f->filp_ino;
|
||||||
@ -139,6 +176,7 @@ int rw_flag; /* READING or WRITING */
|
|||||||
|
|
||||||
/* Split the transfer into chunks that don't span two blocks. */
|
/* Split the transfer into chunks that don't span two blocks. */
|
||||||
while (m_in.nbytes != 0) {
|
while (m_in.nbytes != 0) {
|
||||||
|
|
||||||
off = (unsigned int) (position % block_size);/* offset in blk*/
|
off = (unsigned int) (position % block_size);/* offset in blk*/
|
||||||
if (partial_pipe) { /* pipes only */
|
if (partial_pipe) { /* pipes only */
|
||||||
chunk = MIN(partial_cnt, block_size - off);
|
chunk = MIN(partial_cnt, block_size - off);
|
||||||
@ -154,7 +192,8 @@ int rw_flag; /* READING or WRITING */
|
|||||||
|
|
||||||
/* Read or write 'chunk' bytes. */
|
/* Read or write 'chunk' bytes. */
|
||||||
r = rw_chunk(rip, position, off, chunk, (unsigned) m_in.nbytes,
|
r = rw_chunk(rip, position, off, chunk, (unsigned) m_in.nbytes,
|
||||||
rw_flag, m_in.buffer, seg, usr, block_size);
|
rw_flag, m_in.buffer, seg, usr, block_size, &completed);
|
||||||
|
|
||||||
if (r != OK) break; /* EOF reached */
|
if (r != OK) break; /* EOF reached */
|
||||||
if (rdwt_err < 0) break;
|
if (rdwt_err < 0) break;
|
||||||
|
|
||||||
@ -171,6 +210,9 @@ int rw_flag; /* READING or WRITING */
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* do copying to/from user space */
|
||||||
|
r2 = rw_chunk_finish(&completed);
|
||||||
|
|
||||||
/* On write, update file size and access time. */
|
/* On write, update file size and access time. */
|
||||||
if (rw_flag == WRITING) {
|
if (rw_flag == WRITING) {
|
||||||
if (regular || mode_word == I_DIRECTORY) {
|
if (regular || mode_word == I_DIRECTORY) {
|
||||||
@ -196,6 +238,11 @@ int rw_flag; /* READING or WRITING */
|
|||||||
|
|
||||||
if (rdwt_err != OK) r = rdwt_err; /* check for disk error */
|
if (rdwt_err != OK) r = rdwt_err; /* check for disk error */
|
||||||
if (rdwt_err == END_OF_FILE) r = OK;
|
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 (r == OK) {
|
||||||
if (rw_flag == READING) rip->i_update |= ATIME;
|
if (rw_flag == READING) rip->i_update |= ATIME;
|
||||||
if (rw_flag == WRITING) rip->i_update |= CTIME | MTIME;
|
if (rw_flag == WRITING) rip->i_update |= CTIME | MTIME;
|
||||||
@ -203,7 +250,7 @@ int rw_flag; /* READING or WRITING */
|
|||||||
if (partial_pipe) {
|
if (partial_pipe) {
|
||||||
partial_pipe = 0;
|
partial_pipe = 0;
|
||||||
/* partial write on pipe with */
|
/* partial write on pipe with */
|
||||||
/* O_NONBLOCK, return write count */
|
/* O_NONBLOCK, return write count */
|
||||||
if (!(oflags & O_NONBLOCK)) {
|
if (!(oflags & O_NONBLOCK)) {
|
||||||
fp->fp_cum_io_partial = cum_io;
|
fp->fp_cum_io_partial = cum_io;
|
||||||
suspend(XPIPE); /* partial write on pipe with */
|
suspend(XPIPE); /* partial write on pipe with */
|
||||||
@ -212,16 +259,14 @@ int rw_flag; /* READING or WRITING */
|
|||||||
}
|
}
|
||||||
fp->fp_cum_io_partial = 0;
|
fp->fp_cum_io_partial = 0;
|
||||||
return(cum_io);
|
return(cum_io);
|
||||||
} else {
|
|
||||||
return(r);
|
|
||||||
}
|
}
|
||||||
|
return(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* rw_chunk *
|
* rw_chunk *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
PRIVATE int rw_chunk(rip, position, off, chunk, left, rw_flag, buff, seg, usr, block_size)
|
PRIVATE int rw_chunk(rip, position, off, chunk, left, rw_flag, buff, seg, usr, block_size, completed)
|
||||||
register struct inode *rip; /* pointer to inode for file to be rd/wr */
|
register struct inode *rip; /* pointer to inode for file to be rd/wr */
|
||||||
off_t position; /* position within file to read or write */
|
off_t position; /* position within file to read or write */
|
||||||
unsigned off; /* off within the current block */
|
unsigned off; /* off within the current block */
|
||||||
@ -231,15 +276,19 @@ int rw_flag; /* READING or WRITING */
|
|||||||
char *buff; /* virtual address of the user buffer */
|
char *buff; /* virtual address of the user buffer */
|
||||||
int seg; /* T or D segment in user space */
|
int seg; /* T or D segment in user space */
|
||||||
int usr; /* which user process */
|
int usr; /* which user process */
|
||||||
int block_size;
|
int block_size; /* block size of FS operating on */
|
||||||
|
int *completed; /* number of bytes copied */
|
||||||
{
|
{
|
||||||
/* Read or write (part of) a block. */
|
/* Read or write (part of) a block. */
|
||||||
|
|
||||||
register struct buf *bp;
|
register struct buf *bp;
|
||||||
register int r;
|
register int r = OK;
|
||||||
int n, block_spec;
|
int n, block_spec;
|
||||||
block_t b;
|
block_t b;
|
||||||
dev_t dev;
|
dev_t dev;
|
||||||
|
int entry;
|
||||||
|
|
||||||
|
*completed = 0;
|
||||||
|
|
||||||
block_spec = (rip->i_mode & I_TYPE) == I_BLOCK_SPECIAL;
|
block_spec = (rip->i_mode & I_TYPE) == I_BLOCK_SPECIAL;
|
||||||
if (block_spec) {
|
if (block_spec) {
|
||||||
@ -273,10 +322,15 @@ int block_size;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* In all cases, bp now points to a valid buffer. */
|
/* In all cases, bp now points to a valid buffer. */
|
||||||
|
if(bp == NIL_BUF) {
|
||||||
|
panic("bp not valid in rw_chunk, this can't happen", NO_NUM);
|
||||||
|
}
|
||||||
if (rw_flag == WRITING && chunk != block_size && !block_spec &&
|
if (rw_flag == WRITING && chunk != block_size && !block_spec &&
|
||||||
position >= rip->i_size && off == 0) {
|
position >= rip->i_size && off == 0) {
|
||||||
zero_block(bp);
|
zero_block(bp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
if (rw_flag == READING) {
|
if (rw_flag == READING) {
|
||||||
/* Copy a chunk from the block buffer to user space. */
|
/* Copy a chunk from the block buffer to user space. */
|
||||||
r = sys_vircopy(FS_PROC_NR, D, (phys_bytes) (bp->b_data+off),
|
r = sys_vircopy(FS_PROC_NR, D, (phys_bytes) (bp->b_data+off),
|
||||||
@ -291,9 +345,93 @@ int block_size;
|
|||||||
}
|
}
|
||||||
n = (off + chunk == block_size ? FULL_DATA_BLOCK : PARTIAL_DATA_BLOCK);
|
n = (off + chunk == block_size ? FULL_DATA_BLOCK : PARTIAL_DATA_BLOCK);
|
||||||
put_block(bp, n);
|
put_block(bp, n);
|
||||||
|
#else
|
||||||
|
/* have to copy a buffer now. remember to do it. */
|
||||||
|
if(copy_queue_used < 0 || copy_queue_used > COPY_QUEUE_LEN) {
|
||||||
|
panic("copy_queue_used illegal size", copy_queue_used);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(copy_queue_used == COPY_QUEUE_LEN) {
|
||||||
|
r = rw_chunk_finish(completed);
|
||||||
|
if(copy_queue_used != 0) {
|
||||||
|
panic("copy_queue_used nonzero", copy_queue_used);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = copy_queue_used++;
|
||||||
|
|
||||||
|
if(entry < 0 || entry >= COPY_QUEUE_LEN) {
|
||||||
|
panic("entry illegal slot", entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_queue[entry].bp = bp;
|
||||||
|
copy_queue[entry].op = rw_flag;
|
||||||
|
copy_queue[entry].user_seg = seg;
|
||||||
|
copy_queue[entry].user_proc = usr;
|
||||||
|
copy_queue[entry].fs_offset = (phys_bytes) bp->b_data+off;
|
||||||
|
copy_queue[entry].user_offset = (phys_bytes) buff;
|
||||||
|
copy_queue[entry].chunk = chunk;
|
||||||
|
copy_queue[entry].blocktype = (off + chunk == block_size ? FULL_DATA_BLOCK : PARTIAL_DATA_BLOCK);
|
||||||
|
|
||||||
|
if(rw_flag == WRITING) {
|
||||||
|
bp->b_dirt = DIRTY;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return(r);
|
return(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* rw_chunk_finish *
|
||||||
|
*===========================================================================*/
|
||||||
|
PRIVATE int rw_chunk_finish(int *completed)
|
||||||
|
{
|
||||||
|
int i, total = 0, r;
|
||||||
|
static struct vir_cp_req vir_cp_req[CPVEC_NR];
|
||||||
|
message m;
|
||||||
|
|
||||||
|
*completed = 0;
|
||||||
|
if(copy_queue_used < 1) {
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < copy_queue_used; i++) {
|
||||||
|
struct vir_addr *fs, *user;
|
||||||
|
|
||||||
|
if(copy_queue[i].op == READING) {
|
||||||
|
fs = &vir_cp_req[i].src;
|
||||||
|
user = &vir_cp_req[i].dst;
|
||||||
|
} else {
|
||||||
|
fs = &vir_cp_req[i].dst;
|
||||||
|
user = &vir_cp_req[i].src;
|
||||||
|
}
|
||||||
|
|
||||||
|
vir_cp_req[i].count = copy_queue[i].chunk;
|
||||||
|
fs->proc_nr = FS_PROC_NR;
|
||||||
|
fs->segment = D;
|
||||||
|
fs->offset = copy_queue[i].fs_offset;
|
||||||
|
user->proc_nr = copy_queue[i].user_proc;
|
||||||
|
user->segment = copy_queue[i].user_seg;
|
||||||
|
user->offset = copy_queue[i].user_offset;
|
||||||
|
total += copy_queue[i].chunk;
|
||||||
|
put_block(copy_queue[i].bp, copy_queue[i].blocktype);
|
||||||
|
}
|
||||||
|
|
||||||
|
m.m_type = SYS_VIRVCOPY;
|
||||||
|
m.VCP_VEC_SIZE = i;
|
||||||
|
m.VCP_VEC_ADDR = (char *) vir_cp_req;
|
||||||
|
|
||||||
|
if((r=sendrec(SYSTASK, &m)) < 0) {
|
||||||
|
panic("rw_chunk_finish: virvcopy sendrec failed", r);
|
||||||
|
}
|
||||||
|
|
||||||
|
*completed = total;
|
||||||
|
|
||||||
|
copy_queue_used = 0;
|
||||||
|
|
||||||
|
/* return VIRVCOPY return code */
|
||||||
|
return m.m_type;
|
||||||
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* read_map *
|
* read_map *
|
||||||
|
Loading…
x
Reference in New Issue
Block a user