summaryrefslogtreecommitdiffstats
path: root/xlators/mgmt
diff options
context:
space:
mode:
authorAvra Sengupta <asengupt@redhat.com>2014-04-23 04:26:24 +0000
committerKrishnan Parthasarathi <kparthas@redhat.com>2014-05-06 00:24:39 -0700
commitf846e54b8844decbc8bd73840e7d35b2dcaed2e0 (patch)
treee0f7be12df60b59c42651cd50bd683510e7cce24 /xlators/mgmt
parenta05c579f1c3695c4ddead0a5cfc2c92422bd4f8f (diff)
glusterd: Fetch brick mount_dirs during brick create.
Fetch the mount directory path for a brick, during volume create, add-brick, and replace-brick. When a snap-create is missed, use this mount directory information to create the brick path for the missed snap brick. Change-Id: Iad3eec96a32cf340f26bdf3f28e2f529e4b77e31 BUG: 1061685 Signed-off-by: Avra Sengupta <asengupt@redhat.com> Reviewed-on: http://review.gluster.org/7550 Reviewed-by: Rajesh Joseph <rjoseph@redhat.com> Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Krishnan Parthasarathi <kparthas@redhat.com> Tested-by: Krishnan Parthasarathi <kparthas@redhat.com>
Diffstat (limited to 'xlators/mgmt')
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-brick-ops.c50
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-op-sm.c26
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-replace-brick.c44
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-snapshot.c115
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-store.c12
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-store.h1
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-syncop.c38
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-utils.c153
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-utils.h7
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-volume-ops.c122
-rw-r--r--xlators/mgmt/glusterd/src/glusterd.h10
11 files changed, 461 insertions, 117 deletions
diff --git a/xlators/mgmt/glusterd/src/glusterd-brick-ops.c b/xlators/mgmt/glusterd/src/glusterd-brick-ops.c
index e2e01672893..b14d3606d81 100644
--- a/xlators/mgmt/glusterd/src/glusterd-brick-ops.c
+++ b/xlators/mgmt/glusterd/src/glusterd-brick-ops.c
@@ -996,7 +996,12 @@ glusterd_op_perform_add_bricks (glusterd_volinfo_t *volinfo, int32_t count,
char msg[1024] __attribute__((unused)) = {0, };
int caps = 0;
int brickid = 0;
+ char key[PATH_MAX] = "";
+ char *brick_mount_dir = NULL;
+ xlator_t *this = NULL;
+ this = THIS;
+ GF_ASSERT (this);
GF_ASSERT (volinfo);
if (bricks) {
@@ -1034,6 +1039,18 @@ glusterd_op_perform_add_bricks (glusterd_volinfo_t *volinfo, int32_t count,
GLUSTERD_ASSIGN_BRICKID_TO_BRICKINFO (brickinfo, volinfo,
brickid++);
+ brick_mount_dir = NULL;
+
+ snprintf (key, sizeof(key), "brick%d.mount_dir", i);
+ ret = dict_get_str (dict, key, &brick_mount_dir);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "%s not present", key);
+ goto out;
+ }
+ strncpy (brickinfo->mount_dir, brick_mount_dir,
+ sizeof(brickinfo->mount_dir));
+
ret = glusterd_resolve_brick (brickinfo);
if (ret)
goto out;
@@ -1049,7 +1066,6 @@ glusterd_op_perform_add_bricks (glusterd_volinfo_t *volinfo, int32_t count,
}
-
/* Gets changed only if the options are given in add-brick cli */
if (type)
volinfo->type = type;
@@ -1202,13 +1218,14 @@ out:
}
int
-glusterd_op_stage_add_brick (dict_t *dict, char **op_errstr)
+glusterd_op_stage_add_brick (dict_t *dict, char **op_errstr, dict_t *rsp_dict)
{
int ret = 0;
char *volname = NULL;
int count = 0;
int replica_count = 0;
int i = 0;
+ int32_t local_brick_count = 0;
char *bricks = NULL;
char *brick_list = NULL;
char *saveptr = NULL;
@@ -1218,6 +1235,7 @@ glusterd_op_stage_add_brick (dict_t *dict, char **op_errstr)
glusterd_volinfo_t *volinfo = NULL;
xlator_t *this = NULL;
char msg[2048] = {0,};
+ char key[PATH_MAX] = "";
gf_boolean_t brick_alloc = _gf_false;
char *all_bricks = NULL;
char *str_ret = NULL;
@@ -1349,6 +1367,26 @@ glusterd_op_stage_add_brick (dict_t *dict, char **op_errstr)
op_errstr, is_force);
if (ret)
goto out;
+
+ ret = glusterd_get_brick_mount_dir
+ (brickinfo->path,
+ brickinfo->hostname,
+ brickinfo->mount_dir);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "Failed to get brick mount_dir");
+ goto out;
+ }
+
+ snprintf (key, sizeof(key), "brick%d.mount_dir", i + 1);
+ ret = dict_set_dynstr_with_alloc (rsp_dict, key,
+ brickinfo->mount_dir);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "Failed to set %s", key);
+ goto out;
+ }
+ local_brick_count = i + 1;
}
glusterd_brickinfo_delete (brickinfo);
@@ -1358,6 +1396,14 @@ glusterd_op_stage_add_brick (dict_t *dict, char **op_errstr)
i++;
}
+ ret = dict_set_int32 (rsp_dict, "brick_count",
+ local_brick_count);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "Failed to set local_brick_count");
+ goto out;
+ }
+
out:
GF_FREE (free_ptr);
if (brick_alloc && brickinfo)
diff --git a/xlators/mgmt/glusterd/src/glusterd-op-sm.c b/xlators/mgmt/glusterd/src/glusterd-op-sm.c
index 30658459ba7..d6d72516c67 100644
--- a/xlators/mgmt/glusterd/src/glusterd-op-sm.c
+++ b/xlators/mgmt/glusterd/src/glusterd-op-sm.c
@@ -3373,6 +3373,7 @@ glusterd_op_ac_send_stage_op (glusterd_op_sm_event_t *event, void *ctx)
xlator_t *this = NULL;
glusterd_peerinfo_t *peerinfo = NULL;
dict_t *dict = NULL;
+ dict_t *rsp_dict = NULL;
char *op_errstr = NULL;
glusterd_op_t op = GD_OP_NONE;
uint32_t pending_count = 0;
@@ -3384,6 +3385,13 @@ glusterd_op_ac_send_stage_op (glusterd_op_sm_event_t *event, void *ctx)
op = glusterd_op_get_op ();
+ rsp_dict = dict_new();
+ if (!rsp_dict) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to create rsp_dict");
+ ret = -1;
+ goto out;
+ }
+
ret = glusterd_op_build_payload (&dict, &op_errstr, NULL);
if (ret) {
gf_log (this->name, GF_LOG_ERROR, LOGSTR_BUILD_PAYLOAD,
@@ -3401,8 +3409,7 @@ glusterd_op_ac_send_stage_op (glusterd_op_sm_event_t *event, void *ctx)
goto out;
}
- /* rsp_dict NULL from source */
- ret = glusterd_op_stage_validate (op, dict, &op_errstr, NULL);
+ ret = glusterd_op_stage_validate (op, dict, &op_errstr, rsp_dict);
if (ret) {
gf_log (this->name, GF_LOG_ERROR, LOGSTR_STAGE_FAIL,
gd_op_list[op], "localhost",
@@ -3414,6 +3421,9 @@ glusterd_op_ac_send_stage_op (glusterd_op_sm_event_t *event, void *ctx)
goto out;
}
+ if (op == GD_OP_REPLACE_BRICK)
+ glusterd_rb_use_rsp_dict (NULL, rsp_dict);
+
list_for_each_entry (peerinfo, &priv->peers, uuid_list) {
GF_ASSERT (peerinfo);
@@ -3447,6 +3457,9 @@ glusterd_op_ac_send_stage_op (glusterd_op_sm_event_t *event, void *ctx)
opinfo.pending_count = pending_count;
out:
+ if (rsp_dict)
+ dict_unref (rsp_dict);
+
if (dict)
dict_unref (dict);
if (ret) {
@@ -4586,11 +4599,13 @@ glusterd_op_stage_validate (glusterd_op_t op, dict_t *dict, char **op_errstr,
switch (op) {
case GD_OP_CREATE_VOLUME:
- ret = glusterd_op_stage_create_volume (dict, op_errstr);
+ ret = glusterd_op_stage_create_volume (dict, op_errstr,
+ rsp_dict);
break;
case GD_OP_START_VOLUME:
- ret = glusterd_op_stage_start_volume (dict, op_errstr);
+ ret = glusterd_op_stage_start_volume (dict, op_errstr,
+ rsp_dict);
break;
case GD_OP_STOP_VOLUME:
@@ -4602,7 +4617,8 @@ glusterd_op_stage_validate (glusterd_op_t op, dict_t *dict, char **op_errstr,
break;
case GD_OP_ADD_BRICK:
- ret = glusterd_op_stage_add_brick (dict, op_errstr);
+ ret = glusterd_op_stage_add_brick (dict, op_errstr,
+ rsp_dict);
break;
case GD_OP_REPLACE_BRICK:
diff --git a/xlators/mgmt/glusterd/src/glusterd-replace-brick.c b/xlators/mgmt/glusterd/src/glusterd-replace-brick.c
index ed6d7fd57d5..929c86b718c 100644
--- a/xlators/mgmt/glusterd/src/glusterd-replace-brick.c
+++ b/xlators/mgmt/glusterd/src/glusterd-replace-brick.c
@@ -544,6 +544,30 @@ glusterd_op_stage_replace_brick (dict_t *dict, char **op_errstr,
ret = -1;
goto out;
}
+ } else {
+ ret = glusterd_get_brick_mount_dir (dst_brickinfo->path,
+ dst_brickinfo->hostname,
+ dst_brickinfo->mount_dir);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "Failed to get brick mount_dir");
+ goto out;
+ }
+
+ ret = dict_set_dynstr_with_alloc (rsp_dict, "brick1.mount_dir",
+ dst_brickinfo->mount_dir);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "Failed to set brick1.mount_dir");
+ goto out;
+ }
+
+ ret = dict_set_int32 (rsp_dict, "brick_count", 1);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "Failed to set local_brick_count");
+ goto out;
+ }
}
if (replace_op == GF_REPLACE_OP_START &&
@@ -1493,12 +1517,18 @@ out:
static int
glusterd_op_perform_replace_brick (glusterd_volinfo_t *volinfo,
- char *old_brick, char *new_brick)
+ char *old_brick, char *new_brick,
+ dict_t *dict)
{
+ char *brick_mount_dir = NULL;
glusterd_brickinfo_t *old_brickinfo = NULL;
glusterd_brickinfo_t *new_brickinfo = NULL;
int32_t ret = -1;
+ xlator_t *this = NULL;
+ this = THIS;
+ GF_ASSERT (this);
+ GF_ASSERT (dict);
GF_ASSERT (volinfo);
ret = glusterd_brickinfo_new_from_brick (new_brick,
@@ -1519,6 +1549,15 @@ glusterd_op_perform_replace_brick (glusterd_volinfo_t *volinfo,
strncpy (new_brickinfo->brick_id, old_brickinfo->brick_id,
sizeof (new_brickinfo->brick_id));
+ ret = dict_get_str (dict, "brick1.mount_dir", &brick_mount_dir);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "brick1.mount_dir not present");
+ goto out;
+ }
+ strncpy (new_brickinfo->mount_dir, brick_mount_dir,
+ sizeof(new_brickinfo->mount_dir));
+
list_add_tail (&new_brickinfo->brick_list,
&old_brickinfo->brick_list);
@@ -1629,7 +1668,6 @@ glusterd_op_replace_brick (dict_t *dict, dict_t *rsp_dict)
if (ret)
goto out;
-
if ((GF_REPLACE_OP_START != replace_op)) {
/* Set task-id, if available, in op_ctx dict for operations
@@ -1753,7 +1791,7 @@ glusterd_op_replace_brick (dict_t *dict, dict_t *rsp_dict)
}
ret = glusterd_op_perform_replace_brick (volinfo, src_brick,
- dst_brick);
+ dst_brick, dict);
if (ret) {
gf_log (this->name, GF_LOG_CRITICAL, "Unable to add "
"dst-brick: %s to volume: %s", dst_brick,
diff --git a/xlators/mgmt/glusterd/src/glusterd-snapshot.c b/xlators/mgmt/glusterd/src/glusterd-snapshot.c
index 54b61ee66cd..327155fee31 100644
--- a/xlators/mgmt/glusterd/src/glusterd-snapshot.c
+++ b/xlators/mgmt/glusterd/src/glusterd-snapshot.c
@@ -1042,7 +1042,6 @@ glusterd_snap_create_pre_val_use_rsp_dict (dict_t *dst, dict_t *src)
{
char *snap_brick_dir = NULL;
char *snap_device = NULL;
- char *tmpstr = NULL;
char key[PATH_MAX] = "";
char snapbrckcnt[PATH_MAX] = "";
char snapbrckord[PATH_MAX] = "";
@@ -1081,7 +1080,6 @@ glusterd_snap_create_pre_val_use_rsp_dict (dict_t *dst, dict_t *src)
/* Fetching data from source dict */
snprintf (key, sizeof(key) - 1,
"vol%"PRId64".brickdir%"PRId64, i+1, j);
-
ret = dict_get_ptr (src, key,
(void **)&snap_brick_dir);
if (ret) {
@@ -1090,20 +1088,9 @@ glusterd_snap_create_pre_val_use_rsp_dict (dict_t *dst, dict_t *src)
continue;
}
- snprintf (key, sizeof(key) - 1,
- "vol%"PRId64".brick_snapdevice%"PRId64, i+1, j);
-
- ret = dict_get_ptr (src, key,
- (void **)&snap_device);
- if (ret) {
- gf_log (this->name, GF_LOG_ERROR,
- "Unable to fetch snap_device");
- goto out;
- }
-
+ /* Fetching brick order from source dict */
snprintf (snapbrckord, sizeof(snapbrckord) - 1,
"vol%"PRId64".brick%"PRId64".order", i+1, j);
-
ret = dict_get_int64 (src, snapbrckord, &brick_order);
if (ret) {
gf_log (this->name, GF_LOG_ERROR,
@@ -1111,39 +1098,36 @@ glusterd_snap_create_pre_val_use_rsp_dict (dict_t *dst, dict_t *src)
goto out;
}
- /* Adding the data in the dst dict */
snprintf (key, sizeof(key) - 1,
- "vol%"PRId64".brickdir%"PRId64, i+1, brick_order);
-
- tmpstr = gf_strdup (snap_brick_dir);
- if (!tmpstr) {
+ "vol%"PRId64".brickdir%"PRId64, i+1,
+ brick_order);
+ ret = dict_set_dynstr_with_alloc (dst, key,
+ snap_brick_dir);
+ if (ret) {
gf_log (this->name, GF_LOG_ERROR,
- "Out Of Memory");
- ret = -1;
+ "Failed to set %s", key);
goto out;
}
- ret = dict_set_dynstr (dst, key, tmpstr);
+
+ snprintf (key, sizeof(key) - 1,
+ "vol%"PRId64".brick_snapdevice%"PRId64,
+ i+1, j);
+ ret = dict_get_ptr (src, key,
+ (void **)&snap_device);
if (ret) {
gf_log (this->name, GF_LOG_ERROR,
- "Failed to set %s", key);
- GF_FREE (tmpstr);
+ "Unable to fetch snap_device");
goto out;
}
snprintf (key, sizeof(key) - 1,
"vol%"PRId64".brick_snapdevice%"PRId64,
i+1, brick_order);
-
- tmpstr = gf_strdup (snap_device);
- if (!tmpstr) {
- ret = -1;
- goto out;
- }
- ret = dict_set_dynstr (dst, key, tmpstr);
+ ret = dict_set_dynstr_with_alloc (dst, key,
+ snap_device);
if (ret) {
gf_log (this->name, GF_LOG_ERROR,
"Failed to set %s", key);
- GF_FREE (tmpstr);
goto out;
}
}
@@ -1205,12 +1189,7 @@ glusterd_snapshot_create_prevalidate (dict_t *dict, char **op_errstr,
char *volname = NULL;
char *snapname = NULL;
char *device = NULL;
- char *tmpstr = NULL;
- char *brick_dir = NULL;
- char snap_brick_dir[PATH_MAX] = "";
- char *mnt_pt = NULL;
char key[PATH_MAX] = "";
- char snap_mount[PATH_MAX] = "";
char snap_volname[64] = "";
char err_str[PATH_MAX] = "";
int ret = -1;
@@ -1394,44 +1373,17 @@ glusterd_snapshot_create_prevalidate (dict_t *dict, char **op_errstr,
GF_FREE (device);
goto out;
}
+ device = NULL;
- ret = glusterd_get_brick_root (brickinfo->path,
- &mnt_pt);
- if (ret) {
- snprintf (err_str, sizeof (err_str),
- "could not get the root of the brick path %s",
- brickinfo->path);
- loglevel = GF_LOG_WARNING;
- goto out;
- }
- if (strncmp (brickinfo->path, mnt_pt, strlen(mnt_pt))) {
- snprintf (err_str, sizeof (err_str),
- "brick: %s brick mount: %s",
- brickinfo->path, mnt_pt);
- loglevel = GF_LOG_WARNING;
- goto out;
- }
-
- brick_dir = &brickinfo->path[strlen (mnt_pt)];
- brick_dir++;
-
- snprintf (snap_brick_dir, sizeof (snap_brick_dir),
- "/%s", brick_dir);
-
- tmpstr = gf_strdup (snap_brick_dir);
- if (!tmpstr) {
- ret = -1;
- goto out;
- }
snprintf (key, sizeof(key), "vol%"PRId64".brickdir%"PRId64, i,
brick_count);
- ret = dict_set_dynstr (rsp_dict, key, tmpstr);
+ ret = dict_set_dynstr_with_alloc (rsp_dict, key,
+ brickinfo->mount_dir);
if (ret) {
gf_log (this->name, GF_LOG_ERROR,
- "Failed to set %s", snap_mount);
+ "Failed to set %s", key);
goto out;
}
- tmpstr = NULL;
snprintf (key, sizeof(key) - 1, "vol%"PRId64".brick%"PRId64".order",
i, brick_count);
@@ -1462,8 +1414,8 @@ glusterd_snapshot_create_prevalidate (dict_t *dict, char **op_errstr,
ret = 0;
out:
- if (ret)
- GF_FREE (tmpstr);
+ if (device)
+ GF_FREE (device);
if (ret && err_str[0] != '\0') {
gf_log (this->name, loglevel, "%s", err_str);
@@ -3536,23 +3488,16 @@ glusterd_add_bricks_to_snap_volume (dict_t *dict, dict_t *rsp_dict,
* will help in mapping while recreating the missed snapshot
*/
gf_log (this->name, GF_LOG_WARNING, "Unable to fetch "
- "snap mount path (%s). Using original brickinfo", key);
+ "snap mount path(%s). Adding to missed_snap_list", key);
snap_brickinfo->snap_status = -1;
- strcpy (snap_brick_path, original_brickinfo->path);
+
+ *snap_brick_dir = original_brickinfo->mount_dir;
/* In origiator node add snaps missed
* from different nodes to the dict
*/
if (is_origin_glusterd (dict) == _gf_true)
add_missed_snap = _gf_true;
- } else {
- /* Create brick-path in the format /var/run/gluster/snaps/ *
- * <snap-uuid>/<original-brick#>/snap-brick-dir *
- */
- snprintf (snap_brick_path, sizeof(snap_brick_path),
- "%s/%s/brick%d%s", snap_mount_folder,
- snap_vol->volname, brick_count+1,
- *snap_brick_dir);
}
if ((snap_brickinfo->snap_status != -1) &&
@@ -3566,7 +3511,6 @@ glusterd_add_bricks_to_snap_volume (dict_t *dict, dict_t *rsp_dict,
snap_vol->snapshot->snapname);
snap_brickinfo->snap_status = -1;
- strcpy (snap_brick_path, original_brickinfo->path);
add_missed_snap = _gf_true;
}
@@ -3585,6 +3529,14 @@ glusterd_add_bricks_to_snap_volume (dict_t *dict, dict_t *rsp_dict,
}
}
+ /* Create brick-path in the format /var/run/gluster/snaps/ *
+ * <snap-uuid>/<original-brick#>/snap-brick-dir *
+ */
+ snprintf (snap_brick_path, sizeof(snap_brick_path),
+ "%s/%s/brick%d%s", snap_mount_folder,
+ snap_vol->volname, brick_count+1,
+ *snap_brick_dir);
+
snprintf (key, sizeof(key), "vol%"PRId64".brick_snapdevice%d",
volcount, brick_count);
ret = dict_get_ptr (dict, key, (void **)&snap_device);
@@ -3606,6 +3558,7 @@ glusterd_add_bricks_to_snap_volume (dict_t *dict, dict_t *rsp_dict,
strcpy (snap_brickinfo->hostname, original_brickinfo->hostname);
strcpy (snap_brickinfo->path, snap_brick_path);
+ strcpy (snap_brickinfo->mount_dir, original_brickinfo->mount_dir);
uuid_copy (snap_brickinfo->uuid, original_brickinfo->uuid);
/* AFR changelog names are based on brick_id and hence the snap
* volume's bricks must retain the same ID */
diff --git a/xlators/mgmt/glusterd/src/glusterd-store.c b/xlators/mgmt/glusterd/src/glusterd-store.c
index eda176d1b6b..5b1d80e84aa 100644
--- a/xlators/mgmt/glusterd/src/glusterd-store.c
+++ b/xlators/mgmt/glusterd/src/glusterd-store.c
@@ -294,6 +294,14 @@ glusterd_store_brickinfo_write (int fd, glusterd_brickinfo_t *brickinfo)
goto out;
}
+ if (strlen(brickinfo->mount_dir) > 0) {
+ snprintf (value, sizeof(value), "%s", brickinfo->mount_dir);
+ ret = gf_store_save_value (fd,
+ GLUSTERD_STORE_KEY_BRICK_MOUNT_DIR, value);
+ if (ret)
+ goto out;
+ }
+
snprintf (value, sizeof(value), "%d", brickinfo->snap_status);
ret = gf_store_save_value (fd, GLUSTERD_STORE_KEY_BRICK_SNAP_STATUS,
value);
@@ -2073,6 +2081,10 @@ glusterd_store_retrieve_bricks (glusterd_volinfo_t *volinfo)
strlen (GLUSTERD_STORE_KEY_BRICK_DEVICE_PATH))) {
strncpy (brickinfo->device_path, value,
sizeof (brickinfo->device_path));
+ } else if (!strncmp (key, GLUSTERD_STORE_KEY_BRICK_MOUNT_DIR,
+ strlen (GLUSTERD_STORE_KEY_BRICK_MOUNT_DIR))) {
+ strncpy (brickinfo->mount_dir, value,
+ sizeof (brickinfo->mount_dir));
} else if (!strncmp (key, GLUSTERD_STORE_KEY_BRICK_SNAP_STATUS,
strlen (GLUSTERD_STORE_KEY_BRICK_SNAP_STATUS))) {
gf_string2int (value, &brickinfo->snap_status);
diff --git a/xlators/mgmt/glusterd/src/glusterd-store.h b/xlators/mgmt/glusterd/src/glusterd-store.h
index 7fc643ebe8d..01973bb7ae6 100644
--- a/xlators/mgmt/glusterd/src/glusterd-store.h
+++ b/xlators/mgmt/glusterd/src/glusterd-store.h
@@ -77,6 +77,7 @@ typedef enum glusterd_store_ver_ac_{
#define GLUSTERD_STORE_KEY_BRICK_DECOMMISSIONED "decommissioned"
#define GLUSTERD_STORE_KEY_BRICK_VGNAME "vg"
#define GLUSTERD_STORE_KEY_BRICK_DEVICE_PATH "device_path"
+#define GLUSTERD_STORE_KEY_BRICK_MOUNT_DIR "mount_dir"
#define GLUSTERD_STORE_KEY_BRICK_SNAP_STATUS "snap-status"
#define GLUSTERD_STORE_KEY_BRICK_ID "brick-id"
diff --git a/xlators/mgmt/glusterd/src/glusterd-syncop.c b/xlators/mgmt/glusterd/src/glusterd-syncop.c
index d385cf9eede..998af71b524 100644
--- a/xlators/mgmt/glusterd/src/glusterd-syncop.c
+++ b/xlators/mgmt/glusterd/src/glusterd-syncop.c
@@ -271,9 +271,24 @@ extern struct rpc_clnt_program gd_mgmt_v3_prog;
int
glusterd_syncop_aggr_rsp_dict (glusterd_op_t op, dict_t *aggr, dict_t *rsp)
{
- int ret = 0;
+ int ret = 0;
+ xlator_t *this = NULL;
+
+ this = THIS;
+ GF_ASSERT (this);
switch (op) {
+ case GD_OP_CREATE_VOLUME:
+ case GD_OP_ADD_BRICK:
+ case GD_OP_START_VOLUME:
+ ret = glusterd_aggr_brick_mount_dirs (aggr, rsp);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to "
+ "aggregate brick mount dirs");
+ goto out;
+ }
+ break;
+
case GD_OP_REPLACE_BRICK:
ret = glusterd_rb_use_rsp_dict (aggr, rsp);
if (ret)
@@ -723,7 +738,9 @@ _gd_syncop_stage_op_cbk (struct rpc_req *req, struct iovec *iov,
}
uuid_copy (args->uuid, rsp.uuid);
- if (rsp.op == GD_OP_REPLACE_BRICK || rsp.op == GD_OP_QUOTA) {
+ if (rsp.op == GD_OP_REPLACE_BRICK || rsp.op == GD_OP_QUOTA ||
+ rsp.op == GD_OP_CREATE_VOLUME || rsp.op == GD_OP_ADD_BRICK ||
+ rsp.op == GD_OP_START_VOLUME) {
pthread_mutex_lock (&args->lock_dict);
{
ret = glusterd_syncop_aggr_rsp_dict (rsp.op, args->dict,
@@ -1148,20 +1165,29 @@ gd_stage_op_phase (struct list_head *peers, glusterd_op_t op, dict_t *op_ctx,
uuid_t tmp_uuid = {0};
char *errstr = NULL;
struct syncargs args = {0};
+ dict_t *aggr_dict = NULL;
this = THIS;
rsp_dict = dict_new ();
if (!rsp_dict)
goto out;
+ if ((op == GD_OP_CREATE_VOLUME) || (op == GD_OP_ADD_BRICK) ||
+ (op == GD_OP_START_VOLUME))
+ aggr_dict = req_dict;
+ else
+ aggr_dict = op_ctx;
+
ret = glusterd_op_stage_validate (op, req_dict, op_errstr, rsp_dict);
if (ret) {
hostname = "localhost";
goto stage_done;
}
- if ((op == GD_OP_REPLACE_BRICK || op == GD_OP_QUOTA)) {
- ret = glusterd_syncop_aggr_rsp_dict (op, op_ctx, rsp_dict);
+ if ((op == GD_OP_REPLACE_BRICK || op == GD_OP_QUOTA ||
+ op == GD_OP_CREATE_VOLUME || op == GD_OP_ADD_BRICK ||
+ op == GD_OP_START_VOLUME)) {
+ ret = glusterd_syncop_aggr_rsp_dict (op, aggr_dict, rsp_dict);
if (ret) {
gf_log (this->name, GF_LOG_ERROR, "%s",
"Failed to aggregate response from node/brick");
@@ -1186,7 +1212,7 @@ stage_done:
goto out;
}
- gd_syncargs_init (&args, op_ctx);
+ gd_syncargs_init (&args, aggr_dict);
synctask_barrier_init((&args));
peer_cnt = 0;
list_for_each_entry (peerinfo, peers, op_peers_list) {
@@ -1203,7 +1229,7 @@ stage_done:
if (args.errstr)
*op_errstr = gf_strdup (args.errstr);
- else if (dict_get_str (op_ctx, "errstr", &errstr) == 0)
+ else if (dict_get_str (aggr_dict, "errstr", &errstr) == 0)
*op_errstr = gf_strdup (errstr);
ret = args.op_ret;
diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c
index eb5cb33bb0e..d508e74f510 100644
--- a/xlators/mgmt/glusterd/src/glusterd-utils.c
+++ b/xlators/mgmt/glusterd/src/glusterd-utils.c
@@ -628,6 +628,7 @@ glusterd_brickinfo_dup (glusterd_brickinfo_t *brickinfo,
}
}
strcpy (dup_brickinfo->brick_id, brickinfo->brick_id);
+ strcpy (dup_brickinfo->mount_dir, brickinfo->mount_dir);
dup_brickinfo->status = brickinfo->status;
dup_brickinfo->snap_status = brickinfo->snap_status;
out:
@@ -934,17 +935,71 @@ glusterd_resolve_brick (glusterd_brickinfo_t *brickinfo)
}
int32_t
+glusterd_get_brick_mount_dir (char *brickpath, char *hostname, char *mount_dir)
+{
+ char *mnt_pt = NULL;
+ char *brick_dir = NULL;
+ int32_t ret = -1;
+ uuid_t brick_uuid = {0, };
+ xlator_t *this = NULL;
+
+ this = THIS;
+ GF_ASSERT (this);
+ GF_ASSERT (brickpath);
+ GF_ASSERT (hostname);
+ GF_ASSERT (mount_dir);
+
+ ret = glusterd_hostname_to_uuid (hostname, brick_uuid);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "Failed to convert hostname %s to uuid",
+ hostname);
+ goto out;
+ }
+
+ if (!uuid_compare (brick_uuid, MY_UUID)) {
+ ret = glusterd_get_brick_root (brickpath, &mnt_pt);
+ if (ret) {
+ gf_log (this->name, GF_LOG_WARNING,
+ "Could not get the root of the brick path %s",
+ brickpath);
+ goto out;
+ }
+
+ if (strncmp (brickpath, mnt_pt, strlen(mnt_pt))) {
+ gf_log (this->name, GF_LOG_WARNING,
+ "brick: %s brick mount: %s",
+ brickpath, mnt_pt);
+ ret = -1;
+ goto out;
+ }
+
+ brick_dir = &brickpath[strlen (mnt_pt)];
+ brick_dir++;
+
+ snprintf (mount_dir, PATH_MAX, "/%s", brick_dir);
+ }
+
+out:
+ gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret);
+ return ret;
+}
+
+int32_t
glusterd_brickinfo_new_from_brick (char *brick,
glusterd_brickinfo_t **brickinfo)
{
- int32_t ret = -1;
- glusterd_brickinfo_t *new_brickinfo = NULL;
- char *hostname = NULL;
- char *path = NULL;
- char *tmp_host = NULL;
- char *tmp_path = NULL;
- char *vg = NULL;
+ char *hostname = NULL;
+ char *path = NULL;
+ char *tmp_host = NULL;
+ char *tmp_path = NULL;
+ char *vg = NULL;
+ int32_t ret = -1;
+ glusterd_brickinfo_t *new_brickinfo = NULL;
+ xlator_t *this = NULL;
+ this = THIS;
+ GF_ASSERT (this);
GF_ASSERT (brick);
GF_ASSERT (brickinfo);
@@ -987,7 +1042,8 @@ out:
GF_FREE (tmp_host);
if (tmp_host)
GF_FREE (tmp_path);
- gf_log (THIS->name, GF_LOG_DEBUG, "Returning %d", ret);
+
+ gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret);
return ret;
}
@@ -2565,6 +2621,17 @@ glusterd_add_volume_to_dict (glusterd_volinfo_t *volinfo,
goto out;
}
+ snprintf (key, sizeof (key), "%s%d.brick%d.mount_dir",
+ prefix, count, i);
+ ret = dict_set_str (dict, key, brickinfo->mount_dir);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "Failed to set mount_dir for %s:%s",
+ brickinfo->hostname,
+ brickinfo->path);
+ goto out;
+ }
+
i++;
}
@@ -3485,13 +3552,17 @@ glusterd_import_new_brick (dict_t *peer_data, int32_t vol_count,
int ret = -1;
int32_t snap_status = 0;
char *snap_device = NULL;
+ char *mount_dir = NULL;
char *hostname = NULL;
char *path = NULL;
char *brick_id = NULL;
int decommissioned = 0;
glusterd_brickinfo_t *new_brickinfo = NULL;
char msg[2048] = {0};
+ xlator_t *this = NULL;
+ this = THIS;
+ GF_ASSERT (this);
GF_ASSERT (peer_data);
GF_ASSERT (vol_count >= 0);
GF_ASSERT (brickinfo);
@@ -3545,6 +3616,14 @@ glusterd_import_new_brick (dict_t *peer_data, int32_t vol_count,
goto out;
}
+ snprintf (key, sizeof (key), "%s%d.brick%d.mount_dir",
+ prefix, vol_count, brick_count);
+ ret = dict_get_str (peer_data, key, &mount_dir);
+ if (ret) {
+ snprintf (msg, sizeof (msg), "%s missing in payload", key);
+ goto out;
+ }
+
ret = glusterd_brickinfo_new (&new_brickinfo);
if (ret)
goto out;
@@ -3552,6 +3631,7 @@ glusterd_import_new_brick (dict_t *peer_data, int32_t vol_count,
strcpy (new_brickinfo->path, path);
strcpy (new_brickinfo->hostname, hostname);
strcpy (new_brickinfo->device_path, snap_device);
+ strcpy (new_brickinfo->mount_dir, mount_dir);
new_brickinfo->snap_status = snap_status;
new_brickinfo->decommissioned = decommissioned;
if (brick_id)
@@ -9235,6 +9315,54 @@ glusterd_append_status_dicts (dict_t *dst, dict_t *src)
}
int32_t
+glusterd_aggr_brick_mount_dirs (dict_t *aggr, dict_t *rsp_dict)
+{
+ char key[PATH_MAX] = "";
+ char *brick_mount_dir = NULL;
+ int32_t brick_count = -1;
+ int32_t ret = -1;
+ int32_t i = -1;
+ xlator_t *this = NULL;
+
+ this = THIS;
+ GF_ASSERT (this);
+ GF_ASSERT (aggr);
+ GF_ASSERT (rsp_dict);
+
+ ret = dict_get_int32 (rsp_dict, "brick_count", &brick_count);
+ if (ret) {
+ gf_log (this->name, GF_LOG_DEBUG, "No brick_count present");
+ ret = 0;
+ goto out;
+ }
+
+ for (i = 1; i <= brick_count; i++) {
+ brick_mount_dir = NULL;
+ snprintf (key, sizeof(key), "brick%d.mount_dir", i);
+ ret = dict_get_str (rsp_dict, key, &brick_mount_dir);
+ if (ret) {
+ /* Coz the info will come from a different node */
+ gf_log (this->name, GF_LOG_DEBUG,
+ "%s not present", key);
+ continue;
+ }
+
+ ret = dict_set_dynstr_with_alloc (aggr, key,
+ brick_mount_dir);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "Failed to set %s", key);
+ goto out;
+ }
+ }
+
+ ret = 0;
+out:
+ gf_log (this->name, GF_LOG_TRACE, "Returning %d ", ret);
+ return ret;
+}
+
+int32_t
glusterd_gsync_use_rsp_dict (dict_t *aggr, dict_t *rsp_dict, char *op_errstr)
{
dict_t *ctx = NULL;
@@ -9293,7 +9421,10 @@ glusterd_rb_use_rsp_dict (dict_t *aggr, dict_t *rsp_dict)
int32_t dst_port = 0;
int ret = 0;
dict_t *ctx = NULL;
+ xlator_t *this = NULL;
+ this = THIS;
+ GF_ASSERT (this);
if (aggr) {
ctx = aggr;
@@ -9320,6 +9451,12 @@ glusterd_rb_use_rsp_dict (dict_t *aggr, dict_t *rsp_dict)
"dst-brick-port=%d found", dst_port);
}
+ ret = glusterd_aggr_brick_mount_dirs (ctx, rsp_dict);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to "
+ "aggregate brick mount dirs");
+ goto out;
+ }
}
if (src_port) {
diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.h b/xlators/mgmt/glusterd/src/glusterd-utils.h
index e4d41af64c0..2cf328f91ab 100644
--- a/xlators/mgmt/glusterd/src/glusterd-utils.h
+++ b/xlators/mgmt/glusterd/src/glusterd-utils.h
@@ -780,4 +780,11 @@ glusterd_copy_quota_files (glusterd_volinfo_t *src_vol,
int
glusterd_recursive_rmdir (const char *delete_path);
+
+int32_t
+glusterd_get_brick_mount_dir (char *brickpath, char *hostname, char *mount_dir);
+
+int32_t
+glusterd_aggr_brick_mount_dirs (dict_t *aggr, dict_t *rsp_dict);
+
#endif
diff --git a/xlators/mgmt/glusterd/src/glusterd-volume-ops.c b/xlators/mgmt/glusterd/src/glusterd-volume-ops.c
index 8d126c5cc1a..25b87b661e0 100644
--- a/xlators/mgmt/glusterd/src/glusterd-volume-ops.c
+++ b/xlators/mgmt/glusterd/src/glusterd-volume-ops.c
@@ -714,7 +714,8 @@ out:
/* op-sm */
int
-glusterd_op_stage_create_volume (dict_t *dict, char **op_errstr)
+glusterd_op_stage_create_volume (dict_t *dict, char **op_errstr,
+ dict_t *rsp_dict)
{
int ret = 0;
char *volname = NULL;
@@ -722,8 +723,10 @@ glusterd_op_stage_create_volume (dict_t *dict, char **op_errstr)
char *bricks = NULL;
char *brick_list = NULL;
char *free_ptr = NULL;
+ char key[PATH_MAX] = "";
glusterd_brickinfo_t *brick_info = NULL;
int32_t brick_count = 0;
+ int32_t local_brick_count = 0;
int32_t i = 0;
char *brick = NULL;
char *tmpptr = NULL;
@@ -738,6 +741,7 @@ glusterd_op_stage_create_volume (dict_t *dict, char **op_errstr)
GF_ASSERT (this);
priv = this->private;
GF_ASSERT (priv);
+ GF_ASSERT (rsp_dict);
ret = dict_get_str (dict, "volname", &volname);
if (ret) {
@@ -844,11 +848,40 @@ glusterd_op_stage_create_volume (dict_t *dict, char **op_errstr)
is_force);
if (ret)
goto out;
+
+ ret = glusterd_get_brick_mount_dir
+ (brick_info->path,
+ brick_info->hostname,
+ brick_info->mount_dir);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "Failed to get brick mount_dir");
+ goto out;
+ }
+
+ snprintf (key, sizeof(key), "brick%d.mount_dir", i);
+ ret = dict_set_dynstr_with_alloc
+ (rsp_dict, key,
+ brick_info->mount_dir);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "Failed to set %s", key);
+ goto out;
+ }
+ local_brick_count = i;
+
brick_list = tmpptr;
}
glusterd_brickinfo_delete (brick_info);
brick_info = NULL;
}
+
+ ret = dict_set_int32 (rsp_dict, "brick_count", local_brick_count);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "Failed to set local_brick_count");
+ goto out;
+ }
out:
GF_FREE (free_ptr);
if (brick_info)
@@ -922,11 +955,15 @@ out:
}
int
-glusterd_op_stage_start_volume (dict_t *dict, char **op_errstr)
+glusterd_op_stage_start_volume (dict_t *dict, char **op_errstr,
+ dict_t *rsp_dict)
{
int ret = 0;
char *volname = NULL;
+ char key[PATH_MAX] = "";
int flags = 0;
+ int32_t brick_count = 0;
+ int32_t local_brick_count = 0;
gf_boolean_t exists = _gf_false;
glusterd_volinfo_t *volinfo = NULL;
glusterd_brickinfo_t *brickinfo = NULL;
@@ -942,6 +979,7 @@ glusterd_op_stage_start_volume (dict_t *dict, char **op_errstr)
GF_ASSERT (this);
priv = this->private;
GF_ASSERT (priv);
+ GF_ASSERT (rsp_dict);
ret = glusterd_op_start_volume_args_get (dict, &volname, &flags);
if (ret)
@@ -976,6 +1014,7 @@ glusterd_op_stage_start_volume (dict_t *dict, char **op_errstr)
}
list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) {
+ brick_count++;
ret = glusterd_resolve_brick (brickinfo);
if (ret) {
gf_log (this->name, GF_LOG_ERROR, FMTSTR_RESOLVE_BRICK,
@@ -983,7 +1022,8 @@ glusterd_op_stage_start_volume (dict_t *dict, char **op_errstr)
goto out;
}
- if (uuid_compare (brickinfo->uuid, MY_UUID))
+ if ((uuid_compare (brickinfo->uuid, MY_UUID)) ||
+ (brickinfo->snap_status == -1))
continue;
ret = gf_lstat_dir (brickinfo->path, NULL);
@@ -1030,6 +1070,30 @@ glusterd_op_stage_start_volume (dict_t *dict, char **op_errstr)
ret = -1;
goto out;
}
+
+ if (strlen(brickinfo->mount_dir) < 1) {
+ ret = glusterd_get_brick_mount_dir
+ (brickinfo->path,
+ brickinfo->hostname,
+ brickinfo->mount_dir);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "Failed to get brick mount_dir");
+ goto out;
+ }
+
+ snprintf (key, sizeof(key), "brick%d.mount_dir",
+ brick_count);
+ ret = dict_set_dynstr_with_alloc
+ (rsp_dict, key,
+ brickinfo->mount_dir);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "Failed to set %s", key);
+ goto out;
+ }
+ local_brick_count = brick_count;
+ }
#ifdef HAVE_BD_XLATOR
if (brickinfo->vg[0])
caps = CAPS_BD | CAPS_THIN |
@@ -1047,6 +1111,13 @@ glusterd_op_stage_start_volume (dict_t *dict, char **op_errstr)
#endif
}
+ ret = dict_set_int32 (rsp_dict, "brick_count", local_brick_count);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "Failed to set local_brick_count");
+ goto out;
+ }
+
volinfo->caps = caps;
ret = 0;
out:
@@ -1507,6 +1578,8 @@ glusterd_op_create_volume (dict_t *dict, char **op_errstr)
int caps = 0;
int brickid = 0;
char msg[1024] __attribute__((unused)) = {0, };
+ char *brick_mount_dir = NULL;
+ char key[PATH_MAX] = "";
this = THIS;
GF_ASSERT (this);
@@ -1689,6 +1762,17 @@ glusterd_op_create_volume (dict_t *dict, char **op_errstr)
goto out;
}
+ brick_mount_dir = NULL;
+ snprintf (key, sizeof(key), "brick%d.mount_dir", i);
+ ret = dict_get_str (dict, key, &brick_mount_dir);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "%s not present", key);
+ goto out;
+ }
+ strncpy (brickinfo->mount_dir, brick_mount_dir,
+ sizeof(brickinfo->mount_dir));
+
#ifdef HAVE_BD_XLATOR
if (!uuid_compare (brickinfo->uuid, MY_UUID)) {
if (brickinfo->vg[0]) {
@@ -1792,11 +1876,15 @@ out:
int
glusterd_op_start_volume (dict_t *dict, char **op_errstr)
{
- int ret = 0;
- char *volname = NULL;
- int flags = 0;
- glusterd_volinfo_t *volinfo = NULL;
- xlator_t *this = NULL;
+ int ret = 0;
+ int32_t brick_count = 0;
+ char *brick_mount_dir = NULL;
+ char key[PATH_MAX] = "";
+ char *volname = NULL;
+ int flags = 0;
+ glusterd_volinfo_t *volinfo = NULL;
+ glusterd_brickinfo_t *brickinfo = NULL;
+ xlator_t *this = NULL;
this = THIS;
GF_ASSERT (this);
@@ -1812,8 +1900,24 @@ glusterd_op_start_volume (dict_t *dict, char **op_errstr)
goto out;
}
- ret = glusterd_start_volume (volinfo, flags);
+ list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) {
+ brick_count++;
+ if (strlen(brickinfo->mount_dir) < 1) {
+ brick_mount_dir = NULL;
+ snprintf (key, sizeof(key), "brick%d.mount_dir",
+ brick_count);
+ ret = dict_get_str (dict, key, &brick_mount_dir);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "%s not present", key);
+ goto out;
+ }
+ strncpy (brickinfo->mount_dir, brick_mount_dir,
+ sizeof(brickinfo->mount_dir));
+ }
+ }
+ ret = glusterd_start_volume (volinfo, flags);
if (ret)
goto out;
diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h
index 2f63d07aac4..fc2ae12cbfa 100644
--- a/xlators/mgmt/glusterd/src/glusterd.h
+++ b/xlators/mgmt/glusterd/src/glusterd.h
@@ -191,6 +191,7 @@ struct glusterd_brickinfo {
char hostname[1024];
char path[PATH_MAX];
char device_path[PATH_MAX];
+ char mount_dir[PATH_MAX];
char brick_id[1024];/*Client xlator name, AFR changelog name*/
struct list_head brick_list;
uuid_t uuid;
@@ -903,8 +904,10 @@ int glusterd_op_stage_replace_brick (dict_t *dict, char **op_errstr,
int glusterd_op_replace_brick (dict_t *dict, dict_t *rsp_dict);
int glusterd_op_log_rotate (dict_t *dict);
int glusterd_op_stage_log_rotate (dict_t *dict, char **op_errstr);
-int glusterd_op_stage_create_volume (dict_t *dict, char **op_errstr);
-int glusterd_op_stage_start_volume (dict_t *dict, char **op_errstr);
+int glusterd_op_stage_create_volume (dict_t *dict, char **op_errstr,
+ dict_t *rsp_dict);
+int glusterd_op_stage_start_volume (dict_t *dict, char **op_errstr,
+ dict_t *rsp_dict);
int glusterd_op_stage_stop_volume (dict_t *dict, char **op_errstr);
int glusterd_op_stage_delete_volume (dict_t *dict, char **op_errstr);
int glusterd_op_create_volume (dict_t *dict, char **op_errstr);
@@ -914,7 +917,8 @@ int glusterd_op_delete_volume (dict_t *dict);
int glusterd_op_add_brick (dict_t *dict, char **op_errstr);
int glusterd_op_remove_brick (dict_t *dict, char **op_errstr);
-int glusterd_op_stage_add_brick (dict_t *dict, char **op_errstr);
+int glusterd_op_stage_add_brick (dict_t *dict, char **op_errstr,
+ dict_t *rsp_dict);
int glusterd_op_stage_remove_brick (dict_t *dict, char **op_errstr);
int glusterd_op_stage_rebalance (dict_t *dict, char **op_errstr);