diff options
-rw-r--r-- | api/src/glfs-internal.h | 4 | ||||
-rw-r--r-- | api/src/glfs-mgmt.c | 250 | ||||
-rw-r--r-- | api/src/glfs.h | 32 | ||||
-rw-r--r-- | rpc/rpc-lib/src/protocol-common.h | 8 | ||||
-rw-r--r-- | rpc/xdr/src/glusterfs3-xdr.c | 79 | ||||
-rw-r--r-- | rpc/xdr/src/glusterfs3-xdr.h | 56 | ||||
-rw-r--r-- | rpc/xdr/src/glusterfs3-xdr.x | 10 | ||||
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-handshake.c | 137 |
8 files changed, 530 insertions, 46 deletions
diff --git a/api/src/glfs-internal.h b/api/src/glfs-internal.h index ec1d5579df7..6ed4aeae16f 100644 --- a/api/src/glfs-internal.h +++ b/api/src/glfs-internal.h @@ -60,6 +60,7 @@ typedef int (*glfs_init_cbk) (struct glfs *fs, int ret); struct glfs { char *volname; + uuid_t vol_uuid; glusterfs_ctx_t *ctx; @@ -197,4 +198,7 @@ void glfs_iatt_to_stat (struct glfs *fs, struct iatt *iatt, struct stat *stat); int glfs_loc_link (loc_t *loc, struct iatt *iatt); int glfs_loc_unlink (loc_t *loc); +/* Sends RPC call to glusterd to fetch required volume info */ +int glfs_get_volume_info (struct glfs *fs); + #endif /* !_GLFS_INTERNAL_H */ diff --git a/api/src/glfs-mgmt.c b/api/src/glfs-mgmt.c index 5493e89db81..2557186ebd8 100644 --- a/api/src/glfs-mgmt.c +++ b/api/src/glfs-mgmt.c @@ -22,6 +22,7 @@ #endif /* _CONFIG_H */ #include "glusterfs.h" +#include "glfs.h" #include "stack.h" #include "dict.h" #include "event.h" @@ -39,8 +40,9 @@ #include "glfs-internal.h" #include "glfs-mem-types.h" - int glfs_volfile_fetch (struct glfs *fs); +int32_t glfs_get_volume_info_rpc (call_frame_t *frame, xlator_t *this, + struct glfs *fs); int glfs_process_volfp (struct glfs *fs, FILE *fp) @@ -135,6 +137,7 @@ char *clnt_handshake_procs[GF_HNDSK_MAXVALUE] = { [GF_HNDSK_GETSPEC] = "GETSPEC", [GF_HNDSK_PING] = "PING", [GF_HNDSK_EVENT_NOTIFY] = "EVENTNOTIFY", + [GF_HNDSK_GET_VOLUME_INFO] = "GETVOLUMEINFO", }; rpc_clnt_prog_t clnt_handshake_prog = { @@ -201,6 +204,249 @@ out: return ret; } +/* + * Callback routine for 'GF_HNDSK_GET_VOLUME_INFO' rpc request + */ +int +mgmt_get_volinfo_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + int ret = 0; + char *volume_id_str = NULL; + dict_t *dict = NULL; + char key[1024] = {0}; + gf_get_volume_info_rsp rsp = {0,}; + call_frame_t *frame = NULL; + glusterfs_ctx_t *ctx = NULL; + struct glfs *fs = NULL; + struct syncargs *args; + + frame = myframe; + ctx = frame->this->ctx; + args = frame->local; + + if (!ctx) { + gf_log (frame->this->name, GF_LOG_ERROR, "NULL context"); + errno = EINVAL; + ret = -1; + goto out; + } + + fs = ((xlator_t *)ctx->master)->private; + + if (-1 == req->rpc_status) { + gf_log (frame->this->name, GF_LOG_ERROR, + "GET_VOLUME_INFO RPC call is not successfull"); + errno = EINVAL; + ret = -1; + goto out; + } + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_get_volume_info_rsp); + + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Failed to decode xdr response for GET_VOLUME_INFO"); + goto out; + } + + gf_log (frame->this->name, GF_LOG_DEBUG, + "Received resp to GET_VOLUME_INFO RPC: %d", rsp.op_ret); + + if (rsp.op_ret == -1) { + errno = rsp.op_errno; + ret = -1; + goto out; + } + + if (!rsp.dict.dict_len) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Response received for GET_VOLUME_INFO RPC call is not valid"); + ret = -1; + errno = EINVAL; + goto out; + } + + dict = dict_new (); + + if (!dict) { + ret = -1; + errno = ENOMEM; + goto out; + } + + ret = dict_unserialize (rsp.dict.dict_val, + rsp.dict.dict_len, + &dict); + + if (ret) { + errno = ENOMEM; + goto out; + } + + snprintf (key, sizeof (key), "volume_id"); + ret = dict_get_str (dict, key, &volume_id_str); + if (ret) { + errno = EINVAL; + goto out; + } + + ret = 0; +out: + if (volume_id_str) { + gf_log (frame->this->name, GF_LOG_DEBUG, + "Volume Id: %s", volume_id_str); + pthread_mutex_lock (&fs->mutex); + uuid_parse (volume_id_str, fs->vol_uuid); + pthread_mutex_unlock (&fs->mutex); + } + + if (ret) { + gf_log (frame->this->name, GF_LOG_ERROR, + "In GET_VOLUME_INFO cbk, received error: %s", + strerror(errno)); + } + + if (dict) + dict_destroy (dict); + + if (rsp.dict.dict_val) + free (rsp.dict.dict_val); + + if (rsp.op_errstr && *rsp.op_errstr) + free (rsp.op_errstr); + + gf_log (frame->this->name, GF_LOG_DEBUG, "Returning: %d", ret); + + __wake (args); + + return ret; +} + +int +glfs_get_volumeid (struct glfs *fs, char *volid, size_t size) +{ + /* TODO: Define a global macro to store UUID size */ + size_t uuid_size = 16; + + pthread_mutex_lock (&fs->mutex); + { + /* check if the volume uuid is initialized */ + if (!uuid_is_null (fs->vol_uuid)) { + pthread_mutex_unlock (&fs->mutex); + goto done; + } + } + pthread_mutex_unlock (&fs->mutex); + + /* Need to fetch volume_uuid */ + glfs_get_volume_info (fs); + + if (uuid_is_null (fs->vol_uuid)) { + gf_log (THIS->name, GF_LOG_ERROR, "Unable to fetch volume UUID"); + return -1; + } + +done: + if (!volid || !size) { + gf_log (THIS->name, GF_LOG_DEBUG, "volumeid/size is null"); + return uuid_size; + } + + if (size < uuid_size) { + gf_log (THIS->name, GF_LOG_ERROR, "Insufficient size passed"); + errno = ERANGE; + return -1; + } + + memcpy (volid, fs->vol_uuid, uuid_size); + + gf_log (THIS->name, GF_LOG_INFO, "volume uuid: %s", volid); + + return uuid_size; +} + +int +glfs_get_volume_info (struct glfs *fs) +{ + call_frame_t *frame = NULL; + glusterfs_ctx_t *ctx = NULL; + struct syncargs args = {0, }; + int ret = 0; + + ctx = fs->ctx; + frame = create_frame (THIS, ctx->pool); + frame->local = &args; + + __yawn ((&args)); + + ret = glfs_get_volume_info_rpc (frame, THIS, fs); + if (ret) + goto out; + + __yield ((&args)); + + frame->local = NULL; + STACK_DESTROY (frame->root); + +out: + return ret; +} + +int32_t +glfs_get_volume_info_rpc (call_frame_t *frame, xlator_t *this, + struct glfs *fs) +{ + gf_get_volume_info_req req = {{0,}}; + int ret = 0; + glusterfs_ctx_t *ctx = NULL; + dict_t *dict = NULL; + int32_t flags = 0; + + if (!frame || !this || !fs) { + ret = -1; + goto out; + } + + ctx = fs->ctx; + + dict = dict_new (); + if (!dict) { + ret = -1; + goto out; + } + + if (fs->volname) { + ret = dict_set_str (dict, "volname", fs->volname); + if (ret) + goto out; + } + + // Set the flags for the fields which we are interested in + flags = (int32_t)GF_GET_VOLUME_UUID; //ctx->flags; + ret = dict_set_int32 (dict, "flags", flags); + if (ret) { + gf_log (frame->this->name, GF_LOG_ERROR, "failed to set flags"); + goto out; + } + + ret = dict_allocate_and_serialize (dict, &req.dict.dict_val, + &req.dict.dict_len); + + + ret = mgmt_submit_request (&req, frame, ctx, &clnt_handshake_prog, + GF_HNDSK_GET_VOLUME_INFO, + mgmt_get_volinfo_cbk, + (xdrproc_t)xdr_gf_get_volume_info_req); +out: + if (dict) { + dict_unref (dict); + } + + GF_FREE (req.dict.dict_val); + + return ret; +} static int glusterfs_oldvolfile_update (struct glfs *fs, char *volfile, ssize_t size) @@ -502,7 +748,7 @@ mgmt_rpc_notify (struct rpc_clnt *rpc, void *mydata, rpc_clnt_event_t event, glfs_init_done (fs, -1); } - break; + break; default: break; } diff --git a/api/src/glfs.h b/api/src/glfs.h index 2210c26d34f..964422aab72 100644 --- a/api/src/glfs.h +++ b/api/src/glfs.h @@ -257,6 +257,38 @@ int glfs_init (glfs_t *fs); int glfs_fini (glfs_t *fs); + +/* + SYNOPSIS + + glfs_get_volumeid: Copy the Volume UUID stored in the glfs object fs. + + DESCRIPTION + + This function when invoked for the first time sends RPC call to the + the management server (glusterd) to fetch volume uuid and stores it + in the glusterfs_context linked to the glfs object fs which can be used + in the subsequent calls. Later it parses that UUID to convert it from + cannonical string format into an opaque byte array and copy it into + the volid array. Incase if either of the input parameters, volid or size, + is NULL, number of bytes required to copy the volume UUID is returned. + + PARAMETERS + + @fs: The 'virtual mount' object to be used to retrieve and store + volume's UUID. + @volid: Pointer to a place for the volume UUID to be stored + @size: Length of @volid + + RETURN VALUES + + -1 : Failure. @errno will be set with the type of failure. + Others : length of the volume UUID stored. +*/ + +int glfs_get_volumeid (struct glfs *fs, char *volid, size_t size); + + /* * FILE OPERATION * diff --git a/rpc/rpc-lib/src/protocol-common.h b/rpc/rpc-lib/src/protocol-common.h index 5876a500bdf..d44de48377c 100644 --- a/rpc/rpc-lib/src/protocol-common.h +++ b/rpc/rpc-lib/src/protocol-common.h @@ -69,6 +69,7 @@ enum gf_handshake_procnum { GF_HNDSK_PING, GF_HNDSK_SET_LK_VER, GF_HNDSK_EVENT_NOTIFY, + GF_HNDSK_GET_VOLUME_INFO, GF_HNDSK_MAXVALUE, }; @@ -238,6 +239,13 @@ struct gf_gsync_detailed_status_ { typedef struct gf_gsync_detailed_status_ gf_gsync_status_t; +enum gf_get_volume_info_type { + GF_GET_VOLUME_NONE, /* 0 */ + GF_GET_VOLUME_UUID +}; + +typedef enum gf_get_volume_info_type gf_get_volume_info_type; + #define GLUSTER_HNDSK_PROGRAM 14398633 /* Completely random */ #define GLUSTER_HNDSK_VERSION 2 /* 0.0.2 */ diff --git a/rpc/xdr/src/glusterfs3-xdr.c b/rpc/xdr/src/glusterfs3-xdr.c index 3205c551e5b..45efd860a0d 100644 --- a/rpc/xdr/src/glusterfs3-xdr.c +++ b/rpc/xdr/src/glusterfs3-xdr.c @@ -1587,44 +1587,41 @@ xdr_gfs3_discard_rsp (XDR *xdrs, gfs3_discard_rsp *objp) bool_t xdr_gfs3_zerofill_req (XDR *xdrs, gfs3_zerofill_req *objp) { - register int32_t *buf; + register int32_t *buf; buf = NULL; - if (!xdr_opaque (xdrs, objp->gfid, 16)) - return FALSE; - if (!xdr_quad_t (xdrs, &objp->fd)) - return FALSE; - if (!xdr_u_quad_t (xdrs, &objp->offset)) - return FALSE; - if (!xdr_u_quad_t (xdrs, &objp->size)) - return FALSE; - if (!xdr_bytes (xdrs, (char **)&objp->xdata.xdata_val, - (u_int *) &objp->xdata.xdata_len, ~0)) - return FALSE; - return TRUE; + if (!xdr_opaque (xdrs, objp->gfid, 16)) + return FALSE; + if (!xdr_quad_t (xdrs, &objp->fd)) + return FALSE; + if (!xdr_u_quad_t (xdrs, &objp->offset)) + return FALSE; + if (!xdr_u_quad_t (xdrs, &objp->size)) + return FALSE; + if (!xdr_bytes (xdrs, (char **)&objp->xdata.xdata_val, (u_int *) &objp->xdata.xdata_len, ~0)) + return FALSE; + return TRUE; } bool_t xdr_gfs3_zerofill_rsp (XDR *xdrs, gfs3_zerofill_rsp *objp) { - register int32_t *buf; + register int32_t *buf; buf = NULL; - if (!xdr_int (xdrs, &objp->op_ret)) - return FALSE; - if (!xdr_int (xdrs, &objp->op_errno)) - return FALSE; - if (!xdr_gf_iatt (xdrs, &objp->statpre)) - return FALSE; - if (!xdr_gf_iatt (xdrs, &objp->statpost)) - return FALSE; - if (!xdr_bytes (xdrs, (char **)&objp->xdata.xdata_val, - (u_int *) &objp->xdata.xdata_len, ~0)) - return FALSE; - return TRUE; + if (!xdr_int (xdrs, &objp->op_ret)) + return FALSE; + if (!xdr_int (xdrs, &objp->op_errno)) + return FALSE; + if (!xdr_gf_iatt (xdrs, &objp->statpre)) + return FALSE; + if (!xdr_gf_iatt (xdrs, &objp->statpost)) + return FALSE; + if (!xdr_bytes (xdrs, (char **)&objp->xdata.xdata_val, (u_int *) &objp->xdata.xdata_len, ~0)) + return FALSE; + return TRUE; } - bool_t xdr_gfs3_rchecksum_req (XDR *xdrs, gfs3_rchecksum_req *objp) { @@ -1763,6 +1760,34 @@ xdr_gf_getspec_rsp (XDR *xdrs, gf_getspec_rsp *objp) } bool_t +xdr_gf_get_volume_info_req (XDR *xdrs, gf_get_volume_info_req *objp) +{ + register int32_t *buf; + buf = NULL; + + if (!xdr_bytes (xdrs, (char **)&objp->dict.dict_val, (u_int *) &objp->dict.dict_len, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_gf_get_volume_info_rsp (XDR *xdrs, gf_get_volume_info_rsp *objp) +{ + register int32_t *buf; + buf = NULL; + + if (!xdr_int (xdrs, &objp->op_ret)) + return FALSE; + if (!xdr_int (xdrs, &objp->op_errno)) + return FALSE; + if (!xdr_string (xdrs, &objp->op_errstr, ~0)) + return FALSE; + if (!xdr_bytes (xdrs, (char **)&objp->dict.dict_val, (u_int *) &objp->dict.dict_len, ~0)) + return FALSE; + return TRUE; +} + +bool_t xdr_gf_mgmt_hndsk_req (XDR *xdrs, gf_mgmt_hndsk_req *objp) { register int32_t *buf; diff --git a/rpc/xdr/src/glusterfs3-xdr.h b/rpc/xdr/src/glusterfs3-xdr.h index 13566e69447..ac74cca5cc1 100644 --- a/rpc/xdr/src/glusterfs3-xdr.h +++ b/rpc/xdr/src/glusterfs3-xdr.h @@ -937,30 +937,29 @@ struct gfs3_discard_rsp { typedef struct gfs3_discard_rsp gfs3_discard_rsp; struct gfs3_zerofill_req { - char gfid[16]; - quad_t fd; - u_quad_t offset; - u_quad_t size; - struct { - u_int xdata_len; - char *xdata_val; - } xdata; + char gfid[16]; + quad_t fd; + u_quad_t offset; + u_quad_t size; + struct { + u_int xdata_len; + char *xdata_val; + } xdata; }; typedef struct gfs3_zerofill_req gfs3_zerofill_req; struct gfs3_zerofill_rsp { - int op_ret; - int op_errno; - struct gf_iatt statpre; - struct gf_iatt statpost; - struct { - u_int xdata_len; - char *xdata_val; - } xdata; + int op_ret; + int op_errno; + struct gf_iatt statpre; + struct gf_iatt statpost; + struct { + u_int xdata_len; + char *xdata_val; + } xdata; }; typedef struct gfs3_zerofill_rsp gfs3_zerofill_rsp; - struct gfs3_rchecksum_req { quad_t fd; u_quad_t offset; @@ -1026,6 +1025,25 @@ struct gf_getspec_rsp { }; typedef struct gf_getspec_rsp gf_getspec_rsp; +struct gf_get_volume_info_req { + struct { + u_int dict_len; + char *dict_val; + } dict; +}; +typedef struct gf_get_volume_info_req gf_get_volume_info_req; + +struct gf_get_volume_info_rsp { + int op_ret; + int op_errno; + char *op_errstr; + struct { + u_int dict_len; + char *dict_val; + } dict; +}; +typedef struct gf_get_volume_info_rsp gf_get_volume_info_rsp; + struct gf_mgmt_hndsk_req { struct { u_int hndsk_len; @@ -1268,6 +1286,8 @@ extern bool_t xdr_gf_setvolume_req (XDR *, gf_setvolume_req*); extern bool_t xdr_gf_setvolume_rsp (XDR *, gf_setvolume_rsp*); extern bool_t xdr_gf_getspec_req (XDR *, gf_getspec_req*); extern bool_t xdr_gf_getspec_rsp (XDR *, gf_getspec_rsp*); +extern bool_t xdr_gf_get_volume_info_req (XDR *, gf_get_volume_info_req*); +extern bool_t xdr_gf_get_volume_info_rsp (XDR *, gf_get_volume_info_rsp*); extern bool_t xdr_gf_mgmt_hndsk_req (XDR *, gf_mgmt_hndsk_req*); extern bool_t xdr_gf_mgmt_hndsk_rsp (XDR *, gf_mgmt_hndsk_rsp*); extern bool_t xdr_gf_log_req (XDR *, gf_log_req*); @@ -1368,6 +1388,8 @@ extern bool_t xdr_gf_setvolume_req (); extern bool_t xdr_gf_setvolume_rsp (); extern bool_t xdr_gf_getspec_req (); extern bool_t xdr_gf_getspec_rsp (); +extern bool_t xdr_gf_get_volume_info_req (); +extern bool_t xdr_gf_get_volume_info_rsp (); extern bool_t xdr_gf_mgmt_hndsk_req (); extern bool_t xdr_gf_mgmt_hndsk_rsp (); extern bool_t xdr_gf_log_req (); diff --git a/rpc/xdr/src/glusterfs3-xdr.x b/rpc/xdr/src/glusterfs3-xdr.x index 1edbda3ada9..1c6bf4be244 100644 --- a/rpc/xdr/src/glusterfs3-xdr.x +++ b/rpc/xdr/src/glusterfs3-xdr.x @@ -653,6 +653,16 @@ struct gfs3_fstat_req { opaque xdata<>; /* Extra data */ } ; + struct gf_get_volume_info_req { + opaque dict<>; /* Extra data */ +} ; + struct gf_get_volume_info_rsp { + int op_ret; + int op_errno; + string op_errstr<>; + opaque dict<>; /* Extra data */ +} ; + struct gf_mgmt_hndsk_req { opaque hndsk<>; } ; diff --git a/xlators/mgmt/glusterd/src/glusterd-handshake.c b/xlators/mgmt/glusterd/src/glusterd-handshake.c index 1420eb692ee..87958d0701b 100644 --- a/xlators/mgmt/glusterd/src/glusterd-handshake.c +++ b/xlators/mgmt/glusterd/src/glusterd-handshake.c @@ -591,10 +591,147 @@ glusterd_mgmt_hndsk_versions_ack (rpcsvc_request_t *req) __glusterd_mgmt_hndsk_versions_ack); } +int +__server_get_volume_info (rpcsvc_request_t *req) +{ + int ret = -1; + int32_t op_errno = ENOENT; + gf_get_volume_info_req vol_info_req = {{0,}}; + gf_get_volume_info_rsp vol_info_rsp = {0,}; + char *volname = NULL; + glusterd_volinfo_t *volinfo = NULL; + dict_t *dict = NULL; + dict_t *dict_rsp = NULL; + char *volume_id_str = NULL; + int32_t flags = 0; + + ret = xdr_to_generic (req->msg[0], &vol_info_req, + (xdrproc_t)xdr_gf_get_volume_info_req); + if (ret < 0) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + gf_log ("glusterd", GF_LOG_INFO, "Received get volume info req"); + + if (vol_info_req.dict.dict_len) { + /* Unserialize the dictionary */ + dict = dict_new (); + if (!dict) { + gf_log ("", GF_LOG_WARNING, "Out of Memory"); + op_errno = ENOMEM; + ret = -1; + goto out; + } + + ret = dict_unserialize (vol_info_req.dict.dict_val, + vol_info_req.dict.dict_len, + &dict); + if (ret < 0) { + gf_log ("glusterd", GF_LOG_ERROR, + "failed to " + "unserialize req-buffer to dictionary"); + op_errno = -ret; + ret = -1; + goto out; + } else { + dict->extra_stdfree = vol_info_req.dict.dict_val; + } + } + + ret = dict_get_int32 (dict, "flags", &flags); + if (ret) { + gf_log (THIS->name, GF_LOG_ERROR, "failed to get flags"); + op_errno = -ret; + ret = -1; + goto out; + } + + if (!flags) { + //Nothing to query about. Just return success + gf_log (THIS->name, GF_LOG_ERROR, "No flags set"); + ret = 0; + goto out; + } + + ret = dict_get_str (dict, "volname", &volname); + if (ret) { + op_errno = EINVAL; + ret = -1; + goto out; + } + + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + op_errno = EINVAL; + ret = -1; + goto out; + } + + if (flags | (int32_t)GF_GET_VOLUME_UUID) { + volume_id_str = gf_strdup (uuid_utoa (volinfo->volume_id)); + if (!volume_id_str) { + op_errno = ENOMEM; + ret = -1; + goto out; + } + + dict_rsp = dict_new (); + if (!dict_rsp) { + gf_log ("", GF_LOG_WARNING, "Out of Memory"); + op_errno = ENOMEM; + ret = -1; + goto out; + } + ret = dict_set_dynstr (dict_rsp, "volume_id", volume_id_str); + if (ret) { + op_errno = -ret; + ret = -1; + goto out; + } + } + ret = dict_allocate_and_serialize (dict_rsp, &vol_info_rsp.dict.dict_val, + &vol_info_rsp.dict.dict_len); + if (ret) { + op_errno = -ret; + ret = -1; + goto out; + } + +out: + vol_info_rsp.op_ret = ret; + vol_info_rsp.op_errno = op_errno; + vol_info_rsp.op_errstr = ""; + glusterd_submit_reply (req, &vol_info_rsp, NULL, 0, NULL, + (xdrproc_t)xdr_gf_get_volume_info_rsp); + ret = 0; + + if (dict) { + dict_unref (dict); + } + + if (dict_rsp) { + dict_unref (dict_rsp); + } + + if (vol_info_rsp.dict.dict_val) { + GF_FREE (vol_info_rsp.dict.dict_val); + } + return ret; +} + +int +server_get_volume_info (rpcsvc_request_t *req) +{ + return glusterd_big_locked_handler (req, + __server_get_volume_info); +} + rpcsvc_actor_t gluster_handshake_actors[] = { [GF_HNDSK_NULL] = {"NULL", GF_HNDSK_NULL, NULL, NULL, 0, DRC_NA}, [GF_HNDSK_GETSPEC] = {"GETSPEC", GF_HNDSK_GETSPEC, server_getspec, NULL, 0, DRC_NA}, [GF_HNDSK_EVENT_NOTIFY] = {"EVENTNOTIFY", GF_HNDSK_EVENT_NOTIFY, server_event_notify, NULL, 0, DRC_NA}, + [GF_HNDSK_GET_VOLUME_INFO] = {"GETVOLUMEINFO", GF_HNDSK_GET_VOLUME_INFO, server_get_volume_info, NULL, 0, DRC_NA}, }; |