Example #1
0
static struct dentry *
snap_lookup(struct inode *dir,struct dentry *dentry, struct nameidata *nd)
{
	struct inode *inode = NULL;
	uint64_t id;
	vnode_t *dir_vp = NULL;
	vfs_t *vfsp = NULL;
	struct dentry *dentry_to_return = NULL;
	
	dir_vp = LZFS_ITOV(dir);
	vfsp = dir_vp->v_vfsp;
	if (dentry->d_name.len >= MAXNAMELEN) {
        return ERR_PTR(-ENAMETOOLONG);
	}
	if (!(id = zfs_snapname_to_id(vfsp->vfs_data, dentry->d_name.name))) {
		d_add(dentry, NULL);
		return NULL;
	}
	inode = lzfs_snapshot_iget(vfsp->vfs_super,
						LZFS_ZFSCTL_INO_SHARES - id);
	if (unlikely(IS_ERR(inode))) {
		return ERR_CAST(inode);
	}
	dentry_to_return = d_splice_alias(inode, dentry);	
	return dentry_to_return;
}
Example #2
0
struct dentry *lzfs_get_parent(struct dentry *child)
{
	vnode_t *vcp = LZFS_ITOV(child->d_inode);
	vnode_t *vp;
	int error = 0;
	struct dentry *dentry = NULL;
	const struct cred *cred = get_current_cred();

	SENTRY;
	error = zfs_lookup(vcp, "..", &vp, NULL, 0 , NULL,
			(struct cred *) cred, NULL, NULL, NULL);

	put_cred(cred);
	tsd_exit();
	SEXIT;
	if (error) {
		if (error == ENOENT) {
			printk(KERN_WARNING "Try to get new dentry \n");
			return d_splice_alias(NULL, dentry);
		} else {
			printk(KERN_WARNING "Unable to get dentry \n");
			return ERR_PTR(-error);
		}
	}

	if (LZFS_VTOI(vp))
		dentry = d_obtain_alias(LZFS_VTOI(vp));
	return dentry;
}
Example #3
0
struct inode *
lzfs_snapshot_iget(struct super_block *sb, unsigned long ino)
{
	vnode_t *vp = NULL; 
	struct inode *inode;

	inode = iget_locked(sb, ino);
	if (!inode)
		return ERR_PTR(-ENOMEM);
	if (!(inode->i_state & I_NEW))
		return inode;
	vp = LZFS_ITOV(inode);
	mutex_enter(&vp->v_lock);
	vp->v_count = 1;
	mutex_exit(&vp->v_lock);
	inode->i_mode |= (S_IFDIR | S_IRWXU);
#ifdef HAVE_CRED_STRUCT
	inode->i_uid = current->cred->uid;
	inode->i_gid = current->cred->gid;
#else
	inode->i_uid = current->uid;
	inode->i_gid = current->gid;
#endif
	inode->i_version = 1;
	inode->i_op = &snap_mount_dir_inode_operations;
	inode->i_fop = &simple_dir_operations;
	inode->i_sb = sb;
	inode->i_private = inode;
	unlock_new_inode(inode);
	return inode;
}		
Example #4
0
static int
snap_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
	vnode_t *dir_vp;
	struct inode *dir = filp->f_path.dentry->d_inode;
	char snapname[MAXNAMELEN];
	uint64_t id, cookie;
	boolean_t case_conflict;
	int error, rc;
	vfs_t *vfsp = NULL;

	dir_vp = LZFS_ITOV(dir);
	vfsp = dir_vp->v_vfsp; 
	cookie = filp->f_pos;
	rc = error = 0;
	if (!filp->f_pos) {
		rc = filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR);
		if(rc)
			goto done;
		filp->f_pos++;
	}
	if (filp->f_pos == 1) {
		rc = filldir(dirent, "..", 2, filp->f_pos,
					parent_ino(filp->f_path.dentry), DT_DIR);
		if(rc) {
			goto done;
		}
		filp->f_pos++;
	}

	while (!(error = zfs_snapshot_list_next(vfsp->vfs_data, snapname, &id,
					       &cookie, &case_conflict))) {
		ASSERT(id > 0);
		rc = filldir(dirent, snapname, strlen(snapname), filp->f_pos, 
					LZFS_ZFSCTL_INO_SHARES - id, DT_DIR);
		filp->f_pos = cookie; // next position ptr
	}
	if (error) {
		if (error == ENOENT) {
			return (0);
		}
		return PTR_ERR(ERR_PTR(-error));
	}

