diff --git a/servers/mfs/link.c b/servers/mfs/link.c index d148d5214..621d3c432 100644 --- a/servers/mfs/link.c +++ b/servers/mfs/link.c @@ -6,6 +6,7 @@ #include "inode.h" #include "super.h" #include +#include #define SAME 1000 @@ -172,7 +173,6 @@ int fs_unlink() *===========================================================================*/ int fs_rdlink() { - block_t b; /* block containing link text */ struct buf *bp; /* buffer containing link text */ register struct inode *rip; /* target inode */ register int r; /* return value */ @@ -186,14 +186,13 @@ int fs_rdlink() if(!S_ISLNK(rip->i_mode)) r = EACCES; - else if ((b = read_map(rip, (off_t) 0)) == NO_BLOCK) - r = EIO; else { + if(!(bp = get_block_map(rip, 0))) + return EIO; /* Passed all checks */ /* We can safely cast to unsigned, because copylen is guaranteed to be below max file size */ copylen = min( copylen, (unsigned) rip->i_size); - bp = get_block(rip->i_dev, b, NORMAL); r = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT, (vir_bytes) 0, (vir_bytes) b_data(bp), (size_t) copylen); @@ -677,7 +676,6 @@ off_t len; { /* Zero an arbitrary byte range in a zone, possibly spanning multiple blocks. */ - block_t b; struct buf *bp; off_t offset; unsigned short block_size; @@ -686,10 +684,10 @@ off_t len; block_size = rip->i_sp->s_block_size; if(!len) return; /* no zeroing to be done. */ - if( (b = read_map(rip, pos)) == NO_BLOCK) return; + while (len > 0) { - if( (bp = get_block(rip->i_dev, b, NORMAL)) == NULL) - panic("zerozone_range: no block"); + if( (bp = get_block_map(rip, rounddown(pos, block_size))) == NULL) + return; offset = pos % block_size; bytes = block_size - offset; if (bytes > (size_t) len) @@ -700,7 +698,6 @@ off_t len; pos += bytes; len -= bytes; - b++; } } diff --git a/servers/mfs/path.c b/servers/mfs/path.c index f558c89c4..1e876aade 100644 --- a/servers/mfs/path.c +++ b/servers/mfs/path.c @@ -287,16 +287,13 @@ char *suffix; /* current remaining path. Has to point in the * new pathname. */ - block_t blink; /* block containing link text */ size_t llen; /* length of link */ size_t slen; /* length of suffix */ struct buf *bp; /* buffer containing link text */ char *sp; /* start of link text */ - if ((blink = read_map(rip, (off_t) 0)) == NO_BLOCK) + if(!(bp = get_block_map(rip, 0))) return(EIO); - - bp = get_block(rip->i_dev, blink, NORMAL); llen = (size_t) rip->i_size; sp = b_data(bp); slen = strlen(suffix); @@ -485,7 +482,6 @@ int check_permissions; /* check permissions when flag is !IS_EMPTY */ mode_t bits; off_t pos; unsigned new_slots, old_slots; - block_t b; struct super_block *sp; int extended = 0; @@ -524,12 +520,14 @@ int check_permissions; /* check permissions when flag is !IS_EMPTY */ } for (; pos < ldir_ptr->i_size; pos += ldir_ptr->i_sp->s_block_size) { - b = read_map(ldir_ptr, pos); /* get block number */ + assert(ldir_ptr->i_dev != NO_DEV); /* Since directories don't have holes, 'b' cannot be NO_BLOCK. */ - bp = get_block(ldir_ptr->i_dev, b, NORMAL); /* get a dir block */ + bp = get_block_map(ldir_ptr, pos); + assert(ldir_ptr->i_dev != NO_DEV); assert(bp != NULL); + assert(lmfs_dev(bp) != NO_DEV); /* Search a directory block. */ for (dp = &b_dir(bp)[0]; @@ -573,6 +571,7 @@ int check_permissions; /* check permissions when flag is !IS_EMPTY */ *numb = (ino_t) conv4(sp->s_native, (int) dp->mfs_d_ino); } + assert(lmfs_dev(bp) != NO_DEV); put_block(bp, DIRECTORY_BLOCK); return(r); } @@ -586,6 +585,7 @@ int check_permissions; /* check permissions when flag is !IS_EMPTY */ /* The whole block has been searched or ENTER has a free slot. */ if (e_hit) break; /* e_hit set if ENTER can be performed now */ + assert(lmfs_dev(bp) != NO_DEV); put_block(bp, DIRECTORY_BLOCK); /* otherwise, continue searching dir */ } diff --git a/servers/mfs/proto.h b/servers/mfs/proto.h index 403a39780..e7634f615 100644 --- a/servers/mfs/proto.h +++ b/servers/mfs/proto.h @@ -73,7 +73,8 @@ int read_only(struct inode *ip); int fs_breadwrite(void); int fs_readwrite(void); void read_ahead(void); -block_t read_map(struct inode *rip, off_t pos); +block_t read_map(struct inode *rip, off_t pos, int opportunistic); +struct buf *get_block_map(register struct inode *rip, u64_t position); zone_t rd_indir(struct buf *bp, int index); /* stadir.c */ diff --git a/servers/mfs/read.c b/servers/mfs/read.c index 3e016e72c..0146f5bed 100644 --- a/servers/mfs/read.c +++ b/servers/mfs/read.c @@ -8,6 +8,7 @@ #include "inode.h" #include "super.h" #include +#include #include @@ -62,7 +63,7 @@ int fs_readwrite(void) 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; - + lmfs_reset_rdwt_err(); /* If this is file i/o, check we can write */ @@ -233,6 +234,8 @@ int *completed; /* number of bytes copied */ int n, block_spec; block_t b; dev_t dev; + ino_t ino = VMC_NO_INODE; + u64_t ino_off = rounddown(position, block_size); /* rw_flag: * READING: read from FS, copy to user @@ -250,8 +253,10 @@ int *completed; /* number of bytes copied */ } else { if (ex64hi(position) != 0) panic("rw_chunk: position too high"); - b = read_map(rip, (off_t) ex64lo(position)); + b = read_map(rip, (off_t) ex64lo(position), 0); dev = rip->i_dev; + ino = rip->i_num; + assert(ino != VMC_NO_INODE); } if (!block_spec && b == NO_BLOCK) { @@ -281,7 +286,14 @@ int *completed; /* number of bytes copied */ n = (chunk == block_size ? NO_READ : NORMAL); if (!block_spec && off == 0 && (off_t) ex64lo(position) >= rip->i_size) n = NO_READ; - bp = get_block(dev, b, n); + if(block_spec) { + assert(ino == VMC_NO_INODE); + bp = get_block(dev, b, n); + } else { + assert(ino != VMC_NO_INODE); + assert(!(ino_off % block_size)); + bp = lmfs_get_block_ino(dev, b, n, ino, ino_off); + } } /* In all cases, bp now points to a valid buffer. */ @@ -313,9 +325,10 @@ int *completed; /* number of bytes copied */ /*===========================================================================* * read_map * *===========================================================================*/ -block_t read_map(rip, position) +block_t read_map(rip, position, opportunistic) register struct inode *rip; /* ptr to inode to map from */ off_t position; /* position in file whose blk wanted */ +int opportunistic; /* if nonzero, only use cache for metadata */ { /* Given an inode and a position within the corresponding file, locate the * block (not zone) number in which that position is to be found and return it. @@ -327,7 +340,10 @@ off_t position; /* position in file whose blk wanted */ unsigned int dzones, nr_indirects; block_t b; unsigned long excess, zone, block_pos; - + int iomode = NORMAL; + + if(opportunistic) iomode = PREFETCH; + scale = rip->i_sp->s_log_zone_size; /* for block-zone conversion */ block_pos = position/rip->i_sp->s_block_size; /* relative blk # in file */ zone = block_pos >> scale; /* position's zone */ @@ -359,7 +375,11 @@ off_t position; /* position in file whose blk wanted */ index = (int) (excess/nr_indirects); if ((unsigned int) index > rip->i_nindirs) return(NO_BLOCK); /* Can't go beyond double indirects */ - bp = get_block(rip->i_dev, b, NORMAL); /* get double indirect block */ + bp = get_block(rip->i_dev, b, iomode); /* get double indirect block */ + if(opportunistic && lmfs_dev(bp) == NO_DEV) { + put_block(bp, INDIRECT_BLOCK); + return NO_BLOCK; + } ASSERT(lmfs_dev(bp) != NO_DEV); ASSERT(lmfs_dev(bp) == rip->i_dev); z = rd_indir(bp, index); /* z= zone for single*/ @@ -370,7 +390,11 @@ off_t position; /* position in file whose blk wanted */ /* 'z' is zone num for single indirect block; 'excess' is index into it. */ if (z == NO_ZONE) return(NO_BLOCK); b = (block_t) z << scale; /* b is blk # for single ind */ - bp = get_block(rip->i_dev, b, NORMAL); /* get single indirect block */ + bp = get_block(rip->i_dev, b, iomode); /* get single indirect block */ + if(opportunistic && lmfs_dev(bp) == NO_DEV) { + put_block(bp, INDIRECT_BLOCK); + return NO_BLOCK; + } z = rd_indir(bp, (int) excess); /* get block pointed to */ put_block(bp, INDIRECT_BLOCK); /* release single indir blk */ if (z == NO_ZONE) return(NO_BLOCK); @@ -378,6 +402,16 @@ off_t position; /* position in file whose blk wanted */ return(b); } +struct buf *get_block_map(register struct inode *rip, u64_t position) +{ + block_t b = read_map(rip, position, 0); /* get block number */ + int block_size = get_block_size(rip->i_dev); + if(b == NO_BLOCK) + return NULL; + position = rounddown(position, block_size); + assert(rip->i_num != VMC_NO_INODE); + return lmfs_get_block_ino(rip->i_dev, b, NORMAL, rip->i_num, position); +} /*===========================================================================* * rd_indir * @@ -442,6 +476,7 @@ unsigned bytes_ahead; /* bytes beyond position for immediate use */ struct buf *bp; static unsigned int readqsize = 0; static struct buf **read_q; + u64_t position_running; if(readqsize != nr_bufs) { if(readqsize > 0) { @@ -458,11 +493,24 @@ unsigned bytes_ahead; /* bytes beyond position for immediate use */ dev = (dev_t) rip->i_zone[0]; else dev = rip->i_dev; + + assert(dev != NO_DEV); block_size = get_block_size(dev); block = baseblock; - bp = get_block(dev, block, PREFETCH); + + fragment = position % block_size; + position -= fragment; + position_running = position; + bytes_ahead += fragment; + blocks_ahead = (bytes_ahead + block_size - 1) / block_size; + + if(block_spec) + bp = get_block(dev, block, PREFETCH); + else + bp = lmfs_get_block_ino(dev, block, PREFETCH, rip->i_num, position); + assert(bp != NULL); if (lmfs_dev(bp) != NO_DEV) return(bp); @@ -486,12 +534,6 @@ unsigned bytes_ahead; /* bytes beyond position for immediate use */ * indirect blocks (but don't call read_map!). */ - fragment = rem64u(position, block_size); - position = sub64u(position, fragment); - bytes_ahead += fragment; - - blocks_ahead = (bytes_ahead + block_size - 1) / block_size; - if (block_spec && rip->i_size == 0) { blocks_left = (block_t) NR_IOREQS; } else { @@ -524,6 +566,7 @@ unsigned bytes_ahead; /* bytes beyond position for immediate use */ /* Acquire block buffers. */ for (;;) { + block_t thisblock; read_q[read_q_size++] = bp; if (--blocks_ahead == 0) break; @@ -532,8 +575,14 @@ unsigned bytes_ahead; /* bytes beyond position for immediate use */ if (lmfs_bufs_in_use() >= nr_bufs - 4) break; block++; + position_running += block_size; - bp = get_block(dev, block, PREFETCH); + if(!block_spec && + (thisblock = read_map(rip, (off_t) ex64lo(position_running), 1)) != NO_BLOCK) { + bp = lmfs_get_block_ino(dev, thisblock, PREFETCH, rip->i_num, position_running); + } else { + bp = get_block(dev, block, PREFETCH); + } if (lmfs_dev(bp) != NO_DEV) { /* Oops, block already in the cache, get out. */ put_block(bp, FULL_DATA_BLOCK); @@ -541,7 +590,10 @@ unsigned bytes_ahead; /* bytes beyond position for immediate use */ } } lmfs_rw_scattered(dev, read_q, read_q_size, READING); - return(get_block(dev, baseblock, NORMAL)); + + if(block_spec) + return get_block(dev, baseblock, NORMAL); + return(lmfs_get_block_ino(dev, baseblock, NORMAL, rip->i_num, position)); } @@ -557,7 +609,6 @@ int fs_getdents(void) int o, r, done; unsigned int block_size, len, reclen; ino_t ino; - block_t b; cp_grant_id_t gid; size_t size, tmpbuf_off, userbuf_off; off_t pos, off, block_pos, new_pos, ent_pos; @@ -592,11 +643,8 @@ int fs_getdents(void) new_pos = rip->i_size; for(; block_pos < rip->i_size; block_pos += block_size) { - b = read_map(rip, block_pos); /* get block number */ - - /* Since directories don't have holes, 'b' cannot be NO_BLOCK. */ - bp = get_block(rip->i_dev, b, NORMAL); /* get a dir block */ - + /* Since directories don't have holes, 'bp' cannot be NULL. */ + bp = get_block_map(rip, block_pos); /* get a dir block */ assert(bp != NULL); /* Search a directory block. */ diff --git a/servers/mfs/table.c b/servers/mfs/table.c index 8d19c3b8a..d54c91558 100644 --- a/servers/mfs/table.c +++ b/servers/mfs/table.c @@ -44,6 +44,6 @@ int (*fs_call_vec[])(void) = { fs_rdlink, /* 30 */ fs_getdents, /* 31 */ fs_statvfs, /* 32 */ - no_sys, /* 33 */ /* peek not supported */ + fs_readwrite, /* 33 */ }; diff --git a/servers/mfs/write.c b/servers/mfs/write.c index 1e7e5729f..0dbacbc3b 100644 --- a/servers/mfs/write.c +++ b/servers/mfs/write.c @@ -11,6 +11,8 @@ #include "fs.h" #include +#include +#include #include "buf.h" #include "inode.h" #include "super.h" @@ -99,7 +101,8 @@ int op; /* special actions */ z1 = NO_ZONE; } else { b = (block_t) z << scale; - bp_dindir = get_block(rip->i_dev, b, (new_dbl?NO_READ:NORMAL)); + bp_dindir = get_block(rip->i_dev, b, + (new_dbl?NO_READ:NORMAL)); if (new_dbl) zero_block(bp_dindir); z1 = rd_indir(bp_dindir, ind_ex); } @@ -239,31 +242,12 @@ int flag; /* 1 if called by new_block, 0 otherwise */ * a byte in the first block to be zeroed. Clearzone() is called from * fs_readwrite(), truncate_inode(), and new_block(). */ - - struct buf *bp; - block_t b, blo, bhi; - off_t next; - int scale, zone_size; + int scale; /* If the block size and zone size are the same, clear_zone() not needed. */ scale = rip->i_sp->s_log_zone_size; - if (scale == 0) return; - - zone_size = rip->i_sp->s_block_size << scale; - if (flag == 1) pos = (off_t) ((pos/zone_size) * zone_size); - next = pos + rip->i_sp->s_block_size - 1; - - /* If 'pos' is in the last block of a zone, do not clear the zone. */ - if (next/zone_size != pos/zone_size) return; - if ( (blo = read_map(rip, next)) == NO_BLOCK) return; - bhi = (block_t) ( ((blo>>scale)+1) << scale) - 1; - - /* Clear all the blocks between 'blo' and 'bhi'. */ - for (b = blo; b <= bhi; b++) { - bp = get_block(rip->i_dev, b, NO_READ); - zero_block(bp); - put_block(bp, FULL_DATA_BLOCK); - } + assert(scale == 0); + return; } @@ -286,7 +270,7 @@ off_t position; /* file pointer */ int scale, r; /* Is another block available in the current zone? */ - if ( (b = read_map(rip, position)) == NO_BLOCK) { + if ( (b = read_map(rip, position, 0)) == NO_BLOCK) { if (rip->i_zsearch == NO_ZONE) { /* First search for this file. Start looking from * the file's first data zone to prevent fragmentation @@ -316,7 +300,8 @@ off_t position; /* file pointer */ b = base_block + (block_t)((position % zone_size)/rip->i_sp->s_block_size); } - bp = get_block(rip->i_dev, b, NO_READ); + bp = lmfs_get_block_ino(rip->i_dev, b, NO_READ, rip->i_num, + rounddown(position, rip->i_sp->s_block_size)); zero_block(bp); return(bp); }