Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zhack #4

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 104 additions & 5 deletions cmd/zhack/zhack.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,13 @@ libzfs_handle_t *g_zfs;
static importargs_t g_importargs;
static char *g_pool;
static boolean_t g_readonly;
static boolean_t g_force = B_FALSE;

static void
usage(void)
{
(void) fprintf(stderr,
"Usage: %s [-c cachefile] [-d dir] <subcommand> <args> ...\n"
"Usage: %s [-c cachefile] [-d dir] [-f] <subcommand> <args> ...\n"
"where <subcommand> <args> is one of the following:\n"
"\n", cmdname);

Expand All @@ -73,6 +74,9 @@ usage(void)
" feature enable [-d desc] <pool> <feature>\n"
" add a new enabled feature to the pool\n"
" -d <desc> sets the feature's description\n"
" feature disable <pool> <feature>\n"
" remove an enabled, but not active, feature\n"
" from the pool.\n"
" feature ref [-md] <pool> <feature>\n"
" change the refcount on the given feature\n"
" -d decrease instead of increase the refcount\n"
Expand Down Expand Up @@ -355,8 +359,10 @@ zhack_do_feature_enable(int argc, char **argv)
zhack_spa_open(target, B_FALSE, FTAG, &spa);
mos = spa->spa_meta_objset;

if (zfeature_is_supported(feature.fi_guid))
fatal(spa, FTAG, "'%s' is a real feature, will not enable");
if (zfeature_is_supported(feature.fi_guid) && (g_force == B_FALSE))
fatal(spa, FTAG,
"'%s' is a real feature, will not enable\n"
"provide the -f option to force override", feature.fi_guid);
if (0 == zap_contains(mos, spa->spa_feat_desc_obj, feature.fi_guid))
fatal(spa, FTAG, "feature already enabled: %s",
feature.fi_guid);
Expand All @@ -369,6 +375,94 @@ zhack_do_feature_enable(int argc, char **argv)
free(desc);
}

static void
zhack_feature_disable_sync(void *arg, dmu_tx_t *tx)
{
spa_t *spa = dmu_tx_pool(tx)->dp_spa;
zfeature_info_t *feature = arg;

feature_disable_sync(spa, feature, tx);

spa_history_log_internal(spa, "zhack disable feature", tx,
"name=%s can_readonly=%u",
feature->fi_guid, feature->fi_can_readonly);
}

static void
zhack_do_feature_disable(int argc, char **argv)
{
char c;
char *target;
uint64_t count;
spa_t *spa;
objset_t *mos;
zfeature_info_t feature;
spa_feature_t nodeps[] = { SPA_FEATURE_NONE };

/*
* fi_desc does not matter here because it was written to disk
* when the feature was enabled, but we need to properly set the
* feature for read or write based on the information we read off
* disk later.
*/
feature.fi_uname = "zhack";
feature.fi_mos = B_TRUE;
feature.fi_desc = NULL;
feature.fi_depends = nodeps;
feature.fi_feature = SPA_FEATURE_NONE;

optind = 1;
while ((c = getopt(argc, argv, "")) != -1) {
switch (c) {
default:
usage();
break;
}
}
argc -= optind;
argv += optind;

if (argc < 2) {
(void) fprintf(stderr, "error: missing feature or pool name\n");
usage();
}
target = argv[0];
feature.fi_guid = argv[1];

if (!zfeature_is_valid_guid(feature.fi_guid))
fatal(NULL, FTAG, "invalid feature guid: %s", feature.fi_guid);

zhack_spa_open(target, B_FALSE, FTAG, &spa);
mos = spa->spa_meta_objset;

if (zfeature_is_supported(feature.fi_guid) && (g_force == B_FALSE)) {
fatal(spa, FTAG,
"'%s' is a real feature, will not disable\n"
"provide the -f option to force override", feature.fi_guid);
}

if (0 == zap_contains(mos, spa->spa_feat_for_read_obj,
feature.fi_guid)) {
feature.fi_can_readonly = B_FALSE;
} else if (0 == zap_contains(mos, spa->spa_feat_for_write_obj,
feature.fi_guid)) {
feature.fi_can_readonly = B_TRUE;
} else {
fatal(spa, FTAG, "feature is not enabled: %s", feature.fi_guid);
}

if (feature_get_refcount_from_disk(spa, &feature, &count) == 0 &&
count > 0) {
fatal(spa, FTAG, "feature '%s' is active, can not disable",
feature.fi_guid);
}

VERIFY0(dsl_sync_task(spa_name(spa), NULL,
zhack_feature_disable_sync, &feature, 5, ZFS_SPACE_CHECK_NORMAL));

spa_close(spa, FTAG);
}