done:
	return 0;
}
Example #5
0
static int lzfs_encode_fh(struct dentry *dentry, u32 *fh, int *max_len, int connectable)
{
	lzfs_fid_t  *lzfid = (lzfs_fid_t *)fh;
	struct inode *inode = dentry->d_inode;
	int lfid_type = LZFS_FILEID_INO64_GEN;
	vnode_t *vp;
	int error = 0;

	SENTRY;
	lzfid->fid_len = *max_len;
	if (!(S_ISDIR(inode->i_mode) || !connectable)) {
		spin_lock(&dentry->d_lock);
		inode = dentry->d_parent->d_inode;
		spin_unlock(&dentry->d_lock);
		lfid_type = LZFS_FILEID_INO64_GEN_PARENT;
	}
        /* If inode number is -1 then we looking into .zfs(ZFS control
         * directory). Traversing .zfs from the NFS is not supported yet.
         */
        if (inode->i_ino == -1) {
            return 255;
        }

	vp = LZFS_ITOV(inode);
	error = zfs_fid( vp, lzfid, 0);
	tsd_exit();
	SEXIT;

	if (error) {
		printk(KERN_WARNING "Unable to get file handle \n");
		return 255;
	}

	*max_len = lzfid->fid_len;

	return lfid_type;
}
Example #6
0
static int
lzfs_xattr_security_set(struct dentry *dentry, const char *name,
                    const void *value, size_t size, int flags, int type)
#endif
{
	vnode_t *vp;
	vnode_t *dvp;
	vnode_t *xvp;
	vattr_t *vap;
	int err = 0;
	const struct cred *cred = get_current_cred();
	struct iovec iov = {
		.iov_base = (void *) value,
		.iov_len  = size,
	};

	char *xattr_name = NULL;
	uio_t uio = {
		.uio_iov = &iov,
		.uio_resid = size,
		.uio_iovcnt = 1,
		.uio_loffset = (offset_t)0,
		.uio_limit = MAXOFFSET_T,
		.uio_segflg = UIO_SYSSPACE,
	};

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
	dvp = LZFS_ITOV(inode);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)
	dvp = LZFS_ITOV(dentry->d_inode);
#endif
	err = zfs_lookup(dvp, NULL, &vp, NULL, LOOKUP_XATTR | CREATE_XATTR_DIR,
			 NULL, (struct cred *) cred, NULL, NULL, NULL);
	if(err) {
		return -err;
	}
	
	if(!value) {
		err =zfs_remove(vp, (char *) name,
			(struct cred *)cred, NULL, 0);
		return -err;
	}

	vap = kmalloc(sizeof(vattr_t), GFP_KERNEL);
	ASSERT(vap != NULL);
	memset(vap, 0, sizeof(vap));
	vap->va_type = VREG;
	vap->va_mode = 0644;
	vap->va_mask = AT_TYPE|AT_MODE;
	vap->va_uid = current_fsuid();
	vap->va_gid = current_fsgid();
	xattr_name = kzalloc(strlen(name) + 10, GFP_KERNEL);
	xattr_name = strncpy(xattr_name, "security.", 9);
	xattr_name = strncat(xattr_name, name, strlen(name));

	err = zfs_create(vp, xattr_name, vap, 0, 0644,
			&xvp, (struct cred *)cred, 0, NULL, NULL);
	kfree(vap);
	kfree(xattr_name);
	if(err) {
		return -err;
	}
	err = zfs_write(xvp, &uio, 0, (cred_t *)cred, NULL);
	put_cred(cred);
	if(err) {
		return -err;
	}
	return -err;
}

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
static size_t
lzfs_xattr_security_list(struct inode *inode, char *list, size_t list_size,
				const char *name, size_t name_len)
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)
static size_t
lzfs_xattr_security_list(struct dentry *dentry, char *list, size_t list_size,
				const char *name, size_t name_len, int type)
#endif
{

	const size_t total_len = name_len + 1;

	if (list && total_len <= list_size) {
		memcpy(list, name, name_len);
		list[name_len] = '\0';
	}
	return total_len;
}

