X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fobdclass%2Fkernelcomm.c;h=7afb9484a8a69855dfc9adb291d3a1d9f7a310ed;hb=01261e7b563adc97899d962f0ba2d1b430894bf7;hp=f178ebc9e02faf3faa3150370975132e55951316;hpb=7f67aa42f9123caef3cee714f1e2cee3c6848892;p=fs%2Flustre-release.git diff --git a/lustre/obdclass/kernelcomm.c b/lustre/obdclass/kernelcomm.c index f178ebc..7afb948 100644 --- a/lustre/obdclass/kernelcomm.c +++ b/lustre/obdclass/kernelcomm.c @@ -23,7 +23,7 @@ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. * Use is subject to license terms. * - * Copyright (c) 2012, 2013, Intel Corporation. + * Copyright (c) 2015, 2017, Intel Corporation. */ /* * This file is part of Lustre, http://www.lustre.org/ @@ -35,35 +35,12 @@ */ #define DEBUG_SUBSYSTEM S_CLASS -#define D_KUC D_OTHER + +#include #include #include -/* write a userspace buffer to disk. - * NOTE: this returns 0 on success, not the number of bytes written. */ -static ssize_t -filp_user_write(struct file *filp, const void *buf, size_t count, - loff_t *offset) -{ - mm_segment_t fs; - ssize_t size = 0; - - fs = get_fs(); - set_fs(KERNEL_DS); - while ((ssize_t)count > 0) { - size = vfs_write(filp, (const void __user *)buf, count, offset); - if (size < 0) - break; - count -= size; - buf += size; - size = 0; - } - set_fs(fs); - - return size; -} - /** * libcfs_kkuc_msg_put - send an message from kernel to userspace * @param fp to send the message to @@ -73,10 +50,11 @@ filp_user_write(struct file *filp, const void *buf, size_t count, int libcfs_kkuc_msg_put(struct file *filp, void *payload) { struct kuc_hdr *kuch = (struct kuc_hdr *)payload; - int rc = -ENOSYS; + ssize_t count = kuch->kuc_msglen; loff_t offset = 0; + int rc = 0; - if (filp == NULL || IS_ERR(filp)) + if (IS_ERR_OR_NULL(filp)) return -EBADF; if (kuch->kuc_magic != KUC_MAGIC) { @@ -84,11 +62,19 @@ int libcfs_kkuc_msg_put(struct file *filp, void *payload) return -ENOSYS; } - rc = filp_user_write(filp, payload, kuch->kuc_msglen, &offset); + while (count > 0) { + rc = cfs_kernel_write(filp, payload, count, &offset); + if (rc < 0) + break; + count -= rc; + payload += rc; + rc = 0; + } + if (rc < 0) CWARN("message send failed (%d)\n", rc); else - CDEBUG(D_KUC, "Sent message rc=%d, fp=%p\n", rc, filp); + CDEBUG(D_HSM, "Sent message rc=%d, fp=%p\n", rc, filp); return rc; } @@ -100,27 +86,41 @@ EXPORT_SYMBOL(libcfs_kkuc_msg_put); /** A single group registration has a uid and a file pointer */ struct kkuc_reg { struct list_head kr_chain; + struct obd_uuid kr_uuid; int kr_uid; struct file *kr_fp; char kr_data[0]; }; -static struct list_head kkuc_groups[KUC_GRP_MAX+1] = {}; +static struct list_head kkuc_groups[KUC_GRP_MAX + 1]; /* Protect message sending against remove and adds */ static DECLARE_RWSEM(kg_sem); +static inline bool libcfs_kkuc_group_is_valid(int group) +{ + return 0 <= group && group < ARRAY_SIZE(kkuc_groups); +} + +void libcfs_kkuc_init(void) +{ + int group; + + for (group = 0; group < ARRAY_SIZE(kkuc_groups); group++) + INIT_LIST_HEAD(&kkuc_groups[group]); +} + /** Add a receiver to a broadcast group * @param filp pipe to write into * @param uid identifier for this receiver * @param group group number * @param data user data */ -int libcfs_kkuc_group_add(struct file *filp, int uid, int group, - void *data, size_t data_len) +int libcfs_kkuc_group_add(struct file *filp, const struct obd_uuid *uuid, + int uid, int group, void *data, size_t data_len) { struct kkuc_reg *reg; - if (group > KUC_GRP_MAX) { + if (!libcfs_kkuc_group_is_valid(group)) { CDEBUG(D_WARNING, "Kernelcomm: bad group %d\n", group); return -EINVAL; } @@ -130,33 +130,34 @@ int libcfs_kkuc_group_add(struct file *filp, int uid, int group, return -EBADF; /* freed in group_rem */ - reg = kmalloc(sizeof(*reg) + data_len, 0); + reg = kzalloc(sizeof(*reg) + data_len, 0); if (reg == NULL) return -ENOMEM; + reg->kr_uuid = *uuid; reg->kr_fp = filp; reg->kr_uid = uid; memcpy(reg->kr_data, data, data_len); down_write(&kg_sem); - if (kkuc_groups[group].next == NULL) - INIT_LIST_HEAD(&kkuc_groups[group]); list_add(®->kr_chain, &kkuc_groups[group]); up_write(&kg_sem); - CDEBUG(D_KUC, "Added uid=%d fp=%p to group %d\n", uid, filp, group); + CDEBUG(D_HSM, "Added uid=%d fp=%p to group %d\n", uid, filp, group); return 0; } EXPORT_SYMBOL(libcfs_kkuc_group_add); -int libcfs_kkuc_group_rem(int uid, int group) +int libcfs_kkuc_group_rem(const struct obd_uuid *uuid, int uid, int group) { struct kkuc_reg *reg, *next; ENTRY; - if (kkuc_groups[group].next == NULL) - RETURN(0); + if (!libcfs_kkuc_group_is_valid(group)) { + CDEBUG(D_WARNING, "Kernelcomm: bad group %d\n", group); + return -EINVAL; + } if (uid == 0) { /* Broadcast a shutdown message */ @@ -166,14 +167,15 @@ int libcfs_kkuc_group_rem(int uid, int group) lh.kuc_transport = KUC_TRANSPORT_GENERIC; lh.kuc_msgtype = KUC_MSG_SHUTDOWN; lh.kuc_msglen = sizeof(lh); - libcfs_kkuc_group_put(group, &lh); + libcfs_kkuc_group_put(uuid, group, &lh); } down_write(&kg_sem); list_for_each_entry_safe(reg, next, &kkuc_groups[group], kr_chain) { - if ((uid == 0) || (uid == reg->kr_uid)) { + if (obd_uuid_equals(uuid, ®->kr_uuid) && + (uid == 0 || uid == reg->kr_uid)) { list_del(®->kr_chain); - CDEBUG(D_KUC, "Removed uid=%d fp=%p from group %d\n", + CDEBUG(D_HSM, "Removed uid=%d fp=%p from group %d\n", reg->kr_uid, reg->kr_fp, group); if (reg->kr_fp != NULL) fput(reg->kr_fp); @@ -186,16 +188,30 @@ int libcfs_kkuc_group_rem(int uid, int group) } EXPORT_SYMBOL(libcfs_kkuc_group_rem); -int libcfs_kkuc_group_put(int group, void *payload) +int libcfs_kkuc_group_put(const struct obd_uuid *uuid, int group, void *payload) { struct kkuc_reg *reg; int rc = 0; int one_success = 0; ENTRY; + if (!libcfs_kkuc_group_is_valid(group)) { + CDEBUG(D_WARNING, "Kernelcomm: bad group %d\n", group); + return -EINVAL; + } + down_write(&kg_sem); + + if (unlikely(list_empty(&kkuc_groups[group])) || + unlikely(OBD_FAIL_CHECK(OBD_FAIL_MDS_HSM_CT_REGISTER_NET))) { + /* no agent have fully registered, CDT will retry */ + up_write(&kg_sem); + RETURN(-EAGAIN); + } + list_for_each_entry(reg, &kkuc_groups[group], kr_chain) { - if (reg->kr_fp != NULL) { + if (obd_uuid_equals(uuid, ®->kr_uuid) && + reg->kr_fp != NULL) { rc = libcfs_kkuc_msg_put(reg->kr_fp, payload); if (rc == 0) one_success = 1; @@ -222,25 +238,21 @@ EXPORT_SYMBOL(libcfs_kkuc_group_put); * @param cb_func the function to be called. * @param cb_arg extra argument to be passed to the callback function. */ -int libcfs_kkuc_group_foreach(int group, libcfs_kkuc_cb_t cb_func, - void *cb_arg) +int libcfs_kkuc_group_foreach(const struct obd_uuid *uuid, int group, + libcfs_kkuc_cb_t cb_func, void *cb_arg) { struct kkuc_reg *reg; int rc = 0; ENTRY; - if (group > KUC_GRP_MAX) { + if (!libcfs_kkuc_group_is_valid(group)) { CDEBUG(D_WARNING, "Kernelcomm: bad group %d\n", group); RETURN(-EINVAL); } - /* no link for this group */ - if (kkuc_groups[group].next == NULL) - RETURN(0); - down_read(&kg_sem); list_for_each_entry(reg, &kkuc_groups[group], kr_chain) { - if (reg->kr_fp != NULL) + if (obd_uuid_equals(uuid, ®->kr_uuid) && reg->kr_fp != NULL) rc = cb_func(reg->kr_data, cb_arg); } up_read(&kg_sem);