diff options
-rw-r--r-- | api/src/gfapi.aliases | 3 | ||||
-rw-r--r-- | api/src/gfapi.map | 6 | ||||
-rw-r--r-- | api/src/glfs-fops.c | 186 | ||||
-rw-r--r-- | api/src/glfs-handleops.c | 2 | ||||
-rw-r--r-- | api/src/glfs-handles.h | 43 | ||||
-rw-r--r-- | api/src/glfs-internal.h | 7 | ||||
-rw-r--r-- | api/src/glfs.c | 100 | ||||
-rw-r--r-- | api/src/glfs.h | 150 | ||||
-rw-r--r-- | tests/basic/gfapi/upcall-register-api.c | 281 | ||||
-rwxr-xr-x | tests/basic/gfapi/upcall-register-api.t | 30 |
10 files changed, 713 insertions, 95 deletions
diff --git a/api/src/gfapi.aliases b/api/src/gfapi.aliases index 85e8448982d..16b18a1575d 100644 --- a/api/src/gfapi.aliases +++ b/api/src/gfapi.aliases @@ -164,3 +164,6 @@ _pub_glfs_xreaddirplus_r_get_object _glfs_xreaddirplus_r_get_object$GFAPI_3.11.0 _pub_glfs_object_copy _glfs_object_copy$GFAPI_3.11.0 _priv_glfs_ipc _glfs_ipc$GFAPI_3.12.0 + +_pub_glfs_upcall_register _glfs_upcall_register$GFAPI_3.13.0 +_pub_glfs_upcall_unregister _glfs_upcall_unregister$GFAPI_3.13.0 diff --git a/api/src/gfapi.map b/api/src/gfapi.map index 88673007d25..bb9c0377353 100644 --- a/api/src/gfapi.map +++ b/api/src/gfapi.map @@ -214,3 +214,9 @@ GFAPI_PRIVATE_3.12.0 { global: glfs_ipc; } GFAPI_3.11.0; + +GFAPI_3.13.0 { + global: + glfs_upcall_register; + glfs_upcall_unregister; +} GFAPI_PRIVATE_3.12.0; diff --git a/api/src/glfs-fops.c b/api/src/glfs-fops.c index 8d1ee9de1d7..72fd6975217 100644 --- a/api/src/glfs-fops.c +++ b/api/src/glfs-fops.c @@ -4398,29 +4398,151 @@ invalid_fs: GFAPI_SYMVER_PUBLIC_DEFAULT(glfs_dup, 3.4.0); +static void +glfs_enqueue_upcall_data (struct glfs *fs, struct gf_upcall *upcall_data) +{ + int ret = -1; + upcall_entry *u_list = NULL; + + if (!fs || !upcall_data) + goto out; + + u_list = GF_CALLOC (1, sizeof(*u_list), + glfs_mt_upcall_entry_t); + + if (!u_list) { + gf_msg (THIS->name, GF_LOG_ERROR, ENOMEM, API_MSG_ALLOC_FAILED, + "Upcall entry allocation failed."); + goto out; + } + + INIT_LIST_HEAD (&u_list->upcall_list); + + gf_uuid_copy (u_list->upcall_data.gfid, upcall_data->gfid); + u_list->upcall_data.event_type = upcall_data->event_type; + + switch (upcall_data->event_type) { + case GF_UPCALL_CACHE_INVALIDATION: + ret = glfs_get_upcall_cache_invalidation (&u_list->upcall_data, + upcall_data); + break; + default: + break; + } + + if (ret) { + gf_msg (THIS->name, GF_LOG_ERROR, errno, + API_MSG_INVALID_ENTRY, + "Upcall entry validation failed."); + goto out; + } + + pthread_mutex_lock (&fs->upcall_list_mutex); + { + list_add_tail (&u_list->upcall_list, + &fs->upcall_list); + } + pthread_mutex_unlock (&fs->upcall_list_mutex); + + ret = 0; + +out: + if (ret && u_list) { + GF_FREE (u_list->upcall_data.data); + GF_FREE(u_list); + } +} + +static void +glfs_cbk_upcall_data (struct glfs *fs, struct gf_upcall *upcall_data) +{ + int ret = -1; + struct glfs_upcall *up_arg = NULL; + + if (!fs || !upcall_data) + goto out; + + if (!(fs->upcall_events & upcall_data->event_type)) { + /* ignore events which application hasn't registered*/ + goto out; + } + + up_arg = GLFS_CALLOC (1, sizeof (struct gf_upcall), + glfs_release_upcall, + glfs_mt_upcall_entry_t); + if (!up_arg) { + gf_msg (THIS->name, GF_LOG_ERROR, ENOMEM, API_MSG_ALLOC_FAILED, + "Upcall entry allocation failed."); + goto out; + } + + switch (upcall_data->event_type) { + case GF_UPCALL_CACHE_INVALIDATION: + ret = glfs_h_poll_cache_invalidation (fs, up_arg, upcall_data); + break; + default: + errno = EINVAL; + } + + if (!ret && (up_arg->reason != GLFS_UPCALL_EVENT_NULL)) { + /* It could so happen that the file which got + * upcall notification may have got deleted by + * the same client. In such cases up_arg->reason + * is set to GLFS_UPCALL_EVENT_NULL. No need to + * send upcall then */ + (fs->up_cbk) (up_arg, fs->up_data); + } else if (up_arg->reason == GLFS_UPCALL_EVENT_NULL) { + gf_msg (THIS->name, GF_LOG_DEBUG, errno, + API_MSG_INVALID_ENTRY, + "Upcall_EVENT_NULL received. Skipping it."); + goto out; + } else { + gf_msg (THIS->name, GF_LOG_ERROR, errno, + API_MSG_INVALID_ENTRY, + "Upcall entry validation failed."); + goto out; + } + + /* application takes care of calling glfs_free on up_arg post + * their processing */ + ret = 0; + +out: + if (ret && up_arg) { + GLFS_FREE (up_arg); + } + + return; +} + /* * This routine is called in case of any notification received * from the server. All the upcall events are queued up in a list * to be read by the applications. * - * XXX: Applications may register a cbk function for each 'fs' - * which then needs to be called by this routine incase of any - * event received. The cbk fn is responsible for notifying the + * In case if the application registers a cbk function, that shall + * be called by this routine incase of any event received. + * The cbk fn is responsible for notifying the * applications the way it desires for each event queued (for eg., * can raise a signal or broadcast a cond variable etc.) + * + * Otherwise all the upcall events are queued up in a list + * to be read/polled by the applications. */ void priv_glfs_process_upcall_event (struct glfs *fs, void *data) { - int ret = -1; - upcall_entry *u_list = NULL; glusterfs_ctx_t *ctx = NULL; struct gf_upcall *upcall_data = NULL; + DECLARE_OLD_THIS; + gf_msg_debug (THIS->name, 0, "Upcall gfapi callback is called"); - if (!fs || !data) + __GLFS_ENTRY_VALIDATE_FS (fs, err); + + if (!data) goto out; /* Unlike in I/O path, "glfs_fini" would not have freed @@ -4441,48 +4563,16 @@ priv_glfs_process_upcall_event (struct glfs *fs, void *data) } pthread_mutex_unlock (&fs->mutex); - upcall_data = (struct gf_upcall *)data; - gf_msg_trace (THIS->name, 0, "Upcall gfapi gfid = %s" - "ret = %d", (char *)(upcall_data->gfid), ret); + gf_msg_trace (THIS->name, 0, "Upcall gfapi gfid = %s" , + (char *)(upcall_data->gfid)); - u_list = GF_CALLOC (1, sizeof(*u_list), - glfs_mt_upcall_entry_t); - - if (!u_list) { - gf_msg (THIS->name, GF_LOG_ERROR, ENOMEM, API_MSG_ALLOC_FAILED, - "Upcall entry allocation failed."); - goto out; - } - - INIT_LIST_HEAD (&u_list->upcall_list); - - gf_uuid_copy (u_list->upcall_data.gfid, upcall_data->gfid); - u_list->upcall_data.event_type = upcall_data->event_type; - - switch (upcall_data->event_type) { - case GF_UPCALL_CACHE_INVALIDATION: - ret = glfs_get_upcall_cache_invalidation (&u_list->upcall_data, - upcall_data); - break; - default: - goto out; - } - - if (ret) { - gf_msg (THIS->name, GF_LOG_ERROR, errno, - API_MSG_INVALID_ENTRY, - "Upcall entry validation failed."); - goto out; - } - - pthread_mutex_lock (&fs->upcall_list_mutex); - { - list_add_tail (&u_list->upcall_list, - &fs->upcall_list); + if (fs->up_cbk) { /* upcall cbk registered */ + (void) glfs_cbk_upcall_data (fs, upcall_data); + } else { + (void) glfs_enqueue_upcall_data (fs, upcall_data); } - pthread_mutex_unlock (&fs->upcall_list_mutex); pthread_mutex_lock (&fs->mutex); { @@ -4490,15 +4580,11 @@ priv_glfs_process_upcall_event (struct glfs *fs, void *data) } pthread_mutex_unlock (&fs->mutex); - ret = 0; out: - if (ret && u_list) { - GF_FREE (u_list->upcall_data.data); - GF_FREE(u_list); - } + __GLFS_EXIT_FS; +err: return; } - GFAPI_SYMVER_PRIVATE_DEFAULT(glfs_process_upcall_event, 3.7.0); ssize_t diff --git a/api/src/glfs-handleops.c b/api/src/glfs-handleops.c index 65b2b6a467c..2693c2de306 100644 --- a/api/src/glfs-handleops.c +++ b/api/src/glfs-handleops.c @@ -1987,7 +1987,7 @@ out: return ret; } -static void glfs_release_upcall (void *ptr) +void glfs_release_upcall (void *ptr) { struct glfs_upcall *to_free = ptr; diff --git a/api/src/glfs-handles.h b/api/src/glfs-handles.h index 9583fab069a..211595933fc 100644 --- a/api/src/glfs-handles.h +++ b/api/src/glfs-handles.h @@ -102,49 +102,6 @@ __BEGIN_DECLS struct glfs_object; typedef struct glfs_object glfs_object_t; -/* - * Applications (currently NFS-Ganesha) can make use of this - * structure to read upcall notifications sent by server. - * - * On success, applications need to check for 'reason' to decide - * if any upcall event is received. - * - * Currently supported upcall_events - - * GFAPI_INODE_INVALIDATE - - * 'event_arg' - glfs_upcall_inode - * - * After processing the event, applications need to free 'event_arg' with - * glfs_free(). - * - * Also similar to I/Os, the application should ideally stop polling - * before calling glfs_fini(..). Hence making an assumption that - * 'fs' & ctx structures cannot be freed while in this routine. - */ -struct glfs_upcall; - -struct glfs* -glfs_upcall_get_fs (struct glfs_upcall *arg) __THROW - GFAPI_PUBLIC(glfs_upcall_get_fs, 3.7.16); - -enum glfs_upcall_reason { - GLFS_UPCALL_EVENT_NULL = 0, - GLFS_UPCALL_INODE_INVALIDATE, /* invalidate cache entry */ -}; - -enum glfs_upcall_reason -glfs_upcall_get_reason (struct glfs_upcall *arg) __THROW - GFAPI_PUBLIC(glfs_upcall_get_reason, 3.7.16); - - -/* - * After processing upcall event, glfs_free() should be called on the - * glfs_upcall. - */ -void* -glfs_upcall_get_event (struct glfs_upcall *arg) __THROW - GFAPI_PUBLIC(glfs_upcall_get_event, 3.7.16); - - /* Functions for getting details about the glfs_upcall_inode * * None of the pointers returned by the below functions should be free()'d, diff --git a/api/src/glfs-internal.h b/api/src/glfs-internal.h index 757bc18eb1d..76b0e34f1bd 100644 --- a/api/src/glfs-internal.h +++ b/api/src/glfs-internal.h @@ -194,6 +194,12 @@ struct glfs { uint32_t pin_refcnt; uint32_t pthread_flags; /* GLFS_INIT_* # defines set this flag */ + + uint32_t upcall_events; /* Mask of upcall events application + * is interested in */ + glfs_upcall_cbk up_cbk; /* upcall cbk function to be registered */ + void *up_data; /* Opaque data provided by application + * during upcall registration */ }; /* This enum is used to maintain the state of glfd. In case of async fops @@ -604,4 +610,5 @@ gf_dirent_to_dirent (gf_dirent_t *gf_dirent, struct dirent *dirent); int glfs_ipc (glfs_fd_t *fd, int cmd, void *xd_in, void **xd_out) __THROW GFAPI_PRIVATE(glfs_ipc, 3.12.0); +void glfs_release_upcall (void *ptr); #endif /* !_GLFS_INTERNAL_H */ diff --git a/api/src/glfs.c b/api/src/glfs.c index 72a2c3724a1..b168f682a7d 100644 --- a/api/src/glfs.c +++ b/api/src/glfs.c @@ -703,6 +703,9 @@ glfs_new_fs (const char *volname) goto err; fs->pin_refcnt = 0; + fs->upcall_events = 0; + fs->up_cbk = NULL; + fs->up_data = NULL; return fs; @@ -1551,3 +1554,100 @@ out: } GFAPI_SYMVER_PUBLIC_DEFAULT(glfs_sysrq, 3.10.0); + +int +glfs_upcall_register (struct glfs *fs, uint32_t event_list, + glfs_upcall_cbk cbk, void *data) +{ + int ret = 0; + + /* list of supported upcall events */ + uint32_t up_events = GLFS_EVENT_INODE_INVALIDATE; + + DECLARE_OLD_THIS; + __GLFS_ENTRY_VALIDATE_FS (fs, invalid_fs); + + GF_VALIDATE_OR_GOTO (THIS->name, cbk, out); + + /* Event list should be either GLFS_EVENT_ANY + * or list of supported individual events (up_events) + */ + if ((event_list != GLFS_EVENT_ANY) && + (event_list & ~up_events)) { + errno = EINVAL; + ret = -1; + gf_msg (THIS->name, GF_LOG_ERROR, errno, LG_MSG_INVALID_ARG, + "invalid event_list (0x%08x)", event_list); + goto out; + } + + /* incase other thread does unregister */ + pthread_mutex_lock (&fs->mutex); + { + if (event_list & GLFS_EVENT_INODE_INVALIDATE) { + /* @todo: Check if features.cache-invalidation is + * enabled. + */ + fs->upcall_events |= GF_UPCALL_CACHE_INVALIDATION; + ret |= GF_UPCALL_CACHE_INVALIDATION; + } + + /* Override cbk function if existing */ + fs->up_cbk = cbk; + fs->up_data = data; + fs->cache_upcalls = _gf_true; + } + pthread_mutex_unlock (&fs->mutex); + +out: + __GLFS_EXIT_FS; + +invalid_fs: + return ret; +} +GFAPI_SYMVER_PUBLIC_DEFAULT(glfs_upcall_register, 3.13.0); + +int glfs_upcall_unregister (struct glfs *fs, uint32_t event_list) +{ + int ret = 0; + /* list of supported upcall events */ + uint32_t up_events = GLFS_EVENT_INODE_INVALIDATE; + + DECLARE_OLD_THIS; + __GLFS_ENTRY_VALIDATE_FS (fs, invalid_fs); + + /* Event list should be either GLFS_EVENT_ANY + * or list of supported individual events (up_events) + */ + if ((event_list != GLFS_EVENT_ANY) && + (event_list & ~up_events)) { + errno = EINVAL; + ret = -1; + gf_msg (THIS->name, GF_LOG_ERROR, errno, LG_MSG_INVALID_ARG, + "invalid event_list (0x%08x)", event_list); + goto out; + } + + pthread_mutex_lock (&fs->mutex); + { + if (event_list & GLFS_EVENT_INODE_INVALIDATE) { + fs->upcall_events &= ~GF_UPCALL_CACHE_INVALIDATION; + ret |= GF_UPCALL_CACHE_INVALIDATION; + } + + /* If there are no upcall events registered, reset cbk */ + if (fs->upcall_events == 0) { + fs->up_cbk = NULL; + fs->up_data = NULL; + fs->cache_upcalls = _gf_false; + } + } + pthread_mutex_unlock (&fs->mutex); + +out: + __GLFS_EXIT_FS; + +invalid_fs: + return ret; +} +GFAPI_SYMVER_PUBLIC_DEFAULT(glfs_upcall_unregister, 3.13.0); diff --git a/api/src/glfs.h b/api/src/glfs.h index ec3258d083a..198e4224a6b 100644 --- a/api/src/glfs.h +++ b/api/src/glfs.h @@ -883,6 +883,154 @@ glfs_xreaddirplus_r (struct glfs_fd *glfd, uint32_t flags, */ int glfs_fd_set_lkowner (glfs_fd_t *glfd, void *data, int len); GFAPI_PUBLIC(glfs_fd_set_lkowner, 3.10.7); -__END_DECLS +/* + * Applications (currently NFS-Ganesha) can make use of this + * structure to read upcall notifications sent by server either + * by polling or registering a callback function. + * + * On success, applications need to check for 'reason' to decide + * if any upcall event is received. + * + * Currently supported upcall_events - + * GLFS_UPCALL_INODE_INVALIDATE - + * 'event_arg' - glfs_upcall_inode + * + * After processing the event, applications need to free 'event_arg' with + * glfs_free(). + * + * Also similar to I/Os, the application should ideally stop polling + * or unregister upcall_cbk function before calling glfs_fini(..). + * Hence making an assumption that 'fs' & ctx structures cannot be + * freed while in this routine. + */ +struct glfs_upcall; + +struct glfs* +glfs_upcall_get_fs (struct glfs_upcall *arg) __THROW + GFAPI_PUBLIC(glfs_upcall_get_fs, 3.7.16); + +enum glfs_upcall_reason { + GLFS_UPCALL_EVENT_NULL = 0, + GLFS_UPCALL_INODE_INVALIDATE, /* invalidate cache entry */ +}; + +enum glfs_upcall_reason +glfs_upcall_get_reason (struct glfs_upcall *arg) __THROW + GFAPI_PUBLIC(glfs_upcall_get_reason, 3.7.16); + + +/* + * Applications first need to make use of above API i.e, + * "glfs_upcall_get_reason" to determine which upcall event it has + * received. Post that below API - "glfs_upcall_get_event" should + * be used to get corresponding upcall event object. + * + * Below are the upcall_reason and corresponding upcall_event objects: + * ========================================================== + * glfs_upcall_reason - event_object + * ========================================================== + * GLFS_UPCALL_EVENT_NULL - NULL + * GLFS_UPCALL_INODE_INVALIDATE - struct glfs_upcall_inode + * + * After processing upcall event, glfs_free() should be called on the + * glfs_upcall. + */ +void* +glfs_upcall_get_event (struct glfs_upcall *arg) __THROW + GFAPI_PUBLIC(glfs_upcall_get_event, 3.7.16); + +/* + * SYNOPSIS + * + * glfs_upcall_cbk: Upcall callback definition + * + * This is function type definition of the callback function pointer + * which has to be provided by the caller while registering for any + * upcall events. + * + * This function is called whenever any upcall which the application + * has registered for is received from the server. + * + * @up_arg: Upcall structure whose contents need to be interpreted by + * making use of glfs_upcall_* helper routines. + * + * @data: The same context pointer provided by the caller at the time of + * registering of upcall events. This may be used by the caller for any + * of its internal use while processing upcalls. + */ +typedef void (*glfs_upcall_cbk) (struct glfs_upcall *up_arg, void *data); + +/* + * List of upcall events supported by gluster/gfapi + */ +#define GLFS_EVENT_INODE_INVALIDATE 0x00000001 /* invalidate cache entry */ +#define GLFS_EVENT_ANY 0xffffffff /* for all the above events */ + +/* + * SYNOPSIS + * + * glfs_upcall_register: Register for upcall events + * + * DESCRIPTION + * + * This function is used to register for various upcall events application + * is interested in and the callback function to be invoked when such + * events are triggered. + * + * Multiple calls of this routine shall override cbk function. That means + * only one cbk function can be used for all the upcall events registered + * and that shall be the one last updated. + * + * PARAMETERS: + * + * INPUT: + * @fs: The 'virtual mount' object + * + * @event_list: List of upcall events to be registered. + * Current available values are: + * - GFAPI_UPCALL_INODE_INVALIDATE + * + * @cbk: The cbk routine to be invoked incase of any upcall received + * @data: Any opaque pointer provided by caller which shall be using while + * making cbk calls. This pointer may be used by caller for any of its + * internal use while processing upcalls. Can be NULL. + * + * RETURN VALUE: + * >0: SUCCESS (value contains the events successfully registered) + * -1: FAILURE + */ +int +glfs_upcall_register (struct glfs *fs, uint32_t event_list, + glfs_upcall_cbk cbk, void *data); + GFAPI_PUBLIC(glfs_upcall_register, 3.13.0); + +/* + * SYNOPSIS + * + * glfs_upcall_unregister: Unregister for upcall events + * + * DESCRIPTION + * + * This function is used to unregister the upcall events application + * is not interested in. In case if the caller unregisters all the events + * it has registered for, it shall no more receive any upcall event. + * + * PARAMETERS: + * + * INPUT: + * @fs: The 'virtual mount' object + * + * @event_list: List of upcall events to be unregistered. + * Current available values are: + * - GFAPI_UPCALL_INODE_INVALIDATE + * RETURN VALUE: + * >0: SUCCESS (value contains the events successfully unregistered) + * -1: FAILURE + */ +int +glfs_upcall_unregister (struct glfs *fs, uint32_t event_list); + GFAPI_PUBLIC(glfs_upcall_unregister, 3.13.0); + +__END_DECLS #endif /* !_GLFS_H */ diff --git a/tests/basic/gfapi/upcall-register-api.c b/tests/basic/gfapi/upcall-register-api.c new file mode 100644 index 00000000000..56227a93d0a --- /dev/null +++ b/tests/basic/gfapi/upcall-register-api.c @@ -0,0 +1,281 @@ +#include <fcntl.h> +#include <unistd.h> +#include <time.h> +#include <limits.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> + +#define LOG_ERR(func, ret) do { \ + if (ret != 0) { \ + fprintf (stderr, "%s : returned error %d (%s)\n", \ + func, ret, strerror (errno)); \ + goto out; \ + } else { \ + fprintf (stderr, "%s : returned %d\n", func, ret); \ + } \ + } while (0) + +int upcall_recv = 0; + +void up_async_invalidate (struct glfs_upcall *up_arg, void *data) +{ + struct glfs_upcall_inode *in_arg = NULL; + enum glfs_upcall_reason reason = 0; + struct glfs_object *object = NULL; + uint64_t flags = 0; + uint64_t expire = 0; + + if (!up_arg) + return; + + reason = glfs_upcall_get_reason (up_arg); + + /* Expect 'GLFS_INODE_INVALIDATE' upcall event. */ + + if (reason == GLFS_UPCALL_INODE_INVALIDATE) { + in_arg = glfs_upcall_get_event (up_arg); + + object = glfs_upcall_inode_get_object (in_arg); + flags = glfs_upcall_inode_get_flags (in_arg); + expire = glfs_upcall_inode_get_expire (in_arg); + + fprintf (stderr, " upcall event type - %d," + " object(%p), flags(%d), " + " expire_time_attr(%d)\n" , + reason, object, flags, expire); + upcall_recv++; + } + + glfs_free (up_arg); + return; +} + +int perform_io (glfs_t *fs, glfs_t *fs2, int cnt) +{ + glfs_t *fs_tmp = NULL; + glfs_t *fs_tmp2 = NULL; + glfs_fd_t *fd_tmp = NULL; + glfs_fd_t *fd_tmp2 = NULL; + char readbuf[32]; + char *writebuf = NULL; + glfs_fd_t *fd = NULL; + glfs_fd_t *fd2 = NULL; + char *filename = "file_tmp"; + int ret = -1; + + if (!fs || !fs2) + return -1; + + /* Create file from fs and open it from fs2 */ + fd = glfs_creat(fs, filename, O_RDWR|O_SYNC, 0644); + if (fd <= 0) { + ret = -1; + LOG_ERR ("glfs_creat", ret); + } + + fd2 = glfs_open(fs2, filename, O_SYNC|O_RDWR|O_CREAT); + if (fd2 <= 0) { + ret = -1; + LOG_ERR ("glfs_open-fs2", ret); + } + + do { + if (cnt%2) { + fd_tmp = fd; + fs_tmp = fs; + fd_tmp2 = fd2; + fs_tmp2 = fs2; + } else { + fd_tmp = fd2; + fs_tmp = fs2; + fd_tmp2 = fd; + fs_tmp2 = fs; + } + + /* WRITE on fd_tmp */ + writebuf = malloc(10); + if (writebuf) { + memcpy (writebuf, "abcd", 4); + ret = glfs_write (fd_tmp, writebuf, 4, 0); + if (ret <= 0) { + ret = -1; + LOG_ERR ("glfs_write", ret); + } + free(writebuf); + } else { + fprintf (stderr, + "Could not allocate writebuf\n"); + return -1; + } + + /* READ on fd_tmp2 */ + ret = glfs_lseek (fd_tmp2, 0, SEEK_SET); + LOG_ERR ("glfs_lseek", ret); + + memset (readbuf, 0, sizeof(readbuf)); + ret = glfs_pread (fd_tmp2, readbuf, 4, 0, 0); + + if (ret <= 0) { + ret = -1; + LOG_ERR ("glfs_pread", ret); + } + + sleep(2); + } while (--cnt > 0); + + sleep(2); + + ret = 0; +err: + glfs_close(fd); + + glfs_close(fd2); + +out: + return ret; +} + +int +main (int argc, char *argv[]) +{ + glfs_t *fs = NULL; + glfs_t *fs2 = NULL; + int ret = 0, i; + char *vol_id = NULL; + unsigned int cnt = 5; + struct glfs_upcall *cbk = NULL; + char *logfile = NULL; + char *volname = NULL; + char *hostname = NULL; + int up_events = GLFS_EVENT_ANY; + + if (argc != 4) { + fprintf (stderr, "Invalid argument\n"); + exit(1); + } + + hostname = argv[1]; + volname = argv[2]; + logfile = argv[3]; + + /* Initialize fs */ + fs = glfs_new (volname); + if (!fs) { + fprintf (stderr, "glfs_new: returned NULL\n"); + return -1; + } + + ret = glfs_set_volfile_server (fs, "tcp", hostname, 24007); + LOG_ERR("glfs_set_volfile_server", ret); + + ret = glfs_set_logging (fs, logfile, 7); + LOG_ERR("glfs_set_logging", ret); + + ret = glfs_init (fs); + LOG_ERR("glfs_init", ret); + + /* Intialize fs2 */ + fs2 = glfs_new (volname); + if (!fs2) { + fprintf (stderr, "glfs_new fs2: returned NULL\n"); + return 1; + } + + ret = glfs_set_volfile_server (fs2, "tcp", hostname, 24007); + LOG_ERR("glfs_set_volfile_server-fs2", ret); + + ret = glfs_set_logging (fs2, logfile, 7); + LOG_ERR("glfs_set_logging-fs2", ret); + + ret = glfs_init (fs2); + LOG_ERR("glfs_init-fs2", ret); + + /* Register Upcalls */ + ret = glfs_upcall_register (fs, up_events, up_async_invalidate, NULL); + + /* Check if the return mask contains the event */ + if (!(ret & GLFS_EVENT_INODE_INVALIDATE)) { + fprintf (stderr, "glfs_upcall_register return doesnt contain" + " upcall event\n"); + return -1; + } + + ret = glfs_upcall_register (fs2, up_events, up_async_invalidate, NULL); + + /* Check if the return mask contains the event */ + if ((ret < 0) || !(ret & GLFS_EVENT_INODE_INVALIDATE)) { + fprintf (stderr, "glfs_upcall_register return doesnt contain" + " upcall event\n"); + return -1; + } + + /* Perform I/O */ + ret = perform_io (fs, fs2, cnt); + LOG_ERR("perform_io", ret); + + if (upcall_recv == 0) { + fprintf (stderr, "Upcalls are not received.\n"); + ret = -1; + } else { + fprintf (stderr, "Received %d upcalls as expected\n", + upcall_recv); + ret = 0; + } + + sleep(5); /* to flush out previous upcalls if any */ + + /* Now unregister and check there are no upcall events received */ + ret = glfs_upcall_unregister (fs, up_events); + + /* Check if the return mask contains the event */ + if ((ret < 0) || !(ret & GLFS_EVENT_INODE_INVALIDATE)) { + fprintf (stderr, "glfs_upcall_register return doesnt contain" + " upcall event\n"); + return -1; + } + + ret = glfs_upcall_unregister (fs2, up_events); + + /* Check if the return mask contains the event */ + if ((ret < 0) || !(ret & GLFS_EVENT_INODE_INVALIDATE)) { + fprintf (stderr, "glfs_upcall_register return doesnt contain" + " upcall event\n"); + return -1; + } + + upcall_recv = 0; + + ret = perform_io (fs, fs2, cnt); + LOG_ERR("perform_io", ret); + + if (upcall_recv != 0) { + fprintf (stderr, "%d upcalls received even after unregister.\n", + upcall_recv); + ret = -1; + } else { + fprintf (stderr, "Post unregister, no upcalls received as" + " expected\n"); + ret = 0; + } + +out: + if (fs) { + ret = glfs_fini(fs); + fprintf (stderr, "glfs_fini(fs) returned %d\n", ret); + } + + if (fs2) { + ret = glfs_fini(fs2); + fprintf (stderr, "glfs_fini(fs2) returned %d\n", ret); + } + + if (ret) + exit(1); + exit(0); +} + + diff --git a/tests/basic/gfapi/upcall-register-api.t b/tests/basic/gfapi/upcall-register-api.t new file mode 100755 index 00000000000..a46234ed7af --- /dev/null +++ b/tests/basic/gfapi/upcall-register-api.t @@ -0,0 +1,30 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd + +TEST $CLI volume create $V0 $H0:$B0/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +logdir=`gluster --print-logdir` + +## Enable Upcall cache-invalidation feature +TEST $CLI volume set $V0 features.cache-invalidation on; + +TEST build_tester $(dirname $0)/upcall-register-api.c -lgfapi + +TEST ./$(dirname $0)/upcall-register-api $H0 $V0 $logdir/upcall-register-api.log + +cleanup_tester $(dirname $0)/upcall-register-api + +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +cleanup; |