static int sfs_dirent_read_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, int slot, struct sfs_disk_entry *entry) { assert(_SFS_INODE_GET_TYPE(sin->din) == SFS_TYPE_DIR && (slot >= 0 && slot < sin->din->blocks)); int ret; uint32_t ino; if ((ret = sfs_bmap_load_nolock(sfs, sin, slot, &ino)) != 0) { return ret; } assert(sfs_block_inuse(sfs, ino)); if ((ret = sfs_rbuf(sfs, entry, sizeof(struct sfs_disk_entry), ino, 0)) != 0) { return ret; } entry->name[SFS_MAX_FNAME_LEN] = '\0'; return 0; }
/* * sfs_truncfile : reszie the file with new length */ static int sfs_truncfile(struct inode *node, off_t len) { if (len < 0 || len > SFS_MAX_FILE_SIZE) { return -E_INVAL; } struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs); struct sfs_inode *sin = vop_info(node, sfs_inode); struct sfs_disk_inode *din = sin->din; int ret = 0; //new number of disk blocks of file uint32_t nblks, tblks = ROUNDUP_DIV(len, SFS_BLKSIZE); if (din->size == len) { assert(tblks == din->blocks); return 0; } lock_sin(sin); // old number of disk blocks of file nblks = din->blocks; if (nblks < tblks) { // try to enlarge the file size by add new disk block at the end of file while (nblks != tblks) { if ((ret = sfs_bmap_load_nolock(sfs, sin, nblks, NULL)) != 0) { goto out_unlock; } nblks ++; } } else if (tblks < nblks) { // try to reduce the file size while (tblks != nblks) { if ((ret = sfs_bmap_truncate_nolock(sfs, sin)) != 0) { goto out_unlock; } nblks --; } } assert(din->blocks == tblks); din->size = len; sin->dirty = 1; out_unlock: unlock_sin(sin); return ret; }
/* * sfs_dirent_read_nolock - read the file entry from disk block which contains this entry * @sfs: sfs file system * @sin: sfs inode in memory * @slot: the index of file entry * @entry: file entry */ static int sfs_dirent_read_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, int slot, struct sfs_disk_entry *entry) { assert(sin->din->type == SFS_TYPE_DIR && (slot >= 0 && slot < sin->din->blocks)); int ret; uint32_t ino; // according to the DIR's inode and the slot of file entry, find the index of disk block which contains this file entry if ((ret = sfs_bmap_load_nolock(sfs, sin, slot, &ino)) != 0) { return ret; } assert(sfs_block_inuse(sfs, ino)); // read the content of file entry in the disk block if ((ret = sfs_rbuf(sfs, entry, sizeof(struct sfs_disk_entry), ino, 0)) != 0) { return ret; } entry->name[SFS_MAX_FNAME_LEN] = '\0'; return 0; }
static int sfs_truncfile(struct inode *node, off_t len) { if (len < 0 || len > SFS_MAX_FILE_SIZE) { return -E_INVAL; } struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs); struct sfs_inode *sin = vop_info(node, sfs_inode); struct sfs_disk_inode *din = sin->din; assert(din->type != SFS_TYPE_DIR); int ret = 0; uint32_t nblks, tblks = ROUNDUP_DIV(len, SFS_BLKSIZE); if (din->fileinfo.size == len) { assert(tblks == din->blocks); return 0; } if ((ret = trylock_sin(sin)) != 0) { return ret; } nblks = din->blocks; if (nblks < tblks) { while (nblks != tblks) { if ((ret = sfs_bmap_load_nolock(sfs, sin, nblks, NULL)) != 0) { goto out_unlock; } nblks ++; } } else if (tblks < nblks) { while (tblks != nblks) { if ((ret = sfs_bmap_truncate_nolock(sfs, sin)) != 0) { goto out_unlock; } nblks --; } } assert(din->blocks == tblks); din->fileinfo.size = len; sin->dirty = 1; out_unlock: unlock_sin(sin); return ret; }
static int sfs_dirent_read_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, int slot, struct sfs_disk_entry *entry) { assert(_SFS_INODE_GET_TYPE(sin->din) == SFS_TYPE_DIR && (slot >= 0 && slot < sin->din->blocks)); // kprintf("%s\n", __func__); int ret; uint32_t ino; if ((ret = sfs_bmap_load_nolock(sfs, sin, slot, &ino)) != 0) { return ret; } // kprintf("%s and ino is %d\n", __func__, ino); // if (ino == -1) { // kprintf("%d\n", __LINE__); // } assert(sfs_block_inuse(sfs, ino)); if ((ret = sfs_rbuf(sfs, entry, sizeof(struct sfs_disk_entry), ino, 0)) != 0) { return ret; } entry->name[SFS_MAX_FNAME_LEN] = '\0'; // kprintf("%s finish inner\n", __func__); return 0; }
static int sfs_dirent_write_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, int slot, uint32_t ino, const char *name) { assert(sin->din->type == SFS_TYPE_DIR && (slot >= 0 && slot <= sin->din->blocks)); struct sfs_disk_entry *entry; if ((entry = kmalloc(sizeof(struct sfs_disk_entry))) == NULL) { return -E_NO_MEM; } memset(entry, 0, sizeof(struct sfs_disk_entry)); if (ino != 0) { assert(strlen(name) <= SFS_MAX_FNAME_LEN); entry->ino = ino, strcpy(entry->name, name); } int ret; if ((ret = sfs_bmap_load_nolock(sfs, sin, slot, &ino)) != 0) { goto out; } assert(sfs_block_inuse(sfs, ino)); ret = sfs_wbuf(sfs, entry, sizeof(struct sfs_disk_entry), ino, 0); out: kfree(entry); return ret; }
/* * sfs_io_nolock - Rd/Wr a file contentfrom offset position to offset+ length disk blocks<-->buffer (in memroy) * @sfs: sfs file system * @sin: sfs inode in memory * @buf: the buffer Rd/Wr * @offset: the offset of file * @alenp: the length need to read (is a pointer). and will RETURN the really Rd/Wr lenght * @write: BOOL, 0 read, 1 write */ static int sfs_io_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, void *buf, off_t offset, size_t *alenp, bool write) { struct sfs_disk_inode *din = sin->din; assert(din->type != SFS_TYPE_DIR); off_t endpos = offset + *alenp, blkoff; *alenp = 0; // calculate the Rd/Wr end position if (offset < 0 || offset >= SFS_MAX_FILE_SIZE || offset > endpos) { return -E_INVAL; } if (offset == endpos) { return 0; } if (endpos > SFS_MAX_FILE_SIZE) { endpos = SFS_MAX_FILE_SIZE; } if (!write) { if (offset >= din->size) { return 0; } if (endpos > din->size) { endpos = din->size; } } int (*sfs_buf_op)(struct sfs_fs *sfs, void *buf, size_t len, uint32_t blkno, off_t offset); int (*sfs_block_op)(struct sfs_fs *sfs, void *buf, uint32_t blkno, uint32_t nblks); if (write) { sfs_buf_op = sfs_wbuf, sfs_block_op = sfs_wblock; } else { sfs_buf_op = sfs_rbuf, sfs_block_op = sfs_rblock; } int ret = 0; size_t size, alen = 0; uint32_t ino; uint32_t blkno = offset / SFS_BLKSIZE; // The NO. of Rd/Wr begin block uint32_t nblks = endpos / SFS_BLKSIZE - blkno; // The size of Rd/Wr blocks //LAB8:EXERCISE1 YOUR CODE HINT: call sfs_bmap_load_nolock, sfs_rbuf, sfs_rblock,etc. read different kind of blocks in file /* * (1) If offset isn't aligned with the first block, Rd/Wr some content from offset to the end of the first block * NOTICE: useful function: sfs_bmap_load_nolock, sfs_buf_op * Rd/Wr size = (nblks != 0) ? (SFS_BLKSIZE - blkoff) : (endpos - offset) * (2) Rd/Wr aligned blocks * NOTICE: useful function: sfs_bmap_load_nolock, sfs_block_op * (3) If end position isn't aligned with the last block, Rd/Wr some content from begin to the (endpos % SFS_BLKSIZE) of the last block * NOTICE: useful function: sfs_bmap_load_nolock, sfs_buf_op */ if ((blkoff = offset % SFS_BLKSIZE) != 0) { size = (nblks != 0) ? (SFS_BLKSIZE - blkoff) : (endpos - offset); if ((ret = sfs_bmap_load_nolock(sfs, sin, blkno, &ino)) != 0) { goto out; } if ((ret = sfs_buf_op(sfs, buf, size, ino, blkoff)) != 0) { goto out; } alen += size; if (nblks == 0) { goto out; } buf += size, blkno ++, nblks --; } size = SFS_BLKSIZE; while (nblks != 0) { if ((ret = sfs_bmap_load_nolock(sfs, sin, blkno, &ino)) != 0) { goto out; } if ((ret = sfs_block_op(sfs, buf, ino, 1)) != 0) { goto out; } alen += size, buf += size, blkno ++, nblks --; } if ((size = endpos % SFS_BLKSIZE) != 0) { if ((ret = sfs_bmap_load_nolock(sfs, sin, blkno, &ino)) != 0) { goto out; } if ((ret = sfs_buf_op(sfs, buf, size, ino, 0)) != 0) { goto out; } alen += size; } out: *alenp = alen; if (offset + alen > sin->din->size) { sin->din->size = offset + alen; sin->dirty = 1; } return ret; }
static int sfs_io_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, void *buf, off_t offset, size_t *alenp, bool write) { struct sfs_disk_inode *din = sin->din; assert(_SFS_INODE_GET_TYPE(din) != SFS_TYPE_DIR); off_t endpos = offset + *alenp, blkoff; *alenp = 0; if (offset < 0 || offset >= SFS_MAX_FILE_SIZE || offset > endpos) { return -E_INVAL; } if (offset == endpos) { return 0; } if (endpos > SFS_MAX_FILE_SIZE) { endpos = SFS_MAX_FILE_SIZE; } if (!write) { if (offset >= din->size) { return 0; } if (endpos > din->size) { endpos = din->size; } } int (*sfs_buf_op)(struct sfs_fs *sfs, void *buf, size_t len, uint32_t blkno, off_t offset); int (*sfs_block_op)(struct sfs_fs *sfs, void *buf, uint32_t blkno, uint32_t nblks); if (write) { sfs_buf_op = sfs_wbuf, sfs_block_op = sfs_wblock; } else { sfs_buf_op = sfs_rbuf, sfs_block_op = sfs_rblock; } int ret = 0; size_t size, alen = 0; uint32_t ino; uint32_t blkno = offset / SFS_BLKSIZE; uint32_t nblks = endpos / SFS_BLKSIZE - blkno; //LAB8:EXERCISE1 2009010989 HINT: call sfs_bmap_load_nolock, sfs_rbuf, sfs_rblock,etc. read different kind of blocks in file if((blkoff = offset % SFS_BLKSIZE)!= 0) { if(nblks){ size = SFS_BLKSIZE - blkoff; }else{ size = endpos - offset; } if ((ret = sfs_bmap_load_nolock(sfs, sin, blkno, &ino)) != 0) { goto out; } if ((ret = sfs_buf_op(sfs, buf, size, ino, blkoff)) != 0) { goto out; } // add if (write) { // kprintf("write secno %d\n", ino); int secno = ram2block(ino); swapper_block_changed(secno); swapper_block_late_sync(secno); } alen += size; if (nblks == 0) { goto out; } buf += size, blkno ++, nblks --; } size = SFS_BLKSIZE; while(nblks != 0){ if((ret = sfs_bmap_load_nolock(sfs, sin, blkno, &ino)) != 0) { goto out; } if((ret = sfs_block_op(sfs, buf, ino, 1)) != 0) { goto out; } alen += size, buf += size, blkno ++, nblks --; // add if (write) { // kprintf("write secno %d\n", ino); int secno = ram2block(ino); swapper_block_changed(secno); swapper_block_late_sync(secno); } } if((size = endpos % SFS_BLKSIZE) != 0) { if ((ret = sfs_bmap_load_nolock(sfs, sin, blkno, &ino)) != 0) { goto out; } if ((ret = sfs_buf_op(sfs, buf, size, ino, 0)) != 0) { goto out; } alen += size; // add if (write) { // kprintf("write secno %d\n", ino); int secno = ram2block(ino); swapper_block_changed(secno); swapper_block_late_sync(secno); } } out: *alenp = alen; if (offset + alen > sin->din->size) { sin->din->size = offset + alen; sin->dirty = 1; } return ret; }
/* * sfs_io_nolock - Rd/Wr a file contentfrom offset position to offset+ length disk blocks<-->buffer (in memroy) * @sfs: sfs file system * @sin: sfs inode in memory * @buf: the buffer Rd/Wr * @offset: the offset of file * @alenp: the length need to read (is a pointer). and will RETURN the really Rd/Wr lenght * @write: BOOL, 0 read, 1 write */ static int sfs_io_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, void *buf, off_t offset, size_t *alenp, bool write) { struct sfs_disk_inode *din = sin->din; assert(din->type != SFS_TYPE_DIR); off_t endpos = offset + *alenp, blkoff; *alenp = 0; // calculate the Rd/Wr end position if (offset < 0 || offset >= SFS_MAX_FILE_SIZE || offset > endpos) { return -E_INVAL; } if (offset == endpos) { return 0; } if (endpos > SFS_MAX_FILE_SIZE) { endpos = SFS_MAX_FILE_SIZE; } if (!write) { if (offset >= din->size) { return 0; } if (endpos > din->size) { endpos = din->size; } } int (*sfs_buf_op)(struct sfs_fs *sfs, void *buf, size_t len, uint32_t blkno, off_t offset); int (*sfs_block_op)(struct sfs_fs *sfs, void *buf, uint32_t blkno, uint32_t nblks); if (write) { sfs_buf_op = sfs_wbuf, sfs_block_op = sfs_wblock; } else { sfs_buf_op = sfs_rbuf, sfs_block_op = sfs_rblock; } int ret = 0; size_t size, alen = 0; uint32_t ino; uint32_t blkno = offset / SFS_BLKSIZE; // The NO. of Rd/Wr begin block uint32_t nblks = endpos / SFS_BLKSIZE - blkno; // The size of Rd/Wr blocks //LAB8:EXERCISE1 2012010449 HINT: call sfs_bmap_load_nolock, sfs_rbuf, sfs_rblock,etc. read different kind of blocks in file /* * (1) If offset isn't aligned with the first block, Rd/Wr some content from offset to the end of the first block * NOTICE: useful function: sfs_bmap_load_nolock, sfs_buf_op * Rd/Wr size = (nblks != 0) ? (SFS_BLKSIZE - blkoff) : (endpos - offset) * (2) Rd/Wr aligned blocks * NOTICE: useful function: sfs_bmap_load_nolock, sfs_block_op * (3) If end position isn't aligned with the last block, Rd/Wr some content from begin to the (endpos % SFS_BLKSIZE) of the last block * NOTICE: useful function: sfs_bmap_load_nolock, sfs_buf_op */ //cprintf("Reading from %d to %d, %d blocks\n", offset, endpos, nblks); // Read the first block, if offset is in the middle of the block blkoff = offset % SFS_BLKSIZE; if (blkoff != 0) { size = nblks > 0 ? SFS_BLKSIZE - blkoff : endpos - offset; if (sfs_bmap_load_nolock(sfs, sin, blkno, &ino)) goto out; if (sfs_buf_op(sfs, buf, size, ino, blkoff)) goto out; alen += size; buf = (char *)buf + size; blkno++; } else { // Otherwise read this block either as a full block, or the last block nblks++; } // Read the full blocks int read_count; for (read_count = 0; read_count < (int)nblks - 1; read_count++) { if (sfs_bmap_load_nolock(sfs, sin, blkno, &ino)) goto out; if (sfs_block_op(sfs, buf, ino, 1)) goto out; blkno++; alen += SFS_BLKSIZE; buf = (char *)buf + SFS_BLKSIZE; } // Read the final incomplete block, if it exists size = endpos % SFS_BLKSIZE; if(size != 0 && nblks > 0) { if(sfs_bmap_load_nolock(sfs, sin, blkno, &ino)) goto out; if(sfs_buf_op(sfs, buf, size, ino, 0)) goto out; alen += size; } out: *alenp = alen; if (offset + alen > sin->din->size) { sin->din->size = offset + alen; sin->dirty = 1; } return ret; }
static int sfs_io_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, void *buf, off_t offset, size_t *alenp, bool write) { struct sfs_disk_inode *din = sin->din; assert(din->type != SFS_TYPE_DIR); off_t endpos = offset + *alenp, blkoff; *alenp = 0; if (offset < 0 || offset >= SFS_MAX_FILE_SIZE || offset > endpos) { return -E_INVAL; } if (offset == endpos) { return 0; } if (endpos > SFS_MAX_FILE_SIZE) { endpos = SFS_MAX_FILE_SIZE; } if (!write) { if (offset >= din->fileinfo.size) { return 0; } if (endpos > din->fileinfo.size) { endpos = din->fileinfo.size; } } int (*sfs_buf_op)(struct sfs_fs *sfs, void *buf, size_t len, uint32_t blkno, off_t offset); int (*sfs_block_op)(struct sfs_fs *sfs, void *buf, uint32_t blkno, uint32_t nblks); if (write) { sfs_buf_op = sfs_wbuf, sfs_block_op = sfs_wblock; } else { sfs_buf_op = sfs_rbuf, sfs_block_op = sfs_rblock; } int ret = 0; size_t size, alen = 0; uint32_t ino; uint32_t blkno = offset / SFS_BLKSIZE; uint32_t nblks = endpos / SFS_BLKSIZE - blkno; if ((blkoff = offset % SFS_BLKSIZE) != 0) { size = (nblks != 0) ? (SFS_BLKSIZE - blkoff) : (endpos - offset); if ((ret = sfs_bmap_load_nolock(sfs, sin, blkno, &ino)) != 0) { goto out; } if ((ret = sfs_buf_op(sfs, buf, size, ino, blkoff)) != 0) { goto out; } alen += size; if (nblks == 0) { goto out; } buf += size, blkno ++, nblks --; } size = SFS_BLKSIZE; while (nblks != 0) { if ((ret = sfs_bmap_load_nolock(sfs, sin, blkno, &ino)) != 0) { goto out; } if ((ret = sfs_block_op(sfs, buf, ino, 1)) != 0) { goto out; } alen += size, buf += size, blkno ++, nblks --; } if ((size = endpos % SFS_BLKSIZE) != 0) { if ((ret = sfs_bmap_load_nolock(sfs, sin, blkno, &ino)) != 0) { goto out; } if ((ret = sfs_buf_op(sfs, buf, size, ino, 0)) != 0) { goto out; } alen += size; } out: *alenp = alen; if (offset + alen > din->fileinfo.size) { din->fileinfo.size = offset + alen; sin->dirty = 1; } return ret; }