int v7fs_update(struct vnode *vp, const struct timespec *acc, const struct timespec *mod, int flags) { struct v7fs_node *v7node = vp->v_data; struct v7fs_inode *inode = &v7node->inode; struct v7fs_self *fs = v7node->v7fsmount->core; bool update = false; DPRINTF("%p %zu %d\n", vp, vp->v_size, v7fs_inode_filesize(inode)); KDASSERT(vp->v_size == v7fs_inode_filesize(inode)); if (v7node->update_atime) { inode->atime = acc ? acc->tv_sec : time_second; v7node->update_atime = false; update = true; } if (v7node->update_ctime) { inode->ctime = time_second; v7node->update_ctime = false; update = true; } if (v7node->update_mtime) { inode->mtime = mod ? mod->tv_sec : time_second; v7node->update_mtime = false; update = true; } if (update) v7fs_inode_writeback(fs, inode); return 0; }
int v7fs_symlink(void *v) { struct vop_symlink_v3_args /* { struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; struct vattr *a_vap; char *a_target; } */ *a = v; struct v7fs_node *parent_node = a->a_dvp->v_data; struct v7fs_mount *v7fsmount = parent_node->v7fsmount; struct v7fs_self *fs = v7fsmount->core; struct vattr *va = a->a_vap; kauth_cred_t cr = a->a_cnp->cn_cred; struct componentname *cnp = a->a_cnp; struct v7fs_fileattr attr; v7fs_ino_t ino; const char *from = a->a_target; const char *to = cnp->cn_nameptr; size_t len = strlen(from) + 1; int error = 0; if (len > V7FS_BSIZE) { /* limited to 512byte pathname */ DPRINTF("too long pathname."); return ENAMETOOLONG; } memset(&attr, 0, sizeof(attr)); attr.uid = kauth_cred_geteuid(cr); attr.gid = kauth_cred_getegid(cr); attr.mode = va->va_mode | vtype_to_v7fs_mode(va->va_type); if ((error = v7fs_file_allocate (fs, &parent_node->inode, to, &attr, &ino))) { return error; } /* Sync dirent size change. */ uvm_vnp_setsize(a->a_dvp, v7fs_inode_filesize(&parent_node->inode)); /* Get myself vnode. */ if ((error = v7fs_vget(v7fsmount->mountp, ino, a->a_vpp))) { DPRINTF("can't get vnode.\n"); } struct v7fs_node *newnode = (*a->a_vpp)->v_data; struct v7fs_inode *p = &newnode->inode; v7fs_file_symlink(fs, p, from); uvm_vnp_setsize(*a->a_vpp, v7fs_inode_filesize(p)); newnode->update_ctime = true; newnode->update_mtime = true; newnode->update_atime = true; if (error == 0) VOP_UNLOCK(*a->a_vpp); return error; }
int v7fs_rename(void *v) { struct vop_rename_args /* { struct vnode *a_fdvp; from parent-directory struct vnode *a_fvp; from file struct componentname *a_fcnp; struct vnode *a_tdvp; to parent-directory struct vnode *a_tvp; to file struct componentname *a_tcnp; } */ *a = v; struct vnode *fvp = a->a_fvp; struct vnode *tvp = a->a_tvp; struct vnode *fdvp = a->a_fdvp; struct vnode *tdvp = a->a_tdvp; struct v7fs_node *parent_from = fdvp->v_data; struct v7fs_node *parent_to = tdvp->v_data; struct v7fs_node *v7node = fvp->v_data; struct v7fs_self *fs = v7node->v7fsmount->core; const char *from_name = a->a_fcnp->cn_nameptr; const char *to_name = a->a_tcnp->cn_nameptr; int error; DPRINTF("%s->%s %p %p\n", from_name, to_name, fvp, tvp); if ((fvp->v_mount != tdvp->v_mount) || (tvp && (fvp->v_mount != tvp->v_mount))) { error = EXDEV; DPRINTF("cross-device link\n"); goto out; } // XXXsource file lock? error = v7fs_file_rename(fs, &parent_from->inode, from_name, &parent_to->inode, to_name); /* 'to file' inode may be changed. (hard-linked and it is cached.) t_vnops rename_reg_nodir */ if (error == 0 && tvp) { struct v7fs_inode *inode = &((struct v7fs_node *)tvp->v_data)->inode; error = v7fs_inode_load(fs, inode, inode->inode_number); uvm_vnp_setsize(tvp, v7fs_inode_filesize(inode)); } /* Sync dirent size change. */ uvm_vnp_setsize(tdvp, v7fs_inode_filesize(&parent_to->inode)); uvm_vnp_setsize(fdvp, v7fs_inode_filesize(&parent_from->inode)); out: if (tvp) vput(tvp); /* locked on entry */ if (tdvp == tvp) vrele(tdvp); else vput(tdvp); vrele(fdvp); vrele(fvp); return error; }
int v7fs_directory_add_entry(struct v7fs_self *fs, struct v7fs_inode *parent_dir, v7fs_ino_t ino, const char *srcname) { struct v7fs_inode inode; struct v7fs_dirent *dir; int error = 0; v7fs_daddr_t blk; void *buf; char filename[V7FS_NAME_MAX + 1]; /* Truncate filename. */ v7fs_dirent_filename(filename, srcname); DPRINTF("%s(%s) %d\n", filename, srcname, ino); /* Target inode */ if ((error = v7fs_inode_load(fs, &inode, ino))) return error; /* Expand datablock. */ if ((error = v7fs_datablock_expand(fs, parent_dir, sizeof(*dir)))) return error; /* Read last entry. */ if (!(blk = v7fs_datablock_last(fs, parent_dir, v7fs_inode_filesize(parent_dir)))) return EIO; /* Load dirent block. This vnode(parent dir) is locked by VFS layer. */ if (!(buf = scratch_read(fs, blk))) return EIO; size_t sz = v7fs_inode_filesize(parent_dir); sz = V7FS_RESIDUE_BSIZE(sz); /* last block payload. */ int n = sz / sizeof(*dir) - 1; /* Add dirent. */ dir = (struct v7fs_dirent *)buf; dir[n].inode_number = V7FS_VAL16(fs, ino); memcpy((char *)dir[n].name, filename, V7FS_NAME_MAX); /* Write back datablock */ if (!fs->io.write(fs->io.cookie, buf, blk)) error = EIO; scratch_free(fs, buf); if (v7fs_inode_isdir(&inode)) { parent_dir->nlink++; v7fs_inode_writeback(fs, parent_dir); } DPRINTF("done. (dirent size=%dbyte)\n", parent_dir->filesize); return error; }
int v7fs_link(void *v) { struct vop_link_v2_args /* { struct vnode *a_dvp; struct vnode *a_vp; struct componentname *a_cnp; } */ *a = v; struct vnode *dvp = a->a_dvp; struct vnode *vp = a->a_vp; struct v7fs_node *parent_node = dvp->v_data; struct v7fs_node *node = vp->v_data; struct v7fs_inode *parent = &parent_node->inode; struct v7fs_inode *p = &node->inode; struct v7fs_self *fs = node->v7fsmount->core; struct componentname *cnp = a->a_cnp; int error = 0; DPRINTF("%p\n", vp); /* Lock soruce file */ if ((error = vn_lock(vp, LK_EXCLUSIVE))) { DPRINTF("lock failed. %p\n", vp); VOP_ABORTOP(dvp, cnp); goto unlock; } error = v7fs_file_link(fs, parent, p, cnp->cn_nameptr); /* Sync dirent size change. */ uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode)); VOP_UNLOCK(vp); unlock: return error; }
int v7fs_read(void *v) { struct vop_read_args /* { struct vnode *a_vp; struct uio *a_uio; int a_ioflag; kauth_cred_t a_cred; } */ *a = v; struct vnode *vp = a->a_vp; struct uio *uio = a->a_uio; struct v7fs_node *v7node = vp->v_data; struct v7fs_inode *inode = &v7node->inode; vsize_t sz, filesz = v7fs_inode_filesize(inode); const int advice = IO_ADV_DECODE(a->a_ioflag); int error = 0; DPRINTF("type=%d inode=%d\n", vp->v_type, v7node->inode.inode_number); while (uio->uio_resid > 0) { if ((sz = MIN(filesz - uio->uio_offset, uio->uio_resid)) == 0) break; error = ubc_uiomove(&vp->v_uobj, uio, sz, advice, UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(v)); if (error) { break; } DPRINTF("read %zubyte\n", sz); } v7node->update_atime = true; return error; }
int v7fs_create(void *v) { struct vop_create_v3_args /* { struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; struct vattr *a_vap; } */ *a = v; struct v7fs_node *parent_node = a->a_dvp->v_data; struct v7fs_mount *v7fsmount = parent_node->v7fsmount; struct v7fs_self *fs = v7fsmount->core; struct mount *mp = v7fsmount->mountp; struct v7fs_fileattr attr; struct vattr *va = a->a_vap; kauth_cred_t cr = a->a_cnp->cn_cred; v7fs_ino_t ino; int error = 0; DPRINTF("%s parent#%d\n", a->a_cnp->cn_nameptr, parent_node->inode.inode_number); KDASSERT((va->va_type == VREG) || (va->va_type == VSOCK)); memset(&attr, 0, sizeof(attr)); attr.uid = kauth_cred_geteuid(cr); attr.gid = kauth_cred_getegid(cr); attr.mode = va->va_mode | vtype_to_v7fs_mode (va->va_type); attr.device = 0; /* Allocate disk entry. and register its entry to parent directory. */ if ((error = v7fs_file_allocate(fs, &parent_node->inode, a->a_cnp->cn_nameptr, &attr, &ino))) { DPRINTF("v7fs_file_allocate failed.\n"); return error; } /* Sync dirent size change. */ uvm_vnp_setsize(a->a_dvp, v7fs_inode_filesize(&parent_node->inode)); /* Get myself vnode. */ *a->a_vpp = 0; if ((error = v7fs_vget(mp, ino, a->a_vpp))) { DPRINTF("v7fs_vget failed.\n"); return error; } /* Scheduling update time. real update by v7fs_update */ struct v7fs_node *newnode = (*a->a_vpp)->v_data; newnode->update_ctime = true; newnode->update_mtime = true; newnode->update_atime = true; DPRINTF("allocated %s->#%d\n", a->a_cnp->cn_nameptr, ino); if (error == 0) VOP_UNLOCK(*a->a_vpp); return error; }
int v7fs_mknod(void *v) { struct vop_mknod_v3_args /* { struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; struct vattr *a_vap; } */ *a = v; struct componentname *cnp = a->a_cnp; kauth_cred_t cr = cnp->cn_cred; struct vnode *dvp = a->a_dvp; struct vattr *va = a->a_vap; struct v7fs_node *parent_node = dvp->v_data; struct v7fs_mount *v7fsmount = parent_node->v7fsmount; struct v7fs_self *fs = v7fsmount->core; struct mount *mp = v7fsmount->mountp; struct v7fs_fileattr attr; v7fs_ino_t ino; int error = 0; DPRINTF("%s %06o %lx %d\n", cnp->cn_nameptr, va->va_mode, (long)va->va_rdev, va->va_type); memset(&attr, 0, sizeof(attr)); attr.uid = kauth_cred_geteuid(cr); attr.gid = kauth_cred_getegid(cr); attr.mode = va->va_mode | vtype_to_v7fs_mode(va->va_type); attr.device = va->va_rdev; if ((error = v7fs_file_allocate(fs, &parent_node->inode, cnp->cn_nameptr, &attr, &ino))) return error; /* Sync dirent size change. */ uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode)); if ((error = v7fs_vget(mp, ino, a->a_vpp))) { DPRINTF("can't get vnode.\n"); return error; } struct v7fs_node *newnode = (*a->a_vpp)->v_data; newnode->update_ctime = true; newnode->update_mtime = true; newnode->update_atime = true; if (error == 0) VOP_UNLOCK(*a->a_vpp); return error; }
int v7fs_rmdir(void *v) { struct vop_rmdir_args /* { struct vnode *a_dvp; struct vnode *a_vp; struct componentname *a_cnp; } */ *a = v; struct vnode *vp = a->a_vp; struct vnode *dvp = a->a_dvp; struct v7fs_node *parent_node = dvp->v_data; struct v7fs_mount *v7fsmount = parent_node->v7fsmount; struct v7fs_inode *inode = &((struct v7fs_node *)vp->v_data)->inode; struct v7fs_self *fs = v7fsmount->core; int error = 0; DPRINTF("delete %s\n", a->a_cnp->cn_nameptr); KDASSERT(vp->v_type == VDIR); if ((error = v7fs_file_deallocate(fs, &parent_node->inode, a->a_cnp->cn_nameptr))) { DPRINTF("v7fs_directory_deallocate failed.\n"); goto out; } error = v7fs_inode_load(fs, inode, inode->inode_number); if (error) goto out; uvm_vnp_setsize(vp, v7fs_inode_filesize(inode)); /* Sync dirent size change. */ uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode)); out: vput(vp); vput(dvp); return error; }
int v7fs_write(void *v) { struct vop_write_args /* { struct vnode *a_vp; struct uio *a_uio; int a_ioflag; kauth_cred_t a_cred; } */ *a = v; struct vnode *vp = a->a_vp; struct uio *uio = a->a_uio; int advice = IO_ADV_DECODE(a->a_ioflag); struct v7fs_node *v7node = vp->v_data; struct v7fs_inode *inode = &v7node->inode; struct v7fs_self *fs = v7node->v7fsmount->core; vsize_t sz; int error = 0; if (uio->uio_resid == 0) return 0; sz = v7fs_inode_filesize(inode); DPRINTF("(i)%ld (v)%zu ofs=%zu + res=%zu = %zu\n", sz, vp->v_size, uio->uio_offset, uio->uio_resid, uio->uio_offset + uio->uio_resid); /* Append mode file offset is managed by kernel. */ if (a->a_ioflag & IO_APPEND) uio->uio_offset = sz; /* If write region is over filesize, expand. */ size_t newsize= uio->uio_offset + uio->uio_resid; ssize_t expand = newsize - sz; if (expand > 0) { if ((error = v7fs_datablock_expand(fs, inode, expand))) return error; uvm_vnp_setsize(vp, newsize); } while (uio->uio_resid > 0) { sz = uio->uio_resid; if ((error = ubc_uiomove(&vp->v_uobj, uio, sz, advice, UBC_WRITE | UBC_UNMAP_FLAG(v)))) break; DPRINTF("write %zubyte\n", sz); } v7node->update_mtime = true; return error; }
int v7fs_directory_remove_entry(struct v7fs_self *fs, struct v7fs_inode *parent_dir, const char *name) { struct v7fs_inode inode; int error; struct v7fs_dirent lastdirent; v7fs_daddr_t lastblk; size_t sz, lastsz; v7fs_off_t pos; void *buf; /* Setup replaced entry. */ sz = parent_dir->filesize; lastblk = v7fs_datablock_last(fs, parent_dir, v7fs_inode_filesize(parent_dir)); lastsz = V7FS_RESIDUE_BSIZE(sz); pos = lastsz - sizeof(lastdirent); if (!(buf = scratch_read(fs, lastblk))) return EIO; lastdirent = *((struct v7fs_dirent *)((uint8_t *)buf + pos)); scratch_free(fs, buf); DPRINTF("last dirent=%d %s pos=%d\n", V7FS_VAL16(fs, lastdirent.inode_number), lastdirent.name, pos); struct v7fs_lookup_arg lookup_arg = { .name = name, .replace = &lastdirent/*disk endian */ }; /* Search entry that removed. replace it to last dirent. */ if ((error = v7fs_datablock_foreach(fs, parent_dir, remove_subr, &lookup_arg)) != V7FS_ITERATOR_BREAK) return ENOENT; /* Contract dirent entries. */ v7fs_datablock_contract(fs, parent_dir, sizeof(lastdirent)); DPRINTF("done. (dirent size=%dbyte)\n", parent_dir->filesize); /* Target inode */ if ((error = v7fs_inode_load(fs, &inode, lookup_arg.inode_number))) return error; if (v7fs_inode_isdir(&inode)) { parent_dir->nlink--; v7fs_inode_writeback(fs, parent_dir); } return 0; }
int v7fs_advlock(void *v) { struct vop_advlock_args /* { struct vnode *a_vp; void *a_id; int a_op; struct flock *a_fl; int a_flags; } */ *a = v; struct v7fs_node *v7node = a->a_vp->v_data; DPRINTF("op=%d\n", a->a_op); return lf_advlock(a, &v7node->lockf, v7fs_inode_filesize(&v7node->inode)); }
int v7fs_remove(void *v) { struct vop_remove_args /* { struct vnodeop_desc *a_desc; struct vnode * a_dvp; struct vnode * a_vp; struct componentname * a_cnp; } */ *a = v; struct v7fs_node *parent_node = a->a_dvp->v_data; struct v7fs_mount *v7fsmount = parent_node->v7fsmount; struct vnode *vp = a->a_vp; struct vnode *dvp = a->a_dvp; struct v7fs_inode *inode = &((struct v7fs_node *)vp->v_data)->inode; struct v7fs_self *fs = v7fsmount->core; int error = 0; DPRINTF("delete %s\n", a->a_cnp->cn_nameptr); if (vp->v_type == VDIR) { error = EPERM; goto out; } if ((error = v7fs_file_deallocate(fs, &parent_node->inode, a->a_cnp->cn_nameptr))) { DPRINTF("v7fs_file_delete failed.\n"); goto out; } error = v7fs_inode_load(fs, inode, inode->inode_number); if (error) goto out; /* Sync dirent size change. */ uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode)); out: if (dvp == vp) vrele(vp); /* v_usecount-- of unlocked vp */ else vput(vp); /* unlock vp and then v_usecount-- */ vput(dvp); return error; }
int v7fs_close(void *v) { struct vop_close_args /* { struct vnodeop_desc *a_desc; struct vnode *a_vp; int a_fflag; kauth_cred_t a_cred; } */ *a = v; struct vnode *vp = a->a_vp; #ifdef V7FS_VNOPS_DEBUG struct v7fs_node *v7node = vp->v_data; struct v7fs_inode *inode = &v7node->inode; #endif DPRINTF("#%d (i)%dbyte (v)%zubyte\n", inode->inode_number, v7fs_inode_filesize(inode), vp->v_size); /* Update timestamp */ v7fs_update(vp, 0, 0, UPDATE_WAIT); return 0; }
int v7fs_file_lookup_by_name(struct v7fs_self *fs, struct v7fs_inode *parent_dir, const char *name, v7fs_ino_t *ino) { char filename[V7FS_NAME_MAX + 1]; char *q; int error; size_t len; if ((q = strchr(name, '/'))) { /* Zap following path. */ len = MIN(V7FS_NAME_MAX, q - name); memcpy(filename, name, len); filename[len] = '\0'; /* '/' -> '\0' */ } else { v7fs_dirent_filename(filename, name); } DPRINTF("%s(%s) dir=%d\n", filename, name, parent_dir->inode_number); struct v7fs_lookup_arg lookup_arg = { .name = filename, .inode_number = 0 }; if ((error = v7fs_datablock_foreach(fs, parent_dir, lookup_subr, &lookup_arg)) != V7FS_ITERATOR_BREAK) { DPRINTF("not found.\n"); return ENOENT; } *ino = lookup_arg.inode_number; DPRINTF("done. ino=%d\n", *ino); return 0; } static int lookup_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, size_t sz) { struct v7fs_lookup_arg *p = (struct v7fs_lookup_arg *)ctx; struct v7fs_dirent *dir; const char *name = p->name; void *buf; size_t i, n; int ret = 0; if (!(buf = scratch_read(fs, blk))) return EIO; dir = (struct v7fs_dirent *)buf; n = sz / sizeof(*dir); v7fs_dirent_endian_convert(fs, dir, n); for (i = 0; i < n; i++, dir++) { if (dir->inode_number < 1) { DPRINTF("*** bad inode #%d ***\n", dir->inode_number); continue; } if (strncmp((const char *)dir->name, name, V7FS_NAME_MAX) == 0) { p->inode_number = dir->inode_number; ret = V7FS_ITERATOR_BREAK; /* found */ break; } } scratch_free(fs, buf); return ret; } int v7fs_file_allocate(struct v7fs_self *fs, struct v7fs_inode *parent_dir, const char *srcname, struct v7fs_fileattr *attr, v7fs_ino_t *ino) { struct v7fs_inode inode; char filename[V7FS_NAME_MAX + 1]; struct v7fs_dirent *dir; int error; /* Truncate filename. */ v7fs_dirent_filename(filename, srcname); DPRINTF("%s(%s)\n", filename, srcname); /* Check filename. */ if (v7fs_file_lookup_by_name(fs, parent_dir, filename, ino) == 0) { DPRINTF("%s exists\n", filename); return EEXIST; } /* Get new inode. */ if ((error = v7fs_inode_allocate(fs, ino))) return error; /* Set initial attribute. */ memset(&inode, 0, sizeof(inode)); inode.inode_number = *ino; inode.mode = attr->mode; inode.uid = attr->uid; inode.gid = attr->gid; if (attr->ctime) inode.ctime = attr->ctime; if (attr->mtime) inode.mtime = attr->mtime; if (attr->atime) inode.atime = attr->atime; switch (inode.mode & V7FS_IFMT) { default: DPRINTF("Can't allocate %o type.\n", inode.mode); v7fs_inode_deallocate(fs, *ino); return EINVAL; case V7FS_IFCHR: /* FALLTHROUGH */ case V7FS_IFBLK: inode.nlink = 1; inode.device = attr->device; inode.addr[0] = inode.device; break; case V7FSBSD_IFFIFO: /* FALLTHROUGH */ case V7FSBSD_IFSOCK: /* FALLTHROUGH */ case V7FSBSD_IFLNK: /* FALLTHROUGH */ case V7FS_IFREG: inode.nlink = 1; break; case V7FS_IFDIR: inode.nlink = 2; /* . + .. */ if ((error = v7fs_datablock_expand(fs, &inode, sizeof(*dir) * 2 ))) { v7fs_inode_deallocate(fs, *ino); return error; } v7fs_daddr_t blk = inode.addr[0]; void *buf; if (!(buf = scratch_read(fs, blk))) { v7fs_inode_deallocate(fs, *ino); return EIO; } dir = (struct v7fs_dirent *)buf; strcpy(dir[0].name, "."); dir[0].inode_number = V7FS_VAL16(fs, *ino); strcpy(dir[1].name, ".."); dir[1].inode_number = V7FS_VAL16(fs, parent_dir->inode_number); if (!fs->io.write(fs->io.cookie, buf, blk)) { scratch_free(fs, buf); return EIO; } scratch_free(fs, buf); break; } v7fs_inode_writeback(fs, &inode); /* Link this inode to parent directory. */ if ((error = v7fs_directory_add_entry(fs, parent_dir, *ino, filename))) { DPRINTF("can't add dirent.\n"); return error; } return 0; } int v7fs_file_deallocate(struct v7fs_self *fs, struct v7fs_inode *parent_dir, const char *name) { v7fs_ino_t ino; struct v7fs_inode inode; int error; DPRINTF("%s\n", name); if ((error = v7fs_file_lookup_by_name(fs, parent_dir, name, &ino))) { DPRINTF("no such a file: %s\n", name); return error; } DPRINTF("%s->#%d\n", name, ino); if ((error = v7fs_inode_load(fs, &inode, ino))) return error; if (v7fs_inode_isdir(&inode)) { char filename[V7FS_NAME_MAX + 1]; v7fs_dirent_filename(filename, name); /* Check parent */ if (strncmp(filename, "..", V7FS_NAME_MAX) == 0) { DPRINTF("can not remove '..'\n"); return EINVAL; /* t_vnops rename_dotdot */ } /* Check empty */ if (v7fs_inode_filesize(&inode) != sizeof(struct v7fs_dirent) * 2 /*"." + ".."*/) { DPRINTF("directory not empty.\n"); return ENOTEMPTY;/* t_vnops dir_noempty, rename_dir(6)*/ } error = v7fs_datablock_size_change(fs, 0, &inode); if (error) return error; inode.nlink = 0; /* remove this. */ } else { /* Decrement reference count. */ --inode.nlink; /* regular file. */ DPRINTF("%s nlink=%d\n", name, inode.nlink); } if ((error = v7fs_directory_remove_entry(fs, parent_dir, name))) return error; DPRINTF("remove dirent\n"); v7fs_inode_writeback(fs, &inode); return 0; }
int v7fs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) { struct v7fs_mount *v7fsmount = mp->mnt_data; struct v7fs_self *fs = v7fsmount->core; struct vnode *vp; struct v7fs_node *v7fs_node; struct v7fs_inode inode; int error; /* Lookup requested i-node */ if ((error = v7fs_inode_load(fs, &inode, ino))) { DPRINTF("v7fs_inode_load failed.\n"); return error; } retry: mutex_enter(&mntvnode_lock); for (v7fs_node = LIST_FIRST(&v7fsmount->v7fs_node_head); v7fs_node != NULL; v7fs_node = LIST_NEXT(v7fs_node, link)) { if (v7fs_node->inode.inode_number == ino) { vp = v7fs_node->vnode; mutex_enter(vp->v_interlock); mutex_exit(&mntvnode_lock); if (vget(vp, LK_EXCLUSIVE) == 0) { *vpp = vp; return 0; } else { DPRINTF("retry!\n"); goto retry; } } } mutex_exit(&mntvnode_lock); /* Allocate v-node. */ if ((error = getnewvnode(VT_V7FS, mp, v7fs_vnodeop_p, NULL, &vp))) { DPRINTF("getnewvnode error.\n"); return error; } /* Lock vnode here */ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); /* Allocate i-node */ vp->v_data = pool_get(&v7fs_node_pool, PR_WAITOK); memset(vp->v_data, 0, sizeof(*v7fs_node)); v7fs_node = vp->v_data; mutex_enter(&mntvnode_lock); LIST_INSERT_HEAD(&v7fsmount->v7fs_node_head, v7fs_node, link); mutex_exit(&mntvnode_lock); v7fs_node->vnode = vp; v7fs_node->v7fsmount = v7fsmount; v7fs_node->inode = inode;/*structure copy */ v7fs_node->lockf = NULL; /* advlock */ genfs_node_init(vp, &v7fs_genfsops); uvm_vnp_setsize(vp, v7fs_inode_filesize(&inode)); if (ino == V7FS_ROOT_INODE) { vp->v_type = VDIR; vp->v_vflag |= VV_ROOT; } else { vp->v_type = v7fs_mode_to_vtype(inode.mode); if (vp->v_type == VBLK || vp->v_type == VCHR) { dev_t rdev = inode.device; vp->v_op = v7fs_specop_p; spec_node_init(vp, rdev); } else if (vp->v_type == VFIFO) { vp->v_op = v7fs_fifoop_p; } } *vpp = vp; return 0; }