int
lzfs_init_security(struct dentry *dentry, struct inode *dir)
{
	int err;
	size_t len;
	void *value;
	char *name;

	err = security_inode_init_security(dentry->d_inode, dir, &name, &value, &len);
	if (err) {
		if (err == -EOPNOTSUPP)
			return 0;
		return err;
	}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
	err = lzfs_xattr_security_set(dentry->d_inode, name, value, len, 0);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)
	err = lzfs_xattr_security_set(dentry, name, value, len, 0, 0);
#endif
	kfree(name);
	kfree(value);
	return err;
}

struct xattr_handler lzfs_xattr_security_handler = {
	.prefix = XATTR_SECURITY_PREFIX,
	.list   = lzfs_xattr_security_list,
	.get    = lzfs_xattr_security_get,
	.set    = lzfs_xattr_security_set,
};
Example #7
0
void
lzfs_zfsctl_create(vfs_t *vfsp)
{
	vnode_t *vp_zfsctl_dir = NULL, *vp_snap_dir = NULL;
	struct dentry *zfsctl_dir_dentry = NULL, *snap_dir_dentry = NULL;
	struct inode *inode_ctldir = NULL, *inode_snapdir = NULL;
	timestruc_t now;

	inode_ctldir = iget_locked(vfsp->vfs_super, LZFS_ZFSCTL_INO_ROOT);
	ASSERT(inode_ctldir != NULL);
	vp_zfsctl_dir = LZFS_ITOV(inode_ctldir);
	gethrestime(&now);
	ASSERT(inode_ctldir->i_state & I_NEW);
	mutex_enter(&vp_zfsctl_dir->v_lock);
	vp_zfsctl_dir->v_count = 1;
	VN_SET_VFS_TYPE_DEV(vp_zfsctl_dir, vfsp, VDIR, 0);
	bcopy(&now, &(vp_zfsctl_dir->v_inode.i_ctime), 
			sizeof (timestruc_t));
	bcopy(&now, &(vp_zfsctl_dir->v_inode.i_atime),
	      sizeof (timestruc_t));
	bcopy(&now,&(vp_zfsctl_dir->v_inode.i_mtime),sizeof (timestruc_t));
#ifdef HAVE_CRED_STRUCT
	inode_ctldir->i_uid = current->cred->uid;
	inode_ctldir->i_gid = current->cred->gid;
#else
	inode_ctldir->i_uid = current->uid;
	inode_ctldir->i_gid = current->gid;
#endif
	inode_ctldir->i_version = 1;
	inode_ctldir->i_mode |= (S_IFDIR | S_IRWXU);
	inode_ctldir->i_op = &zfsctl_dir_inode_operations;
	inode_ctldir->i_fop = &zfsctl_dir_file_operations;
	ASSERT(vfsp);
	inode_ctldir->i_sb = vfsp->vfs_super;
	ASSERT(vfsp->vfs_super);
	ASSERT(vfsp->vfs_super->s_root);
	unlock_new_inode(inode_ctldir);
	zfsctl_dir_dentry = d_alloc_name(vfsp->vfs_super->s_root, 
					 ZFS_CTLDIR_NAME);
	if (zfsctl_dir_dentry) {
	  d_add(zfsctl_dir_dentry, LZFS_VTOI(vp_zfsctl_dir));
	  vfsp->zfsctl_dir_dentry = zfsctl_dir_dentry;
	} else {
		goto dentry_out;
	}
	set_zfsvfs_ctldir(vfsp->vfs_data, vp_zfsctl_dir);
	mutex_exit(&vp_zfsctl_dir->v_lock);
	inode_snapdir = iget_locked(vfsp->vfs_super, LZFS_ZFSCTL_INO_SNAPDIR);
	ASSERT(inode_snapdir != NULL);
	ASSERT(inode_snapdir->i_state & I_NEW);
	vp_snap_dir = LZFS_ITOV(inode_snapdir);
	gethrestime(&now);
	vfsp->vfs_snap_dir = vp_snap_dir;
	mutex_enter(&vp_snap_dir->v_lock);
	vp_snap_dir->v_count = 1;
	VN_SET_VFS_TYPE_DEV(vp_snap_dir, vfsp, VDIR, 0);
	bcopy(&now,&(vp_snap_dir->v_inode.i_ctime),sizeof (timestruc_t));
	bcopy(&now,&(vp_snap_dir->v_inode.i_atime),sizeof (timestruc_t));
	bcopy(&now,&(vp_snap_dir->v_inode.i_mtime),sizeof (timestruc_t));
#ifdef HAVE_CRED_STRUCT
	inode_snapdir->i_uid = current->cred->uid;
	inode_snapdir->i_gid = current->cred->gid;
#else
	inode_snapdir->i_uid = current->uid;
	inode_snapdir->i_gid = current->gid;
#endif
	inode_snapdir->i_version = 1;
	inode_snapdir->i_mode |= (S_IFDIR | S_IRWXU);
	inode_snapdir->i_op = &snap_dir_inode_operations;
	inode_snapdir->i_fop = &snap_dir_file_operations;
	inode_snapdir->i_sb = vfsp->vfs_super;
	unlock_new_inode(inode_snapdir);
	ASSERT(zfsctl_dir_dentry);
	snap_dir_dentry = d_alloc_name(zfsctl_dir_dentry, ZFS_SNAPDIR_NAME);
	if (snap_dir_dentry) {
		d_add(snap_dir_dentry, LZFS_VTOI(vp_snap_dir));
		vfsp->snap_dir_dentry = snap_dir_dentry;
		mutex_exit(&vp_snap_dir->v_lock);
	} else {
		goto dentry_out;
	}
	return;
dentry_out:
	// free vnode
	vn_free(vp_zfsctl_dir);
	ASSERT(0 && "TODO");
}
Example #8
0
static void*
snap_mountpoint_follow_link(struct dentry *dentry, struct nameidata *nd)
{
	struct vfsmount *mnt = ERR_PTR(-ENOENT);
	vnode_t *dir_vp = NULL;
	char *snapname = NULL;
	char *zfs_fs_name = NULL;
	int rc = 0;
	vfs_t *vfsp = NULL;
	
	ASSERT(dentry->d_parent);
	dir_vp = LZFS_ITOV(dentry->d_parent->d_inode);
	vfsp = dir_vp->v_vfsp;
	ASSERT(vfsp);
	zfs_fs_name = kzalloc(MAXNAMELEN, KM_SLEEP);
	dput(nd->path.dentry);
	nd->path.dentry = dget(dentry);
	zfs_fs_name_fn(vfsp->vfs_data, zfs_fs_name);
	snapname = kzalloc(strlen(zfs_fs_name) +
			strlen(dentry->d_name.name) + 2, KM_SLEEP);
	snapname = strncpy(snapname, zfs_fs_name, strlen(zfs_fs_name) + 1);
	snapname = strcat(snapname, "@");
	snapname = strcat(snapname, dentry->d_name.name);
	mnt = vfs_kern_mount(&lzfs_fs_type, 0, snapname, NULL);
	((vfs_t *)mnt->mnt_sb->s_fs_info)->vfs_mntpt = dentry;
	mntget(mnt);
	rc = PTR_ERR(mnt);
	if (IS_ERR(mnt)) {
		goto out_err;
	}
	mnt->mnt_mountpoint = dentry;
	ASSERT(nd);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
	rc = do_add_mount(mnt, nd,
	nd->path.mnt->mnt_flags | MNT_READONLY, NULL);
#else
	rc = do_add_mount(mnt, &nd->path,
	nd->path.mnt->mnt_flags | MNT_READONLY, NULL);
#endif	
	switch (rc) {
	case 0:
		path_put(&nd->path);
		nd->path.mnt = mnt;
		nd->path.dentry = dget(mnt->mnt_root);
		break;
	case -EBUSY: 
		
		nd->path.dentry = dget(mnt->mnt_root);
		/* someone else made a mount here whilst we were busy */

#ifdef HAVE_2ARGS_FOLLOW_DOWN		/* for kernel version < 2.6.31 */		
		while (d_mountpoint(nd->path.dentry) &&
			follow_down(&mnt, &nd->path.dentry)) {
			;	
		 }
#else
		while (d_mountpoint(nd->path.dentry) &&
			follow_down(&nd->path)) {
			;
		 }
#endif
		 rc = 0;
	default:
		mntput(mnt);
		break;
	}
	kfree(zfs_fs_name);
	kfree(snapname);
	return ERR_PTR(rc);
out_err:
	path_put(&nd->path);
	kfree(zfs_fs_name);
	kfree(snapname);
	return ERR_PTR(rc);
}