static int zpl_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { boolean_t issnap = ITOZSB(dentry->d_inode)->z_issnap; int error; /* * Ensure MNT_SHRINKABLE is set on snapshots to ensure they are * unmounted automatically with the parent file system. This * is done on the first getattr because it's not easy to get the * vfsmount structure at mount time. This call path is explicitly * marked unlikely to avoid any performance impact. FWIW, ext4 * resorts to a similar trick for sysadmin convenience. */ if (unlikely(issnap && !(mnt->mnt_flags & MNT_SHRINKABLE))) mnt->mnt_flags |= MNT_SHRINKABLE; error = -zfs_getattr_fast(dentry->d_inode, stat); ASSERT3S(error, <=, 0); return (error); }
/* ARGSUSED */ int zfsctl_snapdir_remove(struct inode *dip, char *name, cred_t *cr, int flags) { zfs_sb_t *zsb = ITOZSB(dip); char *snapname, *real; int error; ZFS_ENTER(zsb); snapname = kmem_alloc(MAXNAMELEN, KM_SLEEP); real = kmem_alloc(MAXNAMELEN, KM_SLEEP); if (zsb->z_case == ZFS_CASE_INSENSITIVE) { error = dmu_snapshot_realname(zsb->z_os, name, real, MAXNAMELEN, NULL); if (error == 0) { name = real; } else if (error != ENOTSUP) { goto out; } } error = zfsctl_snapshot_zname(dip, name, MAXNAMELEN, snapname); if (!error) error = zfs_secpolicy_destroy_perms(snapname, cr); if (error) goto out; error = zfsctl_unmount_snapshot(zsb, name, MNT_FORCE); if ((error == 0) || (error == ENOENT)) error = dmu_objset_destroy(snapname, B_FALSE); out: kmem_free(snapname, MAXNAMELEN); kmem_free(real, MAXNAMELEN); ZFS_EXIT(zsb); return (error); }
static int __zpl_xattr_acl_set_default(struct inode *ip, const char *name, const void *value, size_t size, int flags) { struct posix_acl *acl; int type = ACL_TYPE_DEFAULT; int error = 0; /* xattr_resolve_name will do this for us if this is defined */ #ifndef HAVE_XATTR_HANDLER_NAME if (strcmp(name, "") != 0) return (-EINVAL); #endif if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIXACL) return (-EOPNOTSUPP); if (!zpl_inode_owner_or_capable(ip)) return (-EPERM); if (value) { acl = zpl_acl_from_xattr(value, size); if (IS_ERR(acl)) return (PTR_ERR(acl)); else if (acl) { error = zpl_posix_acl_valid(ip, acl); if (error) { zpl_posix_acl_release(acl); return (error); } } } else { acl = NULL; } error = zpl_set_acl(ip, acl, type); zpl_posix_acl_release(acl); return (error); }
/* * When a .zfs/snapshot/<snapshot> inode is evicted they must be removed * from the snapshot list. This will normally happen as part of the auto * unmount, however in the case of a manual snapshot unmount this will be * the only notification we receive. */ void zfsctl_snapdir_inactive(struct inode *ip) { zfs_sb_t *zsb = ITOZSB(ip); zfs_snapentry_t *sep, *next; mutex_enter(&zsb->z_ctldir_lock); sep = avl_first(&zsb->z_ctldir_snaps); while (sep != NULL) { next = AVL_NEXT(&zsb->z_ctldir_snaps, sep); if (sep->se_inode == ip) { avl_remove(&zsb->z_ctldir_snaps, sep); taskq_cancel_id(zfs_expire_taskq, sep->se_taskqid); zfsctl_sep_free(sep); break; } sep = next; } mutex_exit(&zsb->z_ctldir_lock); }
int zpl_chmod_acl(struct inode *ip) { struct posix_acl *acl; int error; if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIXACL) return (0); if (S_ISLNK(ip->i_mode)) return (-EOPNOTSUPP); acl = zpl_get_acl(ip, ACL_TYPE_ACCESS); if (IS_ERR(acl) || !acl) return (PTR_ERR(acl)); error = posix_acl_chmod(&acl,GFP_KERNEL, ip->i_mode); if (!error) error = zpl_set_acl(ip,ACL_TYPE_ACCESS, acl); zpl_posix_acl_release(acl); return (error); }
static int zpl_xattr_filldir(xattr_filldir_t *xf, const char *name, int name_len) { if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) if (!(ITOZSB(xf->inode)->z_flags & ZSB_XATTR)) return (0); if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) if (!capable(CAP_SYS_ADMIN)) return (0); /* When xf->buf is NULL only calculate the required size. */ if (xf->buf) { if (xf->offset + name_len + 1 > xf->size) return (-ERANGE); memcpy(xf->buf + xf->offset, name, name_len); xf->buf[xf->offset + name_len] = '\0'; } xf->offset += (name_len + 1); return (0); }
int zfsctl_mount_snapshot(struct path *path, int flags) { struct dentry *dentry = path->dentry; struct inode *ip = dentry->d_inode; zfs_sb_t *zsb = ITOZSB(ip); char *full_name, *full_path; zfs_snapentry_t *sep; zfs_snapentry_t search; char *argv[] = { "/bin/sh", "-c", NULL, NULL }; char *envp[] = { NULL }; int error; ZFS_ENTER(zsb); full_name = kmem_zalloc(MAXNAMELEN, KM_SLEEP); full_path = kmem_zalloc(PATH_MAX, KM_SLEEP); error = zfsctl_snapshot_zname(ip, dname(dentry), MAXNAMELEN, full_name); if (error) goto error; error = zfsctl_snapshot_zpath(path, PATH_MAX, full_path); if (error) goto error; /* * Attempt to mount the snapshot from user space. Normally this * would be done using the vfs_kern_mount() function, however that * function is marked GPL-only and cannot be used. On error we * careful to log the real error to the console and return EISDIR * to safely abort the automount. This should be very rare. */ argv[2] = kmem_asprintf(SET_MOUNT_CMD, full_name, full_path); error = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC); strfree(argv[2]); if (error) { printk("ZFS: Unable to automount %s at %s: %d\n", full_name, full_path, error); error = EISDIR; goto error; } mutex_enter(&zsb->z_ctldir_lock); /* * Ensure a previous entry does not exist, if it does safely remove * it any cancel the outstanding expiration. This can occur when a * snapshot is manually unmounted and then an automount is triggered. */ search.se_name = full_name; sep = avl_find(&zsb->z_ctldir_snaps, &search, NULL); if (sep) { avl_remove(&zsb->z_ctldir_snaps, sep); taskq_cancel_id(zfs_expire_taskq, sep->se_taskqid); zfsctl_sep_free(sep); } sep = zfsctl_sep_alloc(); sep->se_name = full_name; sep->se_path = full_path; sep->se_inode = ip; avl_add(&zsb->z_ctldir_snaps, sep); sep->se_taskqid = taskq_dispatch_delay(zfs_expire_taskq, zfsctl_expire_snapshot, sep, TQ_SLEEP, ddi_get_lbolt() + zfs_expire_snapshot * HZ); mutex_exit(&zsb->z_ctldir_lock); error: if (error) { kmem_free(full_name, MAXNAMELEN); kmem_free(full_path, PATH_MAX); } ZFS_EXIT(zsb); return (error); }
/*ARGSUSED*/ int zfsctl_snapdir_rename(struct inode *sdip, char *sname, struct inode *tdip, char *tname, cred_t *cr, int flags) { zfs_sb_t *zsb = ITOZSB(sdip); zfs_snapentry_t search, *sep; avl_index_t where; char *to, *from, *real; int error; ZFS_ENTER(zsb); to = kmem_alloc(MAXNAMELEN, KM_SLEEP); from = kmem_alloc(MAXNAMELEN, KM_SLEEP); real = kmem_alloc(MAXNAMELEN, KM_SLEEP); if (zsb->z_case == ZFS_CASE_INSENSITIVE) { error = dmu_snapshot_realname(zsb->z_os, sname, real, MAXNAMELEN, NULL); if (error == 0) { sname = real; } else if (error != ENOTSUP) { goto out; } } error = zfsctl_snapshot_zname(sdip, sname, MAXNAMELEN, from); if (!error) error = zfsctl_snapshot_zname(tdip, tname, MAXNAMELEN, to); if (!error) error = zfs_secpolicy_rename_perms(from, to, cr); if (error) goto out; /* * Cannot move snapshots out of the snapdir. */ if (sdip != tdip) { error = EINVAL; goto out; } /* * No-op when names are identical. */ if (strcmp(sname, tname) == 0) { error = 0; goto out; } mutex_enter(&zsb->z_ctldir_lock); error = dmu_objset_rename(from, to, B_FALSE); if (error) goto out_unlock; search.se_name = (char *)sname; sep = avl_find(&zsb->z_ctldir_snaps, &search, &where); if (sep) zfsctl_rename_snap(zsb, sep, tname); out_unlock: mutex_exit(&zsb->z_ctldir_lock); out: kmem_free(from, MAXNAMELEN); kmem_free(to, MAXNAMELEN); kmem_free(real, MAXNAMELEN); ZFS_EXIT(zsb); return (error); }
int zpl_set_acl(struct inode *ip, int type, struct posix_acl *acl) { struct super_block *sb = ITOZSB(ip)->z_sb; char *name, *value = NULL; int error = 0; size_t size = 0; if (S_ISLNK(ip->i_mode)) return (-EOPNOTSUPP); switch(type) { case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; if (acl) { zpl_equivmode_t mode = ip->i_mode; error = posix_acl_equiv_mode(acl, &mode); if (error < 0) { return (error); } else { /* * The mode bits will have been set by * ->zfs_setattr()->zfs_acl_chmod_setattr() * using the ZFS ACL conversion. If they * differ from the Posix ACL conversion dirty * the inode to write the Posix mode bits. */ if (ip->i_mode != mode) { ip->i_mode = mode; ip->i_ctime = current_fs_time(sb); mark_inode_dirty(ip); } if (error == 0) acl = NULL; } } break; case ACL_TYPE_DEFAULT: name = POSIX_ACL_XATTR_DEFAULT; if (!S_ISDIR(ip->i_mode)) return (acl ? -EACCES : 0); break; default: return (-EINVAL); } if (acl) { size = posix_acl_xattr_size(acl->a_count); value = kmem_alloc(size, KM_SLEEP); error = zpl_acl_to_xattr(acl, value, size); if (error < 0) { kmem_free(value, size); return (error); } } error = zpl_xattr_set(ip, name, value, size, 0); if (value) kmem_free(value, size); if (!error) { if (acl) zpl_set_cached_acl(ip, type, acl); else zpl_forget_cached_acl(ip, type); } return (error); }
/* * Extended user attributes * * "Extended user attributes may be assigned to files and directories for * storing arbitrary additional information such as the mime type, * character set or encoding of a file. The access permissions for user * attributes are defined by the file permission bits: read permission * is required to retrieve the attribute value, and writer permission is * required to change it. * * The file permission bits of regular files and directories are * interpreted differently from the file permission bits of special * files and symbolic links. For regular files and directories the file * permission bits define access to the file's contents, while for * device special files they define access to the device described by * the special file. The file permissions of symbolic links are not * used in access checks. These differences would allow users to * consume filesystem resources in a way not controllable by disk quotas * for group or world writable special files and directories. * * For this reason, extended user attributes are allowed only for * regular files and directories, and access to extended user attributes * is restricted to the owner and to users with appropriate capabilities * for directories with the sticky bit set (see the chmod(1) manual page * for an explanation of the sticky bit)." - xattr(7) * * ZFS allows extended user attributes to be disabled administratively * by setting the 'xattr=off' property on the dataset. */ static int __zpl_xattr_user_list(struct inode *ip, char *list, size_t list_size, const char *name, size_t name_len) { return (ITOZSB(ip)->z_flags & ZSB_XATTR); }