static void
feature_incr_sync(void *arg, dmu_tx_t *tx)
{
Expand Down Expand Up @@ -466,7 +560,7 @@ zhack_do_feature_ref(int argc, char **argv)
if (decr) {
uint64_t count;
if (feature_get_refcount_from_disk(spa, &feature,
&count) == 0 && count != 0) {
&count) == 0 && count == 0) {
fatal(spa, FTAG, "feature refcount already 0: %s",
feature.fi_guid);
}
Expand Down Expand Up @@ -497,6 +591,8 @@ zhack_do_feature(int argc, char **argv)
zhack_do_feature_stat(argc, argv);
} else if (strcmp(subcommand, "enable") == 0) {
zhack_do_feature_enable(argc, argv);
} else if (strcmp(subcommand, "disable") == 0) {
zhack_do_feature_disable(argc, argv);
} else if (strcmp(subcommand, "ref") == 0) {
zhack_do_feature_ref(argc, argv);
} else {
Expand Down Expand Up @@ -525,7 +621,7 @@ main(int argc, char **argv)
dprintf_setup(&argc, argv);
zfs_prop_init();

while ((c = getopt(argc, argv, "c:d:")) != -1) {
while ((c = getopt(argc, argv, "c:d:f")) != -1) {
switch (c) {
case 'c':
g_importargs.cachefile = optarg;
Expand All @@ -534,6 +630,9 @@ main(int argc, char **argv)
assert(g_importargs.paths < MAX_NUM_PATHS);
g_importargs.path[g_importargs.paths++] = optarg;
break;
case 'f':
g_force = B_TRUE;
break;
default:
usage();
break;
Expand Down
2 changes: 2 additions & 0 deletions include/sys/zfeature.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ extern int feature_get_refcount_from_disk(spa_t *spa, zfeature_info_t *feature,
uint64_t *res);
extern void feature_enable_sync(struct spa *, zfeature_info_t *,
struct dmu_tx *);
extern void feature_disable_sync(struct spa *, zfeature_info_t *,
struct dmu_tx *);
extern void feature_sync(struct spa *, zfeature_info_t *, uint64_t,
struct dmu_tx *);

Expand Down
2 changes: 0 additions & 2 deletions lib/libzpool/kernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -643,8 +643,6 @@ vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3)
#ifdef __linux__
flags |= O_DIRECT;
#endif
/* We shouldn't be writing to block devices in userspace */
VERIFY(!(flags & FWRITE));
}

if (flags & FCREAT)
Expand Down
37 changes: 37 additions & 0 deletions module/zfs/zfeature.c
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,43 @@ feature_enable_sync(spa_t *spa, zfeature_info_t *feature, dmu_tx_t *tx)
}
}

/*
* This function is non-static for zhack; it should otherwise not be used
* outside this file.
*/
void
feature_disable_sync(spa_t *spa, zfeature_info_t *feature, dmu_tx_t *tx)
{
uint64_t descobj = spa->spa_feat_desc_obj;
uint64_t zapobj = feature->fi_can_readonly ?
spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;

ASSERT(0 != zapobj);
ASSERT(zfeature_is_valid_guid(feature->fi_guid));
ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES);

if (zap_contains(spa->spa_meta_objset, descobj, feature->fi_guid) == 0)
VERIFY0(zap_remove(spa->spa_meta_objset, descobj,
feature->fi_guid, tx));

if (zap_contains(spa->spa_meta_objset, zapobj, feature->fi_guid) == 0)
VERIFY0(zap_remove(spa->spa_meta_objset, zapobj,
feature->fi_guid, tx));

spa_deactivate_mos_feature(spa, feature->fi_guid);

if (spa_feature_is_enabled(spa, SPA_FEATURE_ENABLED_TXG)) {
uint64_t txgobj = spa->spa_feat_enabled_txg_obj;

if (txgobj && (zap_contains(spa->spa_meta_objset,
txgobj, feature->fi_guid) == 0)) {
spa_feature_decr(spa, SPA_FEATURE_ENABLED_TXG, tx);
VERIFY0(zap_remove(spa->spa_meta_objset, txgobj,
feature->fi_guid, tx));
}
}
}

static void
feature_do_action(spa_t *spa, spa_feature_t fid, feature_action_t action,
dmu_tx_t *tx)
Expand Down