/* Copyright (c) 2008-2012 Red Hat, Inc. This file is part of GlusterFS. This file is licensed to you under your choice of the GNU Lesser General Public License, version 3 or any later version (LGPLv3 or later), or the GNU General Public License, version 2 (GPLv2), in all cases as published by the Free Software Foundation. */ #ifndef _CLIENT_H #define _CLIENT_H #include #include #include "rpc-clnt.h" #include #include #include "client-mem-types.h" #include "protocol-common.h" #include "glusterfs3.h" #include "glusterfs3-xdr.h" #include #include #include #include "client-messages.h" /* FIXME: Needs to be defined in a common file */ #define CLIENT_DUMP_LOCKS "trusted.glusterfs.clientlk-dump" #define GF_MAX_SOCKET_WINDOW_SIZE (1 * GF_UNIT_MB) #define GF_MIN_SOCKET_WINDOW_SIZE (0) typedef enum { DEFAULT_REMOTE_FD = 0, FALLBACK_TO_ANON_FD = 1 } clnt_remote_fd_flags_t; #define CPD_REQ_FIELD(v, f) (v)->compound_req_u.compound_##f##_req #define CPD_RSP_FIELD(v, f) (v)->compound_rsp_u.compound_##f##_rsp #define CLIENT_POST_FOP(fop, this_rsp_u, this_args_cbk, params...) \ do { \ gf_common_rsp *_this_rsp = &CPD_RSP_FIELD(this_rsp_u, fop); \ int _op_ret = 0; \ int _op_errno = 0; \ \ _op_ret = _this_rsp->op_ret; \ _op_errno = gf_error_to_errno(_this_rsp->op_errno); \ args_##fop##_cbk_store(this_args_cbk, _op_ret, _op_errno, params); \ } while (0) #define CLIENT_POST_FOP_TYPE(fop, this_rsp_u, this_args_cbk, params...) \ do { \ gfs3_##fop##_rsp *_this_rsp = &CPD_RSP_FIELD(this_rsp_u, fop); \ int _op_ret = 0; \ int _op_errno = 0; \ \ _op_ret = _this_rsp->op_ret; \ _op_errno = gf_error_to_errno(_this_rsp->op_errno); \ args_##fop##_cbk_store(this_args_cbk, _op_ret, _op_errno, params); \ } while (0) #define CLIENT_PRE_FOP(fop, xl, compound_req, op_errno, label, params...) \ do { \ gfs3_##fop##_req *_req = (gfs3_##fop##_req *)compound_req; \ int _ret = 0; \ \ _ret = client_pre_##fop(xl, _req, params); \ if (_ret < 0) { \ op_errno = -ret; \ goto label; \ } \ } while (0) #define CLIENT_COMPOUND_FOP_CLEANUP(curr_req, fop) \ do { \ gfs3_##fop##_req *_req = &CPD_REQ_FIELD(curr_req, fop); \ \ GF_FREE(_req->xdata.xdata_val); \ } while (0) #define CLIENT_COMMON_RSP_CLEANUP(rsp, fop, i) \ do { \ compound_rsp *this_rsp = NULL; \ this_rsp = &rsp->compound_rsp_array.compound_rsp_array_val[i]; \ gf_common_rsp *_this_rsp = &CPD_RSP_FIELD(this_rsp, fop); \ \ free(_this_rsp->xdata.xdata_val); \ } while (0) #define CLIENT_FOP_RSP_CLEANUP(rsp, fop, i) \ do { \ compound_rsp *this_rsp = NULL; \ this_rsp = &rsp->compound_rsp_array.compound_rsp_array_val[i]; \ gfs3_##fop##_rsp *_this_rsp = &CPD_RSP_FIELD(this_rsp, fop); \ \ free(_this_rsp->xdata.xdata_val); \ } while (0) #define CLIENT_GET_REMOTE_FD(xl, fd, flags, remote_fd, op_errno, label) \ do { \ int _ret = 0; \ _ret = client_get_remote_fd(xl, fd, flags, &remote_fd); \ if (_ret < 0) { \ op_errno = errno; \ goto label; \ } \ if (remote_fd == -1) { \ gf_msg(xl->name, GF_LOG_WARNING, EBADFD, PC_MSG_BAD_FD, \ " (%s) " \ "remote_fd is -1. EBADFD", \ uuid_utoa(fd->inode->gfid)); \ op_errno = EBADFD; \ goto label; \ } \ } while (0) #define CLIENT_STACK_UNWIND(op, frame, params...) \ do { \ if (!frame) \ break; \ clnt_local_t *__local = frame->local; \ frame->local = NULL; \ STACK_UNWIND_STRICT(op, frame, params); \ client_local_wipe(__local); \ } while (0) /* compound v2 */ #define CPD4_REQ_FIELD(v, f) ((v)->compound_req_v2_u.compound_##f##_req) #define CPD4_RSP_FIELD(v, f) ((v)->compound_rsp_v2_u.compound_##f##_rsp) #define CLIENT4_POST_FOP(fop, this_rsp_u, this_args_cbk, params...) \ do { \ gfx_common_rsp *_this_rsp = &CPD4_RSP_FIELD(this_rsp_u, fop); \ int _op_ret = 0; \ int _op_errno = 0; \ \ _op_ret = _this_rsp->op_ret; \ _op_errno = gf_error_to_errno(_this_rsp->op_errno); \ args_##fop##_cbk_store(this_args_cbk, _op_ret, _op_errno, params); \ } while (0) #define CLIENT4_POST_FOP_TYPE(fop, rsp_type, this_rsp_u, this_args_cbk, \ params...) \ do { \ gfx_##rsp_type##_rsp *_this_rsp = &CPD4_RSP_FIELD(this_rsp_u, fop); \ int _op_ret = 0; \ int _op_errno = 0; \ \ _op_ret = _this_rsp->op_ret; \ _op_errno = gf_error_to_errno(_this_rsp->op_errno); \ args_##fop##_cbk_store(this_args_cbk, _op_ret, _op_errno, params); \ } while (0) #define CLIENT4_PRE_FOP(fop, xl, compound_req, op_errno, label, params...) \ do { \ gfx_##fop##_req *_req = (gfx_##fop##_req *)compound_req; \ int _ret = 0; \ \ _ret = client_pre_##fop##_v2(xl, _req, params); \ if (_ret < 0) { \ op_errno = -ret; \ goto label; \ } \ } while (0) #define CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, fop) \ do { \ gfx_##fop##_req *_req = &CPD4_REQ_FIELD(curr_req, fop); \ \ GF_FREE(_req->xdata.pairs.pairs_val); \ } while (0) struct clnt_options { char *remote_subvolume; int ping_timeout; }; typedef struct clnt_conf { struct rpc_clnt *rpc; struct clnt_options opt; struct rpc_clnt_config rpc_conf; struct list_head saved_fds; pthread_spinlock_t fd_lock; /* protects saved_fds list * and all fdctx */ pthread_mutex_t lock; int connected; rpc_clnt_prog_t *fops; rpc_clnt_prog_t *mgmt; rpc_clnt_prog_t *handshake; rpc_clnt_prog_t *dump; int client_id; uint64_t reopen_fd_count; /* Count of fds reopened after a connection is established */ gf_lock_t rec_lock; int skip_notify; int last_sent_event; /* Flag used to make sure we are not repeating the same event which was sent earlier */ char portmap_err_logged; /* flag used to prevent excessive logging */ char disconnect_err_logged; /* flag used to prevent excessive disconnect logging */ char parent_down; gf_boolean_t quick_reconnect; /* When reconnecting after portmap query, do not let the reconnection happen after the usual 3-second wait */ gf_boolean_t filter_o_direct; /* if set, filter O_DIRECT from the flags list of open() */ /* set volume is the op which results in creating/re-using * the conn-id and is called once per connection, this remembers * how manytimes set_volume is called */ uint64_t setvol_count; gf_boolean_t send_gids; /* let the server resolve gids */ int event_threads; /* # of event threads * configured */ gf_boolean_t destroy; /* if enabled implies fini was called * on @this xlator instance */ gf_boolean_t child_up; /* Set to true, when child is up, and * false, when child is down */ gf_boolean_t can_log_disconnect; /* socket level connection is * up, disconnects can be * logged */ } clnt_conf_t; typedef struct _client_fd_ctx { struct list_head sfd_pos; /* Stores the reference to this fd's position in the saved_fds list. */ int64_t remote_fd; char is_dir; char released; int32_t flags; fd_lk_ctx_t *lk_ctx; uuid_t gfid; void (*reopen_done)(struct _client_fd_ctx *, int64_t rfd, xlator_t *); struct list_head lock_list; /* List of all granted locks on this fd */ int32_t reopen_attempts; } clnt_fd_ctx_t; typedef struct _client_posix_lock { fd_t *fd; /* The fd on which the lk operation was made */ struct gf_flock user_flock; /* the flock supplied by the user */ off_t fl_start; off_t fl_end; short fl_type; int32_t cmd; /* the cmd for the lock call */ gf_lkowner_t owner; /* lock owner from fuse */ struct list_head list; /* reference used to add to the fdctx list of locks */ } client_posix_lock_t; typedef struct client_local { loc_t loc; loc_t loc2; fd_t *fd; fd_t *fd_out; /* used in copy_file_range */ clnt_fd_ctx_t *fdctx; uint32_t flags; struct iobref *iobref; client_posix_lock_t *client_lock; gf_lkowner_t owner; int32_t cmd; struct list_head lock_list; pthread_mutex_t mutex; char *name; gf_boolean_t attempt_reopen; /* * The below boolean variable is used * only for copy_file_range fop */ gf_boolean_t attempt_reopen_out; /* required for compound fops */ compound_args_t *compound_args; unsigned int length; /* length of a compound fop */ unsigned int read_length; /* defines the last processed length for a compound read */ } clnt_local_t; typedef struct client_args { loc_t *loc; /* * This is the source fd for copy_file_range and * the default fd for any other fd based fop which * requires only one fd (i.e. opetates on one fd) */ fd_t *fd; fd_t *fd_out; /* this is the destination fd for copy_file_range */ const char *linkname; struct iobref *iobref; struct iovec *vector; dict_t *xattr; struct iatt *stbuf; loc_t *oldloc; loc_t *newloc; const char *name; struct gf_flock *flock; const char *volume; const char *basename; off_t offset; /* * According to the man page of copy_file_range, * the offsets for source and destination file * are of type loff_t. But the type loff_t is * linux specific and is actual a typedef of * off64_t. */ off64_t off_in; /* used in copy_file_range for source fd */ off64_t off_out; /* used in copy_file_range for dst fd */ int32_t mask; int32_t cmd; size_t size; mode_t mode; dev_t rdev; int32_t flags; int32_t count; int32_t datasync; entrylk_cmd cmd_entrylk; entrylk_type type; gf_xattrop_flags_t optype; int32_t valid; int32_t len; gf_seek_what_t what; struct gf_lease *lease; mode_t umask; dict_t *xdata; lock_migration_info_t *locklist; } clnt_args_t; typedef struct client_payload { struct iobref *iobref; struct iovec *payload; struct iovec *rsphdr; struct iovec *rsp_payload; struct iobref *rsp_iobref; int payload_cnt; int rsphdr_cnt; int rsp_payload_cnt; } client_payload_t; typedef ssize_t (*gfs_serialize_t)(struct iovec outmsg, void *args); clnt_fd_ctx_t * this_fd_get_ctx(fd_t *file, xlator_t *this); clnt_fd_ctx_t * this_fd_del_ctx(fd_t *file, xlator_t *this); void this_fd_set_ctx(fd_t *file, xlator_t *this, loc_t *loc, clnt_fd_ctx_t *ctx); int client_local_wipe(clnt_local_t *local); int client_submit_request(xlator_t *this, void *req, call_frame_t *frame, rpc_clnt_prog_t *prog, int procnum, fop_cbk_fn_t cbk, client_payload_t *cp, xdrproc_t xdrproc); int client_submit_compound_request(xlator_t *this, void *req, call_frame_t *frame, rpc_clnt_prog_t *prog, int procnum, fop_cbk_fn_t cbkfn, struct iovec *req_vector, int req_count, struct iobref *iobref, struct iovec *rsphdr, int rsphdr_count, struct iovec *rsp_payload, int rsp_payload_count, struct iobref *rsp_iobref, xdrproc_t xdrproc); int unserialize_rsp_dirent(xlator_t *this, struct gfs3_readdir_rsp *rsp, gf_dirent_t *entries); int unserialize_rsp_direntp(xlator_t *this, fd_t *fd, struct gfs3_readdirp_rsp *rsp, gf_dirent_t *entries); int clnt_readdir_rsp_cleanup(gfs3_readdir_rsp *rsp); int clnt_readdirp_rsp_cleanup(gfs3_readdirp_rsp *rsp); int client_attempt_lock_recovery(xlator_t *this, clnt_fd_ctx_t *fdctx); int32_t delete_granted_locks_owner(fd_t *fd, gf_lkowner_t *owner); int32_t delete_granted_locks_fd(clnt_fd_ctx_t *fdctx); int32_t client_cmd_to_gf_cmd(int32_t cmd, int32_t *gf_cmd); void client_save_number_fds(clnt_conf_t *conf, int count); int dump_client_locks(inode_t *inode); int client_notify_parents_child_up(xlator_t *this); int32_t is_client_dump_locks_cmd(char *name); int32_t client_dump_locks(char *name, inode_t *inode, dict_t *dict); int client_fdctx_destroy(xlator_t *this, clnt_fd_ctx_t *fdctx); int32_t client_type_to_gf_type(short l_type); int client_mark_fd_bad(xlator_t *this); int client_fd_lk_list_empty(fd_lk_ctx_t *lk_ctx, gf_boolean_t use_try_lock); void client_default_reopen_done(clnt_fd_ctx_t *fdctx, int64_t rfd, xlator_t *this); void client_attempt_reopen(fd_t *fd, xlator_t *this); int client_get_remote_fd(xlator_t *this, fd_t *fd, int flags, int64_t *remote_fd); int client_fd_fop_prepare_local(call_frame_t *frame, fd_t *fd, int64_t remote_fd); gf_boolean_t __is_fd_reopen_in_progress(clnt_fd_ctx_t *fdctx); int client_notify_dispatch(xlator_t *this, int32_t event, void *data, ...); int client_notify_dispatch_uniq(xlator_t *this, int32_t event, void *data, ...); gf_boolean_t client_is_reopen_needed(fd_t *fd, xlator_t *this, int64_t remote_fd); int client_add_fd_to_saved_fds(xlator_t *this, fd_t *fd, loc_t *loc, int32_t flags, int64_t remote_fd, int is_dir); int client_handle_fop_requirements( xlator_t *this, call_frame_t *frame, gfs3_compound_req *req, clnt_local_t *local, struct iobref **req_iobref, struct iobref **rsp_iobref, struct iovec *req_vector, struct iovec *rsp_vector, int *req_count, int *rsp_count, default_args_t *args, int fop_enum, int index); int client_process_response(call_frame_t *frame, xlator_t *this, struct rpc_req *req, gfs3_compound_rsp *rsp, compound_args_cbk_t *args_cbk, int index); void compound_request_cleanup(gfs3_compound_req *req); int clnt_unserialize_rsp_locklist(xlator_t *this, struct gfs3_getactivelk_rsp *rsp, lock_migration_info_t *lmi); void clnt_getactivelk_rsp_cleanup(gfs3_getactivelk_rsp *rsp); void clnt_setactivelk_req_cleanup(gfs3_setactivelk_req *req); int serialize_req_locklist(lock_migration_info_t *locklist, gfs3_setactivelk_req *req); void client_compound_rsp_cleanup(gfs3_compound_rsp *rsp, int len); void clnt_getactivelk_rsp_cleanup_v2(gfx_getactivelk_rsp *rsp); void clnt_setactivelk_req_cleanup_v2(gfx_setactivelk_req *req); int serialize_req_locklist_v2(lock_migration_info_t *locklist, gfx_setactivelk_req *req); int clnt_unserialize_rsp_locklist_v2(xlator_t *this, struct gfx_getactivelk_rsp *rsp, lock_migration_info_t *lmi); int unserialize_rsp_dirent_v2(xlator_t *this, struct gfx_readdir_rsp *rsp, gf_dirent_t *entries); int unserialize_rsp_direntp_v2(xlator_t *this, fd_t *fd, struct gfx_readdirp_rsp *rsp, gf_dirent_t *entries); int clnt_readdir_rsp_cleanup_v2(gfx_readdir_rsp *rsp); int clnt_readdirp_rsp_cleanup_v2(gfx_readdirp_rsp *rsp); int client_handle_fop_requirements_v2( xlator_t *this, call_frame_t *frame, gfx_compound_req *req, clnt_local_t *local, struct iobref **req_iobref, struct iobref **rsp_iobref, struct iovec *req_vector, struct iovec *rsp_vector, int *req_count, int *rsp_count, default_args_t *args, int fop_enum, int index); int client_process_response_v2(call_frame_t *frame, xlator_t *this, struct rpc_req *req, gfx_compound_rsp *rsp, compound_args_cbk_t *args_cbk, int index); void compound_request_cleanup_v2(gfx_compound_req *req); void client_compound_rsp_cleanup_v2(gfx_compound_rsp *rsp, int len); #endif /* !_CLIENT_H */