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.
Signed-off-by: NeilBrown <neilb@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
#define LNET_ACCEPTOR_MIN_RESERVED_PORT 512
#define LNET_ACCEPTOR_MAX_RESERVED_PORT 1023
-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) \
- struct libcfs_ioctl_handler ident = { \
- .item = LIST_HEAD_INIT(ident.item), \
- .handle_ioctl = func \
- }
+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;
+}
-int libcfs_register_ioctl(struct libcfs_ioctl_handler *hand);
-int libcfs_deregister_ioctl(struct libcfs_ioctl_handler *hand);
int libcfs_setup(void);
#define _LIBCFS_H
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);
static inline size_t libcfs_ioctl_packlen(struct libcfs_ioctl_data *data)
{
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;
-
- if (!err) {
- if (copy_to_user(uparam, hdr, hdr->ioc_len))
- err = -EFAULT;
- }
- break;
- }
- up_read(&ioctl_list_sem);
- break; }
+ 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;
}
out:
kvfree(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;
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(hdr);
+ rc = lnet_dyn_configure(hdr);
+ break;
case IOC_LIBCFS_DEL_NET:
- return lnet_dyn_unconfigure(hdr);
+ rc = lnet_dyn_unconfigure(hdr);
+ break;
default:
/*
rc = LNetCtl(cmd, hdr);
LNetNIFini();
}
- return rc;
+ break;
}
+ return notifier_from_ioctl_errno(rc);
}
-static 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)
{
return rc;
}
- rc = libcfs_register_ioctl(&lnet_ioctl_handler);
+ rc = blocking_notifier_chain_register(&libcfs_ioctl_list,
+ &lnet_ioctl_handler);
LASSERT(!rc);
if (config_on_load) {
{
int rc;
- rc = libcfs_deregister_ioctl(&lnet_ioctl_handler);
+ rc = blocking_notifier_chain_unregister(&libcfs_ioctl_list,
+ &lnet_ioctl_handler);
LASSERT(!rc);
lnet_lib_exit();
}
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;
+ char *buf = NULL;
struct libcfs_ioctl_data *data;
int opc;
- int rc;
+ int rc = -EINVAL;
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;
buf = kmalloc(data->ioc_plen1, GFP_KERNEL);
+ rc = -ENOMEM;
if (!buf)
- return -ENOMEM;
+ goto err;
/* copy in parameter */
- if (copy_from_user(buf, data->ioc_pbuf1, data->ioc_plen1)) {
- kfree(buf);
- return -EFAULT;
- }
+ rc = -EFAULT;
+ if (copy_from_user(buf, data->ioc_pbuf1, data->ioc_plen1))
+ goto err;
mutex_lock(&console_session.ses_mutex);
break;
default:
rc = -EINVAL;
+ goto out;
}
if (copy_to_user(data->ioc_pbuf2, &console_session.ses_trans_stat,
rc = -EFAULT;
out:
mutex_unlock(&console_session.ses_mutex);
-
+err:
kfree(buf);
- return rc;
+ return notifier_from_ioctl_errno(rc);
}
lstcon_acceptor_service.sv_wi_total = SFW_FRWK_WI_MAX;
}
-static DECLARE_IOCTL_HANDLER(lstcon_ioctl_handler, lstcon_ioctl_entry);
+static struct notifier_block lstcon_ioctl_handler = {
+ .notifier_call = lstcon_ioctl_entry,
+};
/* initialize console */
int
goto out;
}
- rc = libcfs_register_ioctl(&lstcon_ioctl_handler);
+ rc = blocking_notifier_chain_register(&libcfs_ioctl_list,
+ &lstcon_ioctl_handler);
if (!rc) {
lstcon_rpc_module_init();
{
int i;
- libcfs_deregister_ioctl(&lstcon_ioctl_handler);
+ blocking_notifier_chain_unregister(&libcfs_ioctl_list,
+ &lstcon_ioctl_handler);
mutex_lock(&console_session.ses_mutex);
return &hash[idx];
}
-int lstcon_ioctl_entry(unsigned int cmd, struct libcfs_ioctl_hdr *hdr);
+int lstcon_ioctl_entry(struct notifier_block *nb,
+ unsigned long cmd, void *vdata);
int lstcon_console_init(void);
int lstcon_console_fini(void);
int lstcon_session_match(struct lst_sid sid);