From a9f55a2e464a5e031e4434275d883ddbeaf1e142 Mon Sep 17 00:00:00 2001 From: Ben Gras Date: Sun, 13 Jan 2013 21:44:38 +0000 Subject: [PATCH] VFS, FSes: add REQ_PEEK request type REQ_PEEK behaves just like REQ_READ except that it does not copy data anywhere, just obtains the blocks from the FS into the cache. To be used by the future mmap implementation. Change-Id: I1b56de304f0a7152b69a72c8962d04258adb44f9 --- include/minix/const.h | 1 + include/minix/vfsif.h | 3 ++- lib/libsffs/table.c | 1 + lib/libvtreefs/table.c | 1 + servers/ext2/read.c | 25 +++++++++++++++++++------ servers/ext2/table.c | 1 + servers/iso9660fs/proto.h | 2 +- servers/iso9660fs/read.c | 18 ++++++++++++++---- servers/iso9660fs/table.c | 1 + servers/mfs/read.c | 28 ++++++++++++++++++++-------- servers/mfs/table.c | 1 + servers/vfs/proto.h | 2 +- servers/vfs/read.c | 29 ++++++++++++++++++++--------- servers/vfs/request.c | 36 ++++++++++++++++++++++++++++++------ servers/vfs/write.c | 4 +++- 15 files changed, 116 insertions(+), 37 deletions(-) diff --git a/include/minix/const.h b/include/minix/const.h index 0afebcf6c..65378668c 100644 --- a/include/minix/const.h +++ b/include/minix/const.h @@ -72,6 +72,7 @@ #define BYTE 0377 /* mask for 8 bits */ #define READING 0 /* copy data to user */ #define WRITING 1 /* copy data from user */ +#define PEEKING 2 /* retrieve FS data without copying */ #define HAVE_SCATTERED_IO 1 /* scattered I/O is now standard */ /* Memory is allocated in clicks. */ diff --git a/include/minix/vfsif.h b/include/minix/vfsif.h index 00d703074..f4aac02cc 100644 --- a/include/minix/vfsif.h +++ b/include/minix/vfsif.h @@ -114,8 +114,9 @@ typedef struct { #define REQ_RDLINK (VFS_BASE + 30) #define REQ_GETDENTS (VFS_BASE + 31) #define REQ_STATVFS (VFS_BASE + 32) +#define REQ_PEEK (VFS_BASE + 33) -#define NREQS 33 +#define NREQS 34 #define IS_VFS_RQ(type) (((type) & ~0xff) == VFS_BASE) diff --git a/lib/libsffs/table.c b/lib/libsffs/table.c index 1744fcbfd..2573fb97d 100644 --- a/lib/libsffs/table.c +++ b/lib/libsffs/table.c @@ -41,6 +41,7 @@ int (*call_vec[])(void) = { no_sys, /* 30 rdlink */ do_getdents, /* 31 getdents */ do_statvfs, /* 32 statvfs */ + no_sys, /* 33 peek */ }; /* This should not fail with "array size is negative": */ diff --git a/lib/libvtreefs/table.c b/lib/libvtreefs/table.c index 4aef223a0..8f73c1098 100644 --- a/lib/libvtreefs/table.c +++ b/lib/libvtreefs/table.c @@ -37,6 +37,7 @@ int (*fs_call_vec[])(void) = { fs_rdlink, /* 30 rdlink */ fs_getdents, /* 31 getdents */ fs_statvfs, /* 32 statvfs */ + no_sys, /* 33 peek */ }; /* This should not fail with "array size is negative": */ diff --git a/servers/ext2/read.c b/servers/ext2/read.c index 3597acf26..50cc875cb 100644 --- a/servers/ext2/read.c +++ b/servers/ext2/read.c @@ -60,8 +60,13 @@ int fs_readwrite(void) if (f_size < 0) f_size = MAX_FILE_POS; } - /* Get the values from the request message */ rw_flag = (fs_m_in.m_type == REQ_READ ? READING : WRITING); + switch(fs_m_in.m_type) { + case REQ_READ: rw_flag = READING; break; + case REQ_WRITE: rw_flag = WRITING; break; + case REQ_PEEK: rw_flag = PEEKING; break; + default: panic("odd request"); + } 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; @@ -206,7 +211,7 @@ u64_t position; /* position within file to read or write */ unsigned off; /* off within the current block */ unsigned int chunk; /* number of bytes to read or write */ unsigned left; /* max number of bytes wanted after position */ -int rw_flag; /* READING or WRITING */ +int rw_flag; /* READING, WRITING or PEEKING */ cp_grant_id_t gid; /* grant */ unsigned buf_off; /* offset in grant */ unsigned int block_size; /* block size of FS operating on */ @@ -214,12 +219,18 @@ int *completed; /* number of bytes copied */ { /* Read or write (part of) a block. */ - register struct buf *bp; + register struct buf *bp = NULL; register int r = OK; int n, block_spec; block_t b; dev_t dev; + /* rw_flag: + * READING: read from FS, copy to user + * WRITING: copy from user, write to FS + * PEEKING: try to get all the blocks into the cache, no copying + */ + *completed = 0; block_spec = (rip->i_mode & I_TYPE) == I_BLOCK_SPECIAL; @@ -244,11 +255,13 @@ int *completed; /* number of bytes copied */ } return r; } else { - /* Writing to a nonexistent block. Create and enter in inode.*/ + /* Writing to or peeking a nonexistent block. + * Create and enter in inode. + */ if ((bp = new_block(rip, (off_t) ex64lo(position))) == NULL) return(err_code); } - } else if (rw_flag == READING) { + } else if (rw_flag == READING || rw_flag == PEEKING) { /* Read and read ahead if convenient. */ bp = rahead(rip, b, position, left); } else { @@ -275,7 +288,7 @@ int *completed; /* number of bytes copied */ /* Copy a chunk from the block buffer to user space. */ r = sys_safecopyto(VFS_PROC_NR, gid, (vir_bytes) buf_off, (vir_bytes) (b_data(bp)+off), (size_t) chunk); - } else { + } else if(rw_flag == WRITING) { /* Copy a chunk from user space to the block buffer. */ r = sys_safecopyfrom(VFS_PROC_NR, gid, (vir_bytes) buf_off, (vir_bytes) (b_data(bp)+off), (size_t) chunk); diff --git a/servers/ext2/table.c b/servers/ext2/table.c index 6c384a3d6..2ebfcbce2 100644 --- a/servers/ext2/table.c +++ b/servers/ext2/table.c @@ -46,4 +46,5 @@ int (*fs_call_vec[])(void) = { fs_rdlink, /* 30 */ fs_getdents, /* 31 */ fs_statvfs, /* 32 */ + fs_readwrite, /* 33 */ }; diff --git a/servers/iso9660fs/proto.h b/servers/iso9660fs/proto.h index dcc92ce1f..f99d57093 100644 --- a/servers/iso9660fs/proto.h +++ b/servers/iso9660fs/proto.h @@ -50,7 +50,7 @@ int fs_bread(void); int fs_getdents(void); int read_chunk(struct dir_record *rip, u64_t position, unsigned off, int chunk, unsigned left, cp_grant_id_t gid, unsigned buf_off, int - block_size, int *completed); + block_size, int *completed, int rw); /* stadir.c */ int fs_stat(void); diff --git a/servers/iso9660fs/read.c b/servers/iso9660fs/read.c index bd097581f..2e6073a6c 100644 --- a/servers/iso9660fs/read.c +++ b/servers/iso9660fs/read.c @@ -19,6 +19,13 @@ int fs_read(void) { unsigned int off, cum_io; int completed; struct dir_record *dir; + int rw; + + switch(fs_m_in.m_type) { + case REQ_READ: rw = READING; + case REQ_PEEK: rw = PEEKING; + default: panic("odd m_type"); + } r = OK; @@ -48,7 +55,7 @@ int fs_read(void) { /* Read or write 'chunk' bytes. */ r = read_chunk(dir, cvul64(position), off, chunk, (unsigned) nrbytes, - gid, cum_io, block_size, &completed); + gid, cum_io, block_size, &completed, rw); if (r != OK) break; /* EOF reached */ if (rdwt_err < 0) break; @@ -106,7 +113,7 @@ int fs_bread(void) /* Read 'chunk' bytes. */ r = read_chunk(dir, position, off, chunk, (unsigned) nrbytes, - gid, cum_io, block_size, &completed); + gid, cum_io, block_size, &completed, READING); if (r != OK) break; /* EOF reached */ if (rdwt_err < 0) break; @@ -280,7 +287,7 @@ int fs_getdents(void) { /*===========================================================================* * read_chunk * *===========================================================================*/ -int read_chunk(dir, position, off, chunk, left, gid, buf_off, block_size, completed) +int read_chunk(dir, position, off, chunk, left, gid, buf_off, block_size, completed, rw) register struct dir_record *dir;/* pointer to inode for file to be rd/wr */ u64_t position; /* position within file to read or write */ unsigned off; /* off within the current block */ @@ -290,6 +297,7 @@ cp_grant_id_t gid; /* grant */ unsigned buf_off; /* offset in grant */ int block_size; /* block size of FS operating on */ int *completed; /* number of bytes copied */ +int rw; /* READING or PEEKING */ { register struct buf *bp; @@ -325,8 +333,10 @@ int *completed; /* number of bytes copied */ panic("bp not valid in rw_chunk; this can't happen"); } - r = sys_safecopyto(VFS_PROC_NR, gid, buf_off, + if(rw == READING) { + r = sys_safecopyto(VFS_PROC_NR, gid, buf_off, (vir_bytes) (b_data(bp)+off), (phys_bytes) chunk); + } put_block(bp); diff --git a/servers/iso9660fs/table.c b/servers/iso9660fs/table.c index 307ff4cda..e6cb5d387 100644 --- a/servers/iso9660fs/table.c +++ b/servers/iso9660fs/table.c @@ -41,4 +41,5 @@ int (*fs_call_vec[])(void) = { no_sys, /* 30: not used */ fs_getdents, /* 31 */ fs_statvfs, /* 32 */ + fs_read /* 33 */ }; diff --git a/servers/mfs/read.c b/servers/mfs/read.c index 408359ad3..3e016e72c 100644 --- a/servers/mfs/read.c +++ b/servers/mfs/read.c @@ -53,7 +53,12 @@ int fs_readwrite(void) } /* Get the values from the request message */ - rw_flag = (fs_m_in.m_type == REQ_READ ? READING : WRITING); + switch(fs_m_in.m_type) { + case REQ_READ: rw_flag = READING; break; + case REQ_WRITE: rw_flag = WRITING; break; + case REQ_PEEK: rw_flag = PEEKING; break; + default: panic("odd request"); + } 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; @@ -215,7 +220,7 @@ u64_t position; /* position within file to read or write */ unsigned off; /* off within the current block */ unsigned int chunk; /* number of bytes to read or write */ unsigned left; /* max number of bytes wanted after position */ -int rw_flag; /* READING or WRITING */ +int rw_flag; /* READING, WRITING or PEEKING */ cp_grant_id_t gid; /* grant */ unsigned buf_off; /* offset in grant */ unsigned int block_size; /* block size of FS operating on */ @@ -223,12 +228,18 @@ int *completed; /* number of bytes copied */ { /* Read or write (part of) a block. */ - register struct buf *bp; + register struct buf *bp = NULL; register int r = OK; int n, block_spec; block_t b; dev_t dev; + /* rw_flag: + * READING: read from FS, copy to user + * WRITING: copy from user, write to FS + * PEEKING: try to get all the blocks into the cache, no copying + */ + *completed = 0; block_spec = (rip->i_mode & I_TYPE) == I_BLOCK_SPECIAL; @@ -253,11 +264,13 @@ int *completed; /* number of bytes copied */ } return r; } else { - /* Writing to a nonexistent block. Create and enter in inode.*/ + /* Writing to or peeking a nonexistent block. + * Create and enter in inode. + */ if ((bp = new_block(rip, (off_t) ex64lo(position))) == NULL) return(err_code); } - } else if (rw_flag == READING) { + } else if (rw_flag == READING || rw_flag == PEEKING) { /* Read and read ahead if convenient. */ bp = rahead(rip, b, position, left); } else { @@ -272,8 +285,7 @@ int *completed; /* number of bytes copied */ } /* In all cases, bp now points to a valid buffer. */ - if (bp == NULL) - panic("bp not valid in rw_chunk; this can't happen"); + assert(bp); if (rw_flag == WRITING && chunk != block_size && !block_spec && (off_t) ex64lo(position) >= rip->i_size && off == 0) { @@ -284,7 +296,7 @@ int *completed; /* number of bytes copied */ /* Copy a chunk from the block buffer to user space. */ r = sys_safecopyto(VFS_PROC_NR, gid, (vir_bytes) buf_off, (vir_bytes) (b_data(bp)+off), (size_t) chunk); - } else { + } else if(rw_flag == WRITING) { /* Copy a chunk from user space to the block buffer. */ r = sys_safecopyfrom(VFS_PROC_NR, gid, (vir_bytes) buf_off, (vir_bytes) (b_data(bp)+off), (size_t) chunk); diff --git a/servers/mfs/table.c b/servers/mfs/table.c index 42fee46ee..d54c91558 100644 --- a/servers/mfs/table.c +++ b/servers/mfs/table.c @@ -44,5 +44,6 @@ int (*fs_call_vec[])(void) = { fs_rdlink, /* 30 */ fs_getdents, /* 31 */ fs_statvfs, /* 32 */ + fs_readwrite, /* 33 */ }; diff --git a/servers/vfs/proto.h b/servers/vfs/proto.h index ee3df9f25..7bfff497a 100644 --- a/servers/vfs/proto.h +++ b/servers/vfs/proto.h @@ -210,7 +210,7 @@ int do_getdents(void); void lock_bsf(void); void unlock_bsf(void); void check_bsf_lock(void); -int do_read_write(int rw_flag); +int do_read_write_peek(int rw_flag, int fd, char *buf, size_t bytes); int read_write(int rw_flag, struct filp *f, char *buffer, size_t nbytes, endpoint_t for_e); int rw_pipe(int rw_flag, endpoint_t usr, struct filp *f, char *buf, diff --git a/servers/vfs/read.c b/servers/vfs/read.c index 90e8c4a72..e85531a19 100644 --- a/servers/vfs/read.c +++ b/servers/vfs/read.c @@ -31,7 +31,8 @@ *===========================================================================*/ int do_read() { - return(do_read_write(READING)); + return(do_read_write_peek(READING, job_m_in.fd, + job_m_in.buffer, (size_t) job_m_in.nbytes)); } @@ -82,24 +83,26 @@ void check_bsf_lock(void) } /*===========================================================================* - * do_read_write * + * do_read_write_peek * *===========================================================================*/ -int do_read_write(rw_flag) -int rw_flag; /* READING or WRITING */ +int do_read_write_peek(int rw_flag, int io_fd, char *io_buf, size_t io_nbytes) { /* Perform read(fd, buffer, nbytes) or write(fd, buffer, nbytes) call. */ struct filp *f; tll_access_t locktype; int r; + int ro = 1; - scratch(fp).file.fd_nr = job_m_in.fd; - scratch(fp).io.io_buffer = job_m_in.buffer; - scratch(fp).io.io_nbytes = (size_t) job_m_in.nbytes; + if(rw_flag == WRITING) ro = 0; - locktype = (rw_flag == READING) ? VNODE_READ : VNODE_WRITE; + scratch(fp).file.fd_nr = io_fd; + scratch(fp).io.io_buffer = io_buf; + scratch(fp).io.io_nbytes = io_nbytes; + + locktype = ro ? VNODE_READ : VNODE_WRITE; if ((f = get_filp(scratch(fp).file.fd_nr, locktype)) == NULL) return(err_code); - if (((f->filp_mode) & (rw_flag == READING ? R_BIT : W_BIT)) == 0) { + if (((f->filp_mode) & (ro ? R_BIT : W_BIT)) == 0) { unlock_filp(f); return(f->filp_mode == FILP_CLOSED ? EIO : EBADF); } @@ -131,6 +134,8 @@ int read_write(int rw_flag, struct filp *f, char *buf, size_t size, r = OK; cum_io = 0; + assert(rw_flag == READING || rw_flag == WRITING || rw_flag == PEEKING); + if (size > SSIZE_MAX) return(EINVAL); op = (rw_flag == READING ? VFS_DEV_READ : VFS_DEV_WRITE); @@ -139,10 +144,14 @@ int read_write(int rw_flag, struct filp *f, char *buf, size_t size, if (fp->fp_cum_io_partial != 0) { panic("VFS: read_write: fp_cum_io_partial not clear"); } + if(rw_flag == PEEKING) return EINVAL; r = rw_pipe(rw_flag, for_e, f, buf, size); } else if (S_ISCHR(vp->v_mode)) { /* Character special files. */ dev_t dev; int suspend_reopen; + int op = (rw_flag == READING ? VFS_DEV_READ : VFS_DEV_WRITE); + + if(rw_flag == PEEKING) return EINVAL; if (vp->v_sdev == NO_DEV) panic("VFS: read_write tries to access char dev NO_DEV"); @@ -161,6 +170,8 @@ int read_write(int rw_flag, struct filp *f, char *buf, size_t size, if (vp->v_sdev == NO_DEV) panic("VFS: read_write tries to access block dev NO_DEV"); + if(rw_flag == PEEKING) return EINVAL; + lock_bsf(); r = req_breadwrite(vp->v_bfs_e, for_e, vp->v_sdev, position, size, diff --git a/servers/vfs/request.c b/servers/vfs/request.c index de25c4c41..443ba6905 100644 --- a/servers/vfs/request.c +++ b/servers/vfs/request.c @@ -762,19 +762,43 @@ u64_t *new_posp; unsigned int *cum_iop; { int r; - cp_grant_id_t grant_id; + cp_grant_id_t grant_id = -1; message m; + int type = -1; + int grantflag = -1; + + /* rw_flag: + * READING: do i/o from FS, copy into userspace + * WRITING: do i/o from userspace, copy into FS + * PEEKING: do i/o in FS, just get the blocks into the cache, no copy + */ if (ex64hi(pos) != 0) panic("req_readwrite: pos too large"); - grant_id = cpf_grant_magic(fs_e, user_e, (vir_bytes) user_addr, num_of_bytes, - (rw_flag==READING ? CPF_WRITE:CPF_READ)); - if (grant_id == -1) - panic("req_readwrite: cpf_grant_magic failed"); + assert(rw_flag == READING || rw_flag == WRITING || rw_flag == PEEKING); + + switch(rw_flag) { + case READING: + type = REQ_READ; + grantflag = CPF_WRITE; + /* fallthrough */ + case WRITING: + if(type < 0) { type = REQ_WRITE; grantflag = CPF_READ; } + grant_id = cpf_grant_magic(fs_e, user_e, (vir_bytes) user_addr, + num_of_bytes, grantflag); + if (grant_id == -1) + panic("req_readwrite: cpf_grant_magic failed"); + break; + case PEEKING: + type = REQ_PEEK; + break; + default: + panic("odd rw_flag"); + } /* Fill in request message */ - m.m_type = rw_flag == READING ? REQ_READ : REQ_WRITE; + m.m_type = type; m.REQ_INODE_NR = inode_nr; m.REQ_GRANT = grant_id; m.REQ_SEEK_POS_LO = ex64lo(pos); diff --git a/servers/vfs/write.c b/servers/vfs/write.c index 80975b150..6d9e939e4 100644 --- a/servers/vfs/write.c +++ b/servers/vfs/write.c @@ -7,6 +7,7 @@ #include "fs.h" #include "file.h" +#include "param.h" /*===========================================================================* @@ -15,5 +16,6 @@ int do_write() { /* Perform the write(fd, buffer, nbytes) system call. */ - return(do_read_write(WRITING)); + return(do_read_write_peek(WRITING, job_m_in.fd, + job_m_in.buffer, (size_t) job_m_in.nbytes)); }