static int sfs_getdirentry(struct inode *node, struct iobuf *iob) { struct sfs_disk_entry *entry; if ((entry = kmalloc(sizeof(struct sfs_disk_entry))) == NULL) { return -E_NO_MEM; } struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs); struct sfs_inode *sin = vop_info(node, sfs_inode); int ret, slot; off_t offset = iob->io_offset; if (offset < 0 || offset % sfs_dentry_size != 0) { kfree(entry); return -E_INVAL; } if ((slot = offset / sfs_dentry_size) > sin->din->blocks) { kfree(entry); return -E_NOENT; } lock_sin(sin); if ((ret = sfs_getdirentry_sub_nolock(sfs, sin, slot, entry)) != 0) { unlock_sin(sin); goto out; } unlock_sin(sin); ret = iobuf_move(iob, entry->name, sfs_dentry_size, 1, NULL); out: kfree(entry); return ret; }
// Lock the given inode. // Reads the inode from disk if necessary. static void sfs_ilock(struct inode *ip) { struct sfs_inode *sin = vop_info(ip, sfs_inode); struct buf *bp; struct sfs_dinode *dip; if(sin == 0 || sin->ref < 1) panic("ilock"); acquire(&icache.lock); while(sin->flags & I_BUSY) sleep(ip, &icache.lock); sin->flags |= I_BUSY; release(&icache.lock); if(!(sin->flags & I_VALID)){ // cprintf("dev=%d, inum=%d\n", sin->dev, sin->inum); bp = bread(sin->dev, IBLOCK(sin->inum)); dip = (struct sfs_dinode*)bp->data + sin->inum%IPB; sin->type = dip->type; sin->major = dip->major; sin->minor = dip->minor; sin->nlink = dip->nlink; sin->size = dip->size; memmove(sin->addrs, dip->addrs, sizeof(sin->addrs)); brelse(bp); sin->flags |= I_VALID; if(sin->type == 0) panic("ilock: no type"); } }
static int pipe_inode_ioctl(struct inode * node, int op, void *data) { struct pipe_inode *pin = vop_info(node, pipe_inode); if(op & 04000) pin->no_block = 1; else pin->no_block = 0; return 0; }
// PAGEBREAK! // Write data to inode. int sfs_writei(struct inode *ip, char *src, uint off, uint n) { struct sfs_inode *sin = vop_info(ip, sfs_inode); uint tot, m; struct buf *bp; if(sin->type == T_DEV){ if(sin->major < 0 || sin->major >= NDEV || !devsw[sin->major].write) return -1; return devsw[sin->major].write(ip, src, n); } if(off > sin->size || off + n < off) return -1; if(off + n > MAXFILE*BSIZE) return -1; for(tot=0; tot<n; tot+=m, off+=m, src+=m){ bp = bread(sin->dev, bmap(sin, off/BSIZE)); m = min(n - tot, BSIZE - off%BSIZE); memmove(bp->data + off%BSIZE, src, m); log_write(bp); brelse(bp); } if(n > 0 && off > sin->size){ sin->size = off; sfs_iupdate(ip); } return n; }
//PAGEBREAK! // Read data from inode. int sfs_readi(struct inode *ip, char *dst, uint off, uint n) { // cprintf("enter sfs_readi\n"); struct sfs_inode *sin = vop_info(ip, sfs_inode); uint tot, m; struct buf *bp; // cprintf("inum = %d , type = %d \n", sin->inum, sin->type); if(sin->type == T_DEV){ if(sin->major < 0 || sin->major >= NDEV || !devsw[sin->major].read) return -1; return devsw[sin->major].read(ip, dst, n); } if(off > sin->size || off + n < off) return -1; if(off + n > sin->size) n = sin->size - off; for(tot=0; tot<n; tot+=m, off+=m, dst+=m){ bp = bread(sin->dev, bmap(sin, off/BSIZE)); m = min(n - tot, BSIZE - off%BSIZE); memmove(dst, bp->data + off%BSIZE, m); brelse(bp); } return n; }
static int sfs_dirent_create_inode(struct sfs_fs *sfs, uint16_t type, struct inode **node_store) { struct sfs_disk_inode *din; if ((din = kmalloc(sizeof(struct sfs_disk_inode))) == NULL) { return -E_NO_MEM; } memset(din, 0, sizeof(struct sfs_disk_inode)); din->type = type; int ret; uint32_t ino; if ((ret = sfs_block_alloc(sfs, &ino)) != 0) { goto failed_cleanup_din; } struct inode *node; if ((ret = sfs_create_inode(sfs, din, ino, &node)) != 0) { goto failed_cleanup_ino; } lock_sfs_fs(sfs); { sfs_set_links(sfs, vop_info(node, sfs_inode)); } unlock_sfs_fs(sfs); *node_store = node; return 0; failed_cleanup_ino: sfs_block_free(sfs, ino); failed_cleanup_din: kfree(din); return ret; }
static int sfs_mkdir_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, const char *name) { int ret, slot; if ((ret = sfs_dirent_search_nolock(sfs, sin, name, NULL, NULL, &slot)) != -E_NOENT) { return (ret != 0) ? ret : -E_EXISTS; } struct inode *link_node; if ((ret = sfs_dirent_create_inode(sfs, SFS_TYPE_DIR, &link_node)) != 0) { return ret; } struct sfs_inode *lnksin = vop_info(link_node, sfs_inode); if ((ret = sfs_dirent_link_nolock(sfs, sin, slot, lnksin, name)) != 0) { assert(lnksin->din->nlinks == 0); assert(inode_ref_count(link_node) == 1 && inode_open_count(link_node) == 0); goto out; } /* set parent */ sfs_dirinfo_set_parent(lnksin, sin); /* add '.' link to itself */ sfs_nlinks_inc_nolock(lnksin); /* add '..' link to parent */ sfs_nlinks_inc_nolock(sin); out: vop_ref_dec(link_node); return ret; }
// Truncate inode (discard contents). // Only called when the inode has no links // to it (no directory entries referring to it) // and has no in-memory reference to it (is // not an open file or current directory). static void sfs_itrunc(struct inode *ip) { struct sfs_inode *sin = vop_info(ip, sfs_inode); int i, j; struct buf *bp; uint *a; for(i = 0; i < NDIRECT; i++){ if(sin->addrs[i]){ bfree(sin->dev, sin->addrs[i]); sin->addrs[i] = 0; } } if(sin->addrs[NDIRECT]){ bp = bread(sin->dev, sin->addrs[NDIRECT]); a = (uint*)bp->data; for(j = 0; j < NINDIRECT; j++){ if(a[j]) bfree(sin->dev, a[j]); } brelse(bp); bfree(sin->dev, sin->addrs[NDIRECT]); sin->addrs[NDIRECT] = 0; } sin->size = 0; sfs_iupdate(ip); }
int linux_devfile_write(int fd, void *base, size_t len, size_t * copied_store) { int ret = -E_INVAL; struct file *file; /* use 8byte int, in case of 64bit off_t * config in linux kernel */ int64_t offset; if ((ret = fd2file(fd, &file)) != 0) { return 0; } if (!file->writable) { return -E_INVAL; } filemap_acquire(file); offset = file->pos; struct device *dev = vop_info(file->node, device); assert(dev); ret = dev->d_linux_write(dev, base, len, (size_t *) & offset); if (ret >= 0) { *copied_store = (size_t) ret; file->pos += ret; ret = 0; } filemap_release(file); return ret; }
/* * Called for each open(). * * We reject O_CREAT | O_TRUNC | O_EXCL | O_APPEND */ static int dev_open(struct inode *node, uint32_t open_flags) { if (open_flags & (O_CREAT | O_TRUNC | O_EXCL | O_APPEND)) { return -E_INVAL; } struct device *dev = vop_info(node, device); return dop_open(dev, open_flags); }
// Increment reference count for ip. // Returns ip to enable ip = idup(ip1) idiom. struct inode* sfs_idup(struct inode *ip) { struct sfs_inode *sip = vop_info(ip, sfs_inode); acquire(&icache.lock); sip->ref++; release(&icache.lock); return ip; }
// Increment reference count for ip. // Returns ip to enable ip = idup(ip1) idiom. struct inode* sfs_link_dec(struct inode *ip) { struct sfs_inode *sip = vop_info(ip, sfs_inode); acquire(&icache.lock); sip->nlink--; release(&icache.lock); return ip; }
/* * Called for each open(). * * We reject O_CREAT | O_TRUNC | O_EXCL | O_APPEND */ static int dev_open(struct inode *node, struct file *filp) { if (filp->open_flags & (O_CREAT | O_TRUNC | O_EXCL | O_APPEND)) { return -E_INVAL; } struct device *dev = vop_info(node, device); return dop_open(dev, node, filp); }
/* * sfs_tryseek - Check if seeking to the specified position within the file is legal. */ static int sfs_tryseek(struct inode *node, off_t pos) { if (pos < 0 || pos >= SFS_MAX_FILE_SIZE) { return -E_INVAL; } struct sfs_inode *sin = vop_info(node, sfs_inode); if (pos > sin->din->size) { return vop_truncate(node, pos); } return 0; }
// Copy stat information from inode. void sfs_stati(struct inode *ip, struct stat *st) { struct sfs_inode *sin = vop_info(ip, sfs_inode); st->dev = sin->dev; st->ino = sin->inum; st->type = sin->type; st->nlink = sin->nlink; st->size = sin->size; st->fstype = ip->fstype; }
/* linux devfile adaptor */ bool __is_linux_devfile(int fd) { int ret = -E_INVAL; struct file *file; if ((ret = fd2file(fd, &file)) != 0) { return 0; } if (file->node && check_inode_type(file->node, device) && dev_is_linux_dev(vop_info(file->node, device))) return 1; return 0; }
/* * Attempt a seek. * For block devices, require block alignment. * For character devices, prohibit seeking entirely. */ static int dev_tryseek(struct inode *node, off_t pos) { struct device *dev = vop_info(node, device); if (dev->d_blocks > 0) { if ((pos % dev->d_blocksize) == 0) { if (pos >= 0 && pos < dev->d_blocks * dev->d_blocksize) { return 0; } } } return -E_INVAL; }
static int sfs_link(struct inode *node, const char *name, struct inode *link_node) { if (strlen(name) > SFS_MAX_FNAME_LEN) { return -E_TOO_BIG; } if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { return -E_EXISTS; } struct sfs_inode *lnksin = vop_info(link_node, sfs_inode); if (lnksin->din->type == SFS_TYPE_DIR) { return -E_ISDIR; } struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs); struct sfs_inode *sin = vop_info(node, sfs_inode); int ret; if ((ret = trylock_sin(sin)) == 0) { ret = sfs_link_nolock(sfs, sin, lnksin, name); unlock_sin(sin); } return ret; }
// Unlock the given inode. static void sfs_iunlock(struct inode *ip) { struct sfs_inode *sin = vop_info(ip, sfs_inode); if(sin == 0 || !(sin->flags & I_BUSY) || sin->ref < 1) panic("iunlock"); acquire(&icache.lock); sin->flags &= ~I_BUSY; wakeup(ip); release(&icache.lock); }
/* * sfs_fstat - Return nlinks/block/size, etc. info about a file. The pointer is a pointer to struct stat; */ static int sfs_fstat(struct inode *node, struct stat *stat) { int ret; memset(stat, 0, sizeof(struct stat)); if ((ret = vop_gettype(node, &(stat->st_mode))) != 0) { return ret; } struct sfs_disk_inode *din = vop_info(node, sfs_inode)->din; stat->st_nlinks = din->nlinks; stat->st_blocks = din->blocks; stat->st_size = din->size; return 0; }
/* * sfs_create_inode - alloc a inode in memroy, and init din/ino/dirty/reclian_count/sem fields in sfs_inode in inode */ static int sfs_create_inode(struct sfs_fs *sfs, struct sfs_disk_inode *din, uint32_t ino, struct inode **node_store) { struct inode *node; if ((node = alloc_inode(sfs_inode)) != NULL) { vop_init(node, sfs_get_ops(din->type), info2fs(sfs, sfs)); struct sfs_inode *sin = vop_info(node, sfs_inode); sin->din = din, sin->ino = ino, sin->dirty = 0, sin->reclaim_count = 1; sem_init(&(sin->sem), 1); *node_store = node; return 0; } return -E_NO_MEM; }
/* * Called for fstat(). * Set the type and the size. * The link count for a device is always 1. */ static int dev_fstat(struct inode *node, struct stat *stat) { int ret; memset(stat, 0, sizeof(struct stat)); if ((ret = vop_gettype(node, &(stat->st_mode))) != 0) { return ret; } struct device *dev = vop_info(node, device); stat->st_nlinks = 1; stat->st_blocks = dev->d_blocks; stat->st_size = stat->st_blocks * dev->d_blocksize; return 0; }
void dev_init_ashmem(void) { struct inode *node; if((node = dev_create_inode()) == NULL) { panic("null: dev_create_node.\n"); } ashmem_device_init(vop_info(node, device)); int ret; if((ret = vfs_add_dev("ashmem", node, 0)) != 0) { panic("ashmem: vfs_add_dev: %e.\n", ret); } }
void dev_init_stdout(void) { struct inode *node; if ((node = dev_create_inode()) == NULL) { panic("stdout: dev_create_node.\n"); } stdout_device_init(vop_info(node, device)); int ret; if ((ret = vfs_add_dev("stdout", node, 0)) != 0) { panic("stdout: vfs_add_dev: %e.\n", ret); } }
static int pipe_inode_write(struct inode *node, struct iobuf *iob) { struct pipe_inode *pin = vop_info(node, pipe_inode); if (pin->pin_type != PIN_WRONLY) { return -E_INVAL; } size_t ret; if ((ret = pipe_state_write(pin->state, iob->io_base, iob->io_resid)) != 0) { iobuf_skip(iob, ret); } return 0; }
void dev_init_disk0(void) { struct inode *node; if ((node = dev_create_inode()) == NULL) { panic("disk0: dev_create_node.\n"); } disk0_device_init(vop_info(node, device)); int ret; if ((ret = vfs_add_dev("disk0", node, 1)) != 0) { panic("disk0: vfs_add_dev: %e.\n", ret); } }
static int sfs_reclaim(struct inode *node) { struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs); struct sfs_inode *sin = vop_info(node, sfs_inode); lock_sfs_fs(sfs); int ret = -E_BUSY; assert(sin->reclaim_count > 0); if ((-- sin->reclaim_count) != 0) { goto failed_unlock; } assert(inode_ref_count(node) == 0 && inode_open_count(node) == 0); if (sin->din->nlinks == 0) { uint32_t nblks; for (nblks = sin->din->blocks; nblks != 0; nblks --) { sfs_bmap_truncate_nolock(sfs, sin); } } else if (sin->dirty) { if ((ret = vop_fsync(node)) != 0) { goto failed_unlock; } } sfs_remove_links(sin); unlock_sfs_fs(sfs); if (sin->din->nlinks == 0) { sfs_block_free(sfs, sin->ino); uint32_t ent; if ((ent = sin->din->indirect) != 0) { sfs_block_free(sfs, ent); } if ((ent = sin->din->db_indirect) != 0) { int i; for (i = 0; i < SFS_BLK_NENTRY; i ++) { sfs_bmap_free_sub_nolock(sfs, ent, i); } sfs_block_free(sfs, ent); } } kfree(sin->din); vop_kill(node); return 0; failed_unlock: unlock_sfs_fs(sfs); return ret; }
int linux_devfile_ioctl(int fd, unsigned int cmd, unsigned long arg) { int ret = -E_INVAL; struct file *file; if ((ret = fd2file(fd, &file)) != 0) { return 0; } filemap_acquire(file); struct device *dev = vop_info(file->node, device); assert(dev); ret = dev->d_linux_ioctl(dev, cmd, arg); filemap_release(file); return ret; }
void *linux_devfile_mmap2(void *addr, size_t len, int prot, int flags, int fd, size_t pgoff) { int ret = -E_INVAL; struct file *file; if ((ret = fd2file(fd, &file)) != 0) { return NULL; } filemap_acquire(file); struct device *dev = vop_info(file->node, device); assert(dev); void* r = dev->d_linux_mmap(dev, addr, len, prot, flags, pgoff); filemap_release(file); return r; }
struct inode* sfs_create_inode(struct inode *dirnode, short type, short major, short minor, char* name){ // cprintf("enter sfs_create_inode\n"); struct sfs_inode *sdirnode = vop_info(dirnode, sfs_inode); struct inode *ip = sfs_ialloc(dirnode, sdirnode->dev, type); struct sfs_inode *sip = vop_info(ip, sfs_inode); vop_ilock(ip); sip->major = major; sip->minor = minor; sip->nlink = 1; vop_iupdate(ip); if(type == T_DIR){ // Create . and .. entries. vop_link_inc(dirnode); // for ".." vop_iupdate(dirnode); // No ip->nlink++ for ".": avoid cyclic ref count. if(vop_dirlink(ip, ".", ip) < 0 || vop_dirlink(ip, "..", dirnode) < 0) panic("create dots"); } if(vop_dirlink(dirnode, name, ip) < 0) panic("create: dirlink"); return ip; }