From fba98579efc4fe3bb69309041b60d7723475b5e2 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 5 Oct 2018 09:02:41 -0400 Subject: [PATCH] LU-6202 libcfs: replace libcfs_register_ioctl with a blocking notifier_chain libcfs allows other modules to register handlers for ioctls. The implementation it uses for this is nearly identical to a blocking notifier chain, so change to use that. The biggest difference is that the return value from notifier has a defined format, where libcfs_register_ioctl uses -EINVAL to mean "continue". This requires a little bit of conversion. Linux-commit: 912a846027c203370f4837a2b2db7ba2ebe1b47c Change-Id: I84657fc1befd004eb09de37b5549af8bff034738 Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: James Simmons Reviewed-on: https://review.whamcloud.com/33284 Reviewed-by: Andreas Dilger Reviewed-by: Ben Evans Tested-by: Jenkins Tested-by: Maloo Reviewed-by: Oleg Drokin --- libcfs/include/libcfs/libcfs.h | 8 ++++++ libcfs/libcfs/module.c | 58 +++++++++--------------------------------- lnet/include/lnet/lib-lnet.h | 13 ---------- lnet/lnet/module.c | 46 +++++++++++++++++++++------------ lnet/selftest/conctl.c | 31 ++++++++++++---------- lnet/selftest/console.c | 23 +++++++++-------- lnet/selftest/console.h | 2 ++ 7 files changed, 82 insertions(+), 99 deletions(-) diff --git a/libcfs/include/libcfs/libcfs.h b/libcfs/include/libcfs/libcfs.h index 9b4395e..7d687dc 100644 --- a/libcfs/include/libcfs/libcfs.h +++ b/libcfs/include/libcfs/libcfs.h @@ -91,6 +91,14 @@ void lc_watchdog_delete(struct lc_watchdog *lcw); #define LNET_ACCEPTOR_MIN_RESERVED_PORT 512 #define LNET_ACCEPTOR_MAX_RESERVED_PORT 1023 +extern struct blocking_notifier_head libcfs_ioctl_list; +static inline int notifier_from_ioctl_errno(int err) +{ + if (err == -EINVAL) + return NOTIFY_OK; + return notifier_from_errno(err) | NOTIFY_STOP_MASK; +} + /* * Defined by platform */ diff --git a/libcfs/libcfs/module.c b/libcfs/libcfs/module.c index e6e6d0c..370c905 100644 --- a/libcfs/libcfs/module.c +++ b/libcfs/libcfs/module.c @@ -58,38 +58,8 @@ static struct dentry *lnet_debugfs_root; -static DECLARE_RWSEM(ioctl_list_sem); -static LIST_HEAD(ioctl_list); - -int libcfs_register_ioctl(struct libcfs_ioctl_handler *hand) -{ - int rc = 0; - - down_write(&ioctl_list_sem); - if (!list_empty(&hand->item)) - rc = -EBUSY; - else - list_add_tail(&hand->item, &ioctl_list); - up_write(&ioctl_list_sem); - - return rc; -} -EXPORT_SYMBOL(libcfs_register_ioctl); - -int libcfs_deregister_ioctl(struct libcfs_ioctl_handler *hand) -{ - int rc = 0; - - down_write(&ioctl_list_sem); - if (list_empty(&hand->item)) - rc = -ENOENT; - else - list_del_init(&hand->item); - up_write(&ioctl_list_sem); - - return rc; -} -EXPORT_SYMBOL(libcfs_deregister_ioctl); +BLOCKING_NOTIFIER_HEAD(libcfs_ioctl_list); +EXPORT_SYMBOL(libcfs_ioctl_list); int libcfs_ioctl(unsigned long cmd, void __user *uparam) { @@ -131,22 +101,18 @@ int libcfs_ioctl(unsigned long cmd, void __user *uparam) libcfs_debug_mark_buffer(data->ioc_inlbuf1); break; - default: { - struct libcfs_ioctl_handler *hand; - - err = -EINVAL; - down_read(&ioctl_list_sem); - list_for_each_entry(hand, &ioctl_list, item) { - err = hand->handle_ioctl(cmd, hdr); - if (err == -EINVAL) - continue; - + default: + err = blocking_notifier_call_chain(&libcfs_ioctl_list, + cmd, hdr); + if (!(err & NOTIFY_STOP_MASK)) + /* No-one claimed the ioctl */ + err = -EINVAL; + else + err = notifier_to_errno(err); + if (!err) if (copy_to_user(uparam, hdr, hdr->ioc_len)) err = -EFAULT; - break; - } - up_read(&ioctl_list_sem); - break; } + break; } out: LIBCFS_FREE(hdr, hdr->ioc_len); diff --git a/lnet/include/lnet/lib-lnet.h b/lnet/include/lnet/lib-lnet.h index aeb0e4b..2b52cb7 100644 --- a/lnet/include/lnet/lib-lnet.h +++ b/lnet/include/lnet/lib-lnet.h @@ -575,19 +575,6 @@ struct lnet_ni *lnet_get_next_ni_locked(struct lnet_net *mynet, struct lnet_ni *prev); struct lnet_ni *lnet_get_ni_idx_locked(int idx); -struct libcfs_ioctl_handler { - struct list_head item; - int (*handle_ioctl)(unsigned int cmd, struct libcfs_ioctl_hdr *hdr); -}; - -#define DECLARE_IOCTL_HANDLER(ident, func) \ - static struct libcfs_ioctl_handler ident = { \ - .item = LIST_HEAD_INIT(ident.item), \ - .handle_ioctl = func \ - } - -extern int libcfs_register_ioctl(struct libcfs_ioctl_handler *hand); -extern int libcfs_deregister_ioctl(struct libcfs_ioctl_handler *hand); extern int libcfs_ioctl_getdata(struct libcfs_ioctl_hdr **hdr_pp, struct libcfs_ioctl_hdr __user *uparam); extern int lnet_get_peer_list(__u32 *countp, __u32 *sizep, diff --git a/lnet/lnet/module.c b/lnet/lnet/module.c index c30669a..676f734 100644 --- a/lnet/lnet/module.c +++ b/lnet/lnet/module.c @@ -172,36 +172,45 @@ lnet_dyn_unconfigure_ni(struct libcfs_ioctl_hdr *hdr) } static int -lnet_ioctl(unsigned int cmd, struct libcfs_ioctl_hdr *hdr) +lnet_ioctl(struct notifier_block *nb, + unsigned long cmd, void *vdata) { - int rc; + struct libcfs_ioctl_hdr *hdr = vdata; + int rc; switch (cmd) { case IOC_LIBCFS_CONFIGURE: { struct libcfs_ioctl_data *data = (struct libcfs_ioctl_data *)hdr; - if (data->ioc_hdr.ioc_len < sizeof(*data)) - return -EINVAL; - - the_lnet.ln_nis_from_mod_params = data->ioc_flags; - return lnet_configure(NULL); + if (data->ioc_hdr.ioc_len < sizeof(*data)) { + rc = -EINVAL; + } else { + the_lnet.ln_nis_from_mod_params = data->ioc_flags; + rc = lnet_configure(NULL); + } + break; } case IOC_LIBCFS_UNCONFIGURE: - return lnet_unconfigure(); + rc = lnet_unconfigure(); + break; case IOC_LIBCFS_ADD_NET: - return lnet_dyn_configure_net(hdr); + rc = lnet_dyn_configure_net(hdr); + break; case IOC_LIBCFS_DEL_NET: - return lnet_dyn_unconfigure_net(hdr); + rc = lnet_dyn_unconfigure_net(hdr); + break; case IOC_LIBCFS_ADD_LOCAL_NI: - return lnet_dyn_configure_ni(hdr); + rc = lnet_dyn_configure_ni(hdr); + break; case IOC_LIBCFS_DEL_LOCAL_NI: - return lnet_dyn_unconfigure_ni(hdr); + rc = lnet_dyn_unconfigure_ni(hdr); + break; default: /* Passing LNET_PID_ANY only gives me a ref if the net is up @@ -212,11 +221,14 @@ lnet_ioctl(unsigned int cmd, struct libcfs_ioctl_hdr *hdr) rc = LNetCtl(cmd, hdr); LNetNIFini(); } - return rc; + break; } + return notifier_from_ioctl_errno(rc); } -DECLARE_IOCTL_HANDLER(lnet_ioctl_handler, lnet_ioctl); +static struct notifier_block lnet_ioctl_handler = { + .notifier_call = lnet_ioctl, +}; static int __init lnet_init(void) { @@ -231,7 +243,8 @@ static int __init lnet_init(void) RETURN(rc); } - rc = libcfs_register_ioctl(&lnet_ioctl_handler); + rc = blocking_notifier_chain_register(&libcfs_ioctl_list, + &lnet_ioctl_handler); LASSERT(rc == 0); if (config_on_load) { @@ -247,7 +260,8 @@ static void __exit lnet_exit(void) { int rc; - rc = libcfs_deregister_ioctl(&lnet_ioctl_handler); + rc = blocking_notifier_chain_unregister(&libcfs_ioctl_list, + &lnet_ioctl_handler); LASSERT(rc == 0); lnet_lib_exit(); diff --git a/lnet/selftest/conctl.c b/lnet/selftest/conctl.c index ef878b6..4767ab8 100644 --- a/lnet/selftest/conctl.c +++ b/lnet/selftest/conctl.c @@ -805,31 +805,35 @@ out: } int -lstcon_ioctl_entry(unsigned int cmd, struct libcfs_ioctl_hdr *hdr) +lstcon_ioctl_entry(struct notifier_block *nb, + unsigned long cmd, void *vdata) { - char *buf; + struct libcfs_ioctl_hdr *hdr = vdata; struct libcfs_ioctl_data *data; - int opc; - int rc; + char *buf = NULL; + int rc = -EINVAL; + int opc; if (cmd != IOC_LIBCFS_LNETST) - return -EINVAL; + goto err; data = container_of(hdr, struct libcfs_ioctl_data, ioc_hdr); opc = data->ioc_u32[0]; if (data->ioc_plen1 > PAGE_SIZE) - return -EINVAL; + goto err; LIBCFS_ALLOC(buf, data->ioc_plen1); - if (buf == NULL) - return -ENOMEM; + if (buf == NULL) { + rc = -ENOMEM; + goto err; + } /* copy in parameter */ if (copy_from_user(buf, data->ioc_pbuf1, data->ioc_plen1)) { - LIBCFS_FREE(buf, data->ioc_plen1); - return -EFAULT; + rc = -EFAULT; + goto out_free_buf; } mutex_lock(&console_session.ses_mutex); @@ -910,6 +914,7 @@ lstcon_ioctl_entry(unsigned int cmd, struct libcfs_ioctl_hdr *hdr) break; default: rc = -EINVAL; + goto out; } if (copy_to_user(data->ioc_pbuf2, &console_session.ses_trans_stat, @@ -917,8 +922,8 @@ lstcon_ioctl_entry(unsigned int cmd, struct libcfs_ioctl_hdr *hdr) rc = -EFAULT; out: mutex_unlock(&console_session.ses_mutex); - +out_free_buf: LIBCFS_FREE(buf, data->ioc_plen1); - - return rc; +err: + return notifier_from_ioctl_errno(rc); } diff --git a/lnet/selftest/console.c b/lnet/selftest/console.c index ee41bf3..a595476 100644 --- a/lnet/selftest/console.c +++ b/lnet/selftest/console.c @@ -2004,9 +2004,9 @@ static void lstcon_init_acceptor_service(void) lstcon_acceptor_service.sv_wi_total = SFW_FRWK_WI_MAX; } -int lstcon_ioctl_entry(unsigned int cmd, struct libcfs_ioctl_hdr *hdr); - -DECLARE_IOCTL_HANDLER(lstcon_ioctl_handler, lstcon_ioctl_entry); +static struct notifier_block lstcon_ioctl_handler = { + .notifier_call = lstcon_ioctl_entry, +}; /* initialize console */ int @@ -2058,12 +2058,12 @@ lstcon_console_init(void) goto out; } - rc = libcfs_register_ioctl(&lstcon_ioctl_handler); - - if (rc == 0) { - lstcon_rpc_module_init(); - return 0; - } + rc = blocking_notifier_chain_register(&libcfs_ioctl_list, + &lstcon_ioctl_handler); + if (rc == 0) { + lstcon_rpc_module_init(); + return 0; + } out: srpc_shutdown_service(&lstcon_acceptor_service); @@ -2080,9 +2080,10 @@ out: int lstcon_console_fini(void) { - int i; + int i; - libcfs_deregister_ioctl(&lstcon_ioctl_handler); + blocking_notifier_chain_unregister(&libcfs_ioctl_list, + &lstcon_ioctl_handler); mutex_lock(&console_session.ses_mutex); diff --git a/lnet/selftest/console.h b/lnet/selftest/console.h index d1d9635..09cd0e8 100644 --- a/lnet/selftest/console.h +++ b/lnet/selftest/console.h @@ -256,6 +256,8 @@ extern int lstcon_test_add(char *batch_name, int type, int loop, void *param, int paramlen, int *retp, struct list_head __user *result_up); +int lstcon_ioctl_entry(struct notifier_block *nb, + unsigned long cmd, void *vdata); int lstcon_console_init(void); int lstcon_console_fini(void); -- 1.8.3.1