示例#1
0
/* Reload disk inode information */
int
v7fs_vnode_reload(struct mount *mp, struct vnode *vp)
{
    struct v7fs_mount *v7fsmount = mp->mnt_data;
    struct v7fs_self *fs = v7fsmount->core;
    struct v7fs_node *v7fs_node;
    struct v7fs_inode *inode = &((struct v7fs_node *)vp->v_data)->inode;
    int target_ino = inode->inode_number;
    int error = 0;

    DPRINTF("#%d\n", target_ino);
    mutex_enter(&mntvnode_lock);
    for (v7fs_node = LIST_FIRST(&v7fsmount->v7fs_node_head);
            v7fs_node != NULL; v7fs_node = LIST_NEXT(v7fs_node, link)) {
        inode = &v7fs_node->inode;
        if (!v7fs_inode_allocated(inode)) {
            continue;
        }
        if (inode->inode_number == target_ino) {
            error = v7fs_inode_load(fs, &v7fs_node->inode,
                                    target_ino);
            DPRINTF("sync #%d error=%d\n", target_ino, error);
            break;
        }
    }
    mutex_exit(&mntvnode_lock);

    return error;
}
static int
allocate(struct v7fs_self *fs, struct v7fs_inode *parent_inode, fsnode *node,
    dev_t dev, struct v7fs_inode *inode)
{
	int error;
	v7fs_ino_t ino;
	struct v7fs_fileattr attr;

	memset(inode, 0, sizeof(*inode));

	attr_setup(node, &attr);
	attr.device = dev;
	if ((error = v7fs_file_allocate(fs, parent_inode, node->name, &attr,
	    &ino))) {
		errno = error;
		warn("%s", node->name);
		return error;
	}
	node->inode->ino = ino;
	node->inode->flags |= FI_ALLOCATED;
	if ((error = v7fs_inode_load(fs, inode, ino))) {
		errno = error;
		warn("%s", node->name);
		return error;
	}

	return 0;
}
示例#3
0
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_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;
}
示例#6
0
int
readdir_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, size_t sz)
{
	struct v7fs_readdir_arg *p = (struct v7fs_readdir_arg *)ctx;
	struct v7fs_dirent *dir;
	struct dirent *dp = p->dp;
	struct v7fs_inode inode;
	char filename[V7FS_NAME_MAX + 1];
	int i, n;
	int error = 0;
	void *buf;

	if (!(buf = scratch_read(fs, blk)))
		return EIO;
	dir = (struct v7fs_dirent *)buf;

	n = sz / sizeof(*dir);

	for (i = 0; (i < n) && (p->cnt < p->end); i++, dir++, p->cnt++) {
		if (p->cnt < p->start)
			continue;

		if ((error = v7fs_inode_load(fs, &inode, dir->inode_number)))
			break;

		v7fs_dirent_filename(filename, dir->name);

		DPRINTF("inode=%d name=%s %s\n", dir->inode_number, filename,
		    v7fs_inode_isdir(&inode) ? "DIR" : "FILE");
		memset(dp, 0, sizeof(*dp));
		dp->d_fileno = dir->inode_number;
		dp->d_type = v7fs_mode_to_d_type(inode.mode);
		dp->d_namlen = strlen(filename);
		strcpy(dp->d_name, filename);
		dp->d_reclen = sizeof(*dp);
		if ((error = uiomove(dp, dp->d_reclen, p->uio))) {
			DPRINTF("uiomove failed.\n");
			break;
		}
	}
	scratch_free(fs, buf);

	if (p->cnt == p->end)
		return V7FS_ITERATOR_BREAK;

	return error;
}
示例#7
0
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;
}
static int
file_copy(struct v7fs_self *fs, struct v7fs_inode *parent_inode, fsnode *node,
	const char *filepath)
{
	struct v7fs_inode inode;
	const char *errmsg;
	fsinode *fnode = node->inode;
	int error = 0;
	int fd;

	/* Check hard-link */
	if ((fnode->nlink > 1) && (fnode->flags & FI_ALLOCATED)) {
		if ((error = v7fs_inode_load(fs, &inode, fnode->ino))) {
			errmsg = "inode load";
			goto err_exit;
		}
		if ((error = v7fs_file_link(fs, parent_inode, &inode,
			    node->name))) {
			errmsg = "hard link";
			goto err_exit;
		}
		return 0;
	}

	/* Allocate file */
	if ((error = allocate(fs, parent_inode, node, 0, &inode))) {
		errmsg = "file allocate";
		goto err_exit;
	}
	if ((error = v7fs_datablock_expand(fs, &inode, fnode->st.st_size))) {
		errmsg = "datablock expand";
		goto err_exit;
	}

	/* Data copy */
	if ((fd = open(filepath, O_RDONLY)) == -1) {
		error = errno;
		errmsg = "source file";
		goto err_exit;
	}

	error = v7fs_datablock_foreach(fs, &inode, copy_subr,
	    &(struct copy_arg){ .fd = fd });
示例#9
0
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_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;
}
示例#11
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;
}