* Copyright (c) 2014, 2016 Joyent, Inc. All rights reserved.
* Copyright 2016 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2014, Joyent, Inc. All rights reserved.
- * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
* Copyright (c) 2013 Steven Hartland. All rights reserved.
* Copyright (c) 2014 Integros [integros.com]
#include <sys/zfeature.h>
#include <sys/zcp.h>
#include <sys/zio_checksum.h>
+#include <sys/vdev_removal.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
ZFS_DELEG_PERM_USEROBJQUOTA,
ZFS_DELEG_PERM_GROUPOBJUSED,
ZFS_DELEG_PERM_GROUPOBJQUOTA,
+ ZFS_DELEG_PERM_PROJECTUSED,
+ ZFS_DELEG_PERM_PROJECTQUOTA,
+ ZFS_DELEG_PERM_PROJECTOBJUSED,
+ ZFS_DELEG_PERM_PROJECTOBJQUOTA,
};
static int zfs_ioc_userspace_upgrade(zfs_cmd_t *zc);
-static int zfs_ioc_userobjspace_upgrade(zfs_cmd_t *zc);
+static int zfs_ioc_id_quota_upgrade(zfs_cmd_t *zc);
static int zfs_check_settable(const char *name, nvpair_t *property,
cred_t *cr);
static int zfs_check_clearable(char *dataset, nvlist_t *props,
return (error);
}
+/* ARGSUSED */
+static int
+zfs_secpolicy_remap(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+ return (zfs_secpolicy_write_perms(zc->zc_name,
+ ZFS_DELEG_PERM_REMAP, cr));
+}
+
/* ARGSUSED */
static int
zfs_secpolicy_destroy_bookmarks(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
zc->zc_objset_type == ZFS_PROP_USEROBJQUOTA) {
if (zc->zc_guid == crgetuid(cr))
return (0);
- } else {
+ } else if (zc->zc_objset_type == ZFS_PROP_GROUPUSED ||
+ zc->zc_objset_type == ZFS_PROP_GROUPQUOTA ||
+ zc->zc_objset_type == ZFS_PROP_GROUPOBJUSED ||
+ zc->zc_objset_type == ZFS_PROP_GROUPOBJQUOTA) {
if (groupmember(zc->zc_guid, cr))
return (0);
}
+ /* else is for project quota/used */
}
return (zfs_secpolicy_write_perms(zc->zc_name,
return (error);
}
-static int
+int
getzfsvfs(const char *dsname, zfsvfs_t **zfvp)
{
objset_t *os;
int error = 0;
if (getzfsvfs(name, zfvp) != 0)
- error = zfsvfs_create(name, zfvp);
+ error = zfsvfs_create(name, B_FALSE, zfvp);
if (error == 0) {
rrm_enter(&(*zfvp)->z_teardown_lock, (writer) ? RW_WRITER :
RW_READER, tag);
spa_t *spa;
int error;
- if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
- return (error);
-
if (zc->zc_flags >= POOL_SCRUB_FLAGS_END)
return (SET_ERROR(EINVAL));
+ if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
+ return (error);
+
if (zc->zc_flags == POOL_SCRUB_PAUSE)
error = spa_scrub_pause_resume(spa, POOL_SCRUB_PAUSE);
else if (zc->zc_cookie == POOL_SCAN_NONE)
/*
* inputs:
* zc_name name of the pool
- * zc_nvlist_conf nvlist of devices to remove
- * zc_cookie to stop the remove?
+ * zc_guid guid of vdev to remove
+ * zc_cookie cancel removal
*/
static int
zfs_ioc_vdev_remove(zfs_cmd_t *zc)
error = spa_open(zc->zc_name, &spa, FTAG);
if (error != 0)
return (error);
- error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE);
+ if (zc->zc_cookie != 0) {
+ error = spa_vdev_remove_cancel(spa);
+ } else {
+ error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE);
+ }
spa_close(spa, FTAG);
return (error);
}
zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP);
(void) strcpy(zc->zc_name, dsname);
(void) zfs_ioc_userspace_upgrade(zc);
- (void) zfs_ioc_userobjspace_upgrade(zc);
+ (void) zfs_ioc_id_quota_upgrade(zc);
kmem_free(zc, sizeof (zfs_cmd_t));
}
break;
mutex_enter(&spa_namespace_lock);
if ((spa = spa_lookup(zc->zc_name)) != NULL) {
spa_configfile_set(spa, props, B_FALSE);
- spa_config_sync(spa, B_FALSE, B_TRUE);
+ spa_write_cachefile(spa, B_FALSE, B_TRUE);
}
mutex_exit(&spa_namespace_lock);
if (spa != NULL) {
return (error);
}
+/* ARGSUSED */
+static int
+zfs_ioc_remap(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
+{
+ if (strchr(fsname, '@') ||
+ strchr(fsname, '%'))
+ return (SET_ERROR(EINVAL));
+
+ return (dmu_objset_remap_indirects(fsname));
+}
+
/*
* innvl: {
* "snaps" -> { snapshot1, snapshot2 }
* Returns 0 if the argument is not a snapshot, or it is not currently a
* filesystem, or we were able to unmount it. Returns error code otherwise.
*/
-int
+void
zfs_unmount_snap(const char *snapname)
{
- int err;
-
if (strchr(snapname, '@') == NULL)
- return (0);
-
- err = zfsctl_snapshot_unmount((char *)snapname, MNT_FORCE);
- if (err != 0 && err != ENOENT)
- return (SET_ERROR(err));
+ return;
- return (0);
+ (void) zfsctl_snapshot_unmount((char *)snapname, MNT_FORCE);
}
/* ARGSUSED */
static int
zfs_unmount_snap_cb(const char *snapname, void *arg)
{
- return (zfs_unmount_snap(snapname));
+ zfs_unmount_snap(snapname);
+ return (0);
}
/*
char originname[ZFS_MAX_DATASET_NAME_LEN];
dsl_dataset_name(ds->ds_prev, originname);
dmu_objset_rele(os, FTAG);
- (void) zfs_unmount_snap(originname);
+ zfs_unmount_snap(originname);
} else {
dmu_objset_rele(os, FTAG);
}
for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
pair = nvlist_next_nvpair(snaps, pair)) {
- (void) zfs_unmount_snap(nvpair_name(pair));
+ zfs_unmount_snap(nvpair_name(pair));
}
return (dsl_destroy_snapshots_nvl(snaps, defer, outnvl));
{
char *program;
uint64_t instrlimit, memlimit;
+ boolean_t sync_flag;
nvpair_t *nvarg = NULL;
if (0 != nvlist_lookup_string(innvl, ZCP_ARG_PROGRAM, &program)) {
return (EINVAL);
}
+ if (0 != nvlist_lookup_boolean_value(innvl, ZCP_ARG_SYNC, &sync_flag)) {
+ sync_flag = B_TRUE;
+ }
if (0 != nvlist_lookup_uint64(innvl, ZCP_ARG_INSTRLIMIT, &instrlimit)) {
instrlimit = ZCP_DEFAULT_INSTRLIMIT;
}
if (memlimit == 0 || memlimit > zfs_lua_max_memlimit)
return (EINVAL);
- return (zcp_eval(poolname, program, instrlimit, memlimit,
+ return (zcp_eval(poolname, program, sync_flag, instrlimit, memlimit,
nvarg, outnvl));
}
{
int err;
- if (zc->zc_objset_type == DMU_OST_ZFS) {
- err = zfs_unmount_snap(zc->zc_name);
- if (err != 0)
- return (err);
- }
+ if (zc->zc_objset_type == DMU_OST_ZFS)
+ zfs_unmount_snap(zc->zc_name);
if (strchr(zc->zc_name, '@')) {
err = dsl_destroy_snapshot(zc->zc_name, zc->zc_defer_destroy);
(void) nvlist_lookup_string(innvl, "target", &target);
if (target != NULL) {
- int fslen = strlen(fsname);
+ const char *cp = strchr(target, '@');
- if (strncmp(fsname, target, fslen) != 0)
- return (SET_ERROR(EINVAL));
- if (target[fslen] != '@')
+ /*
+ * The snap name must contain an @, and the part after it must
+ * contain only valid characters.
+ */
+ if (cp == NULL ||
+ zfs_component_namecheck(cp + 1, NULL, NULL) != 0)
return (SET_ERROR(EINVAL));
}
{
const char *snapname = arg;
char *fullname;
- int error;
fullname = kmem_asprintf("%s@%s", fsname, snapname);
- error = zfs_unmount_snap(fullname);
+ zfs_unmount_snap(fullname);
strfree(fullname);
- return (error);
+ return (0);
}
/*
zfs_userquota_prop_prefixes[ZFS_PROP_USEROBJQUOTA];
const char *giq_prefix =
zfs_userquota_prop_prefixes[ZFS_PROP_GROUPOBJQUOTA];
+ const char *pq_prefix =
+ zfs_userquota_prop_prefixes[ZFS_PROP_PROJECTQUOTA];
+ const char *piq_prefix = zfs_userquota_prop_prefixes[\
+ ZFS_PROP_PROJECTOBJQUOTA];
if (strncmp(propname, uq_prefix,
strlen(uq_prefix)) == 0) {
} else if (strncmp(propname, giq_prefix,
strlen(giq_prefix)) == 0) {
perm = ZFS_DELEG_PERM_GROUPOBJQUOTA;
+ } else if (strncmp(propname, pq_prefix,
+ strlen(pq_prefix)) == 0) {
+ perm = ZFS_DELEG_PERM_PROJECTQUOTA;
+ } else if (strncmp(propname, piq_prefix,
+ strlen(piq_prefix)) == 0) {
+ perm = ZFS_DELEG_PERM_PROJECTOBJQUOTA;
} else {
- /* USERUSED and GROUPUSED are read-only */
+ /* {USER|GROUP|PROJECT}USED are read-only */
return (SET_ERROR(EINVAL));
}
}
/*
- * Retrieve a single {user|group}{used|quota}@... property.
+ * Retrieve a single {user|group|project}{used|quota}@... property.
*
* inputs:
* zc_name name of filesystem
* objset needs to be closed & reopened (to grow the
* objset_phys_t). Suspend/resume the fs will do that.
*/
- dsl_dataset_t *ds;
+ dsl_dataset_t *ds, *newds;
ds = dmu_objset_ds(zfsvfs->z_os);
error = zfs_suspend_fs(zfsvfs);
if (error == 0) {
- dmu_objset_refresh_ownership(zfsvfs->z_os,
+ dmu_objset_refresh_ownership(ds, &newds,
B_TRUE, zfsvfs);
- error = zfs_resume_fs(zfsvfs, ds);
+ error = zfs_resume_fs(zfsvfs, newds);
}
}
if (error == 0)
* none
*/
static int
-zfs_ioc_userobjspace_upgrade(zfs_cmd_t *zc)
+zfs_ioc_id_quota_upgrade(zfs_cmd_t *zc)
{
objset_t *os;
int error;
if (error != 0)
return (error);
- if (dmu_objset_userobjspace_upgradable(os)) {
+ if (dmu_objset_userobjspace_upgradable(os) ||
+ dmu_objset_projectquota_upgradable(os)) {
mutex_enter(&os->os_upgrade_lock);
if (os->os_upgrade_id == 0) {
/* clear potential error code and retry */
os->os_upgrade_status = 0;
mutex_exit(&os->os_upgrade_lock);
- dmu_objset_userobjspace_upgrade(os);
+ dmu_objset_id_quota_upgrade(os);
} else {
mutex_exit(&os->os_upgrade_lock);
}
zfs_ioc_clone, zfs_secpolicy_create_clone, DATASET_NAME,
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
+ zfs_ioctl_register("remap", ZFS_IOC_REMAP,
+ zfs_ioc_remap, zfs_secpolicy_remap, DATASET_NAME,
+ POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_TRUE);
+
zfs_ioctl_register("destroy_snaps", ZFS_IOC_DESTROY_SNAPS,
zfs_ioc_destroy_snaps, zfs_secpolicy_destroy_snaps, POOL_NAME,
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
};
static struct miscdevice zfs_misc = {
- .minor = MISC_DYNAMIC_MINOR,
+ .minor = ZFS_MINOR,
.name = ZFS_DRIVER,
.fops = &zfsdev_fops,
};
+MODULE_ALIAS_MISCDEV(ZFS_MINOR);
+MODULE_ALIAS("devname:zfs");
+
static int
zfs_attach(void)
{
zfsdev_state_list->zs_minor = -1;
error = misc_register(&zfs_misc);
- if (error != 0) {
- printk(KERN_INFO "ZFS: misc_register() failed %d\n", error);
- return (error);
+ if (error == -EBUSY) {
+ /*
+ * Fallback to dynamic minor allocation in the event of a
+ * collision with a reserved minor in linux/miscdevice.h.
+ * In this case the kernel modules must be manually loaded.
+ */
+ printk(KERN_INFO "ZFS: misc_register() with static minor %d "
+ "failed %d, retrying with MISC_DYNAMIC_MINOR\n",
+ ZFS_MINOR, error);
+
+ zfs_misc.minor = MISC_DYNAMIC_MINOR;
+ error = misc_register(&zfs_misc);
}
- return (0);
+ if (error)
+ printk(KERN_INFO "ZFS: misc_register() failed %d\n", error);
+
+ return (error);
}
static void