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; }
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; }
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; }
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; }
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; }
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, };
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"); }
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); }