linux/drivers/staging/lustre/lustre/libcfs/module.c
<<
>>
Prefs
   1/*
   2 * GPL HEADER START
   3 *
   4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 only,
   8 * as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful, but
  11 * WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13 * General Public License version 2 for more details (a copy is included
  14 * in the LICENSE file that accompanied this code).
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * version 2 along with this program; If not, see
  18 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
  19 *
  20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  21 * CA 95054 USA or visit www.sun.com if you need additional information or
  22 * have any questions.
  23 *
  24 * GPL HEADER END
  25 */
  26/*
  27 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  28 * Use is subject to license terms.
  29 *
  30 * Copyright (c) 2012, Intel Corporation.
  31 */
  32/*
  33 * This file is part of Lustre, http://www.lustre.org/
  34 * Lustre is a trademark of Sun Microsystems, Inc.
  35 */
  36
  37#define DEBUG_SUBSYSTEM S_LNET
  38
  39#include <linux/libcfs/libcfs.h>
  40#include <linux/libcfs/libcfs_crypto.h>
  41#include <linux/lnet/lib-lnet.h>
  42#include <linux/lnet/lnet.h>
  43#include "tracefile.h"
  44
  45void
  46kportal_memhog_free (struct libcfs_device_userstate *ldu)
  47{
  48        struct page **level0p = &ldu->ldu_memhog_root_page;
  49        struct page **level1p;
  50        struct page **level2p;
  51        int        count1;
  52        int        count2;
  53
  54        if (*level0p != NULL) {
  55
  56                level1p = (struct page **)page_address(*level0p);
  57                count1 = 0;
  58
  59                while (count1 < PAGE_CACHE_SIZE/sizeof(struct page *) &&
  60                       *level1p != NULL) {
  61
  62                        level2p = (struct page **)page_address(*level1p);
  63                        count2 = 0;
  64
  65                        while (count2 < PAGE_CACHE_SIZE/sizeof(struct page *) &&
  66                               *level2p != NULL) {
  67
  68                                __free_page(*level2p);
  69                                ldu->ldu_memhog_pages--;
  70                                level2p++;
  71                                count2++;
  72                        }
  73
  74                        __free_page(*level1p);
  75                        ldu->ldu_memhog_pages--;
  76                        level1p++;
  77                        count1++;
  78                }
  79
  80                __free_page(*level0p);
  81                ldu->ldu_memhog_pages--;
  82
  83                *level0p = NULL;
  84        }
  85
  86        LASSERT (ldu->ldu_memhog_pages == 0);
  87}
  88
  89int
  90kportal_memhog_alloc (struct libcfs_device_userstate *ldu, int npages, int flags)
  91{
  92        struct page **level0p;
  93        struct page **level1p;
  94        struct page **level2p;
  95        int        count1;
  96        int        count2;
  97
  98        LASSERT (ldu->ldu_memhog_pages == 0);
  99        LASSERT (ldu->ldu_memhog_root_page == NULL);
 100
 101        if (npages < 0)
 102                return -EINVAL;
 103
 104        if (npages == 0)
 105                return 0;
 106
 107        level0p = &ldu->ldu_memhog_root_page;
 108        *level0p = alloc_page(flags);
 109        if (*level0p == NULL)
 110                return -ENOMEM;
 111        ldu->ldu_memhog_pages++;
 112
 113        level1p = (struct page **)page_address(*level0p);
 114        count1 = 0;
 115        memset(level1p, 0, PAGE_CACHE_SIZE);
 116
 117        while (ldu->ldu_memhog_pages < npages &&
 118               count1 < PAGE_CACHE_SIZE/sizeof(struct page *)) {
 119
 120                if (cfs_signal_pending())
 121                        return (-EINTR);
 122
 123                *level1p = alloc_page(flags);
 124                if (*level1p == NULL)
 125                        return -ENOMEM;
 126                ldu->ldu_memhog_pages++;
 127
 128                level2p = (struct page **)page_address(*level1p);
 129                count2 = 0;
 130                memset(level2p, 0, PAGE_CACHE_SIZE);
 131
 132                while (ldu->ldu_memhog_pages < npages &&
 133                       count2 < PAGE_CACHE_SIZE/sizeof(struct page *)) {
 134
 135                        if (cfs_signal_pending())
 136                                return (-EINTR);
 137
 138                        *level2p = alloc_page(flags);
 139                        if (*level2p == NULL)
 140                                return (-ENOMEM);
 141                        ldu->ldu_memhog_pages++;
 142
 143                        level2p++;
 144                        count2++;
 145                }
 146
 147                level1p++;
 148                count1++;
 149        }
 150
 151        return 0;
 152}
 153
 154/* called when opening /dev/device */
 155static int libcfs_psdev_open(unsigned long flags, void *args)
 156{
 157        struct libcfs_device_userstate *ldu;
 158        ENTRY;
 159
 160        try_module_get(THIS_MODULE);
 161
 162        LIBCFS_ALLOC(ldu, sizeof(*ldu));
 163        if (ldu != NULL) {
 164                ldu->ldu_memhog_pages = 0;
 165                ldu->ldu_memhog_root_page = NULL;
 166        }
 167        *(struct libcfs_device_userstate **)args = ldu;
 168
 169        RETURN(0);
 170}
 171
 172/* called when closing /dev/device */
 173static int libcfs_psdev_release(unsigned long flags, void *args)
 174{
 175        struct libcfs_device_userstate *ldu;
 176        ENTRY;
 177
 178        ldu = (struct libcfs_device_userstate *)args;
 179        if (ldu != NULL) {
 180                kportal_memhog_free(ldu);
 181                LIBCFS_FREE(ldu, sizeof(*ldu));
 182        }
 183
 184        module_put(THIS_MODULE);
 185        RETURN(0);
 186}
 187
 188static struct rw_semaphore ioctl_list_sem;
 189static struct list_head ioctl_list;
 190
 191int libcfs_register_ioctl(struct libcfs_ioctl_handler *hand)
 192{
 193        int rc = 0;
 194
 195        down_write(&ioctl_list_sem);
 196        if (!list_empty(&hand->item))
 197                rc = -EBUSY;
 198        else
 199                list_add_tail(&hand->item, &ioctl_list);
 200        up_write(&ioctl_list_sem);
 201
 202        return rc;
 203}
 204EXPORT_SYMBOL(libcfs_register_ioctl);
 205
 206int libcfs_deregister_ioctl(struct libcfs_ioctl_handler *hand)
 207{
 208        int rc = 0;
 209
 210        down_write(&ioctl_list_sem);
 211        if (list_empty(&hand->item))
 212                rc = -ENOENT;
 213        else
 214                list_del_init(&hand->item);
 215        up_write(&ioctl_list_sem);
 216
 217        return rc;
 218}
 219EXPORT_SYMBOL(libcfs_deregister_ioctl);
 220
 221static int libcfs_ioctl_int(struct cfs_psdev_file *pfile,unsigned long cmd,
 222                            void *arg, struct libcfs_ioctl_data *data)
 223{
 224        int err = -EINVAL;
 225        ENTRY;
 226
 227        switch (cmd) {
 228        case IOC_LIBCFS_CLEAR_DEBUG:
 229                libcfs_debug_clear_buffer();
 230                RETURN(0);
 231        /*
 232         * case IOC_LIBCFS_PANIC:
 233         * Handled in arch/cfs_module.c
 234         */
 235        case IOC_LIBCFS_MARK_DEBUG:
 236                if (data->ioc_inlbuf1 == NULL ||
 237                    data->ioc_inlbuf1[data->ioc_inllen1 - 1] != '\0')
 238                        RETURN(-EINVAL);
 239                libcfs_debug_mark_buffer(data->ioc_inlbuf1);
 240                RETURN(0);
 241#if LWT_SUPPORT
 242        case IOC_LIBCFS_LWT_CONTROL:
 243                err = lwt_control ((data->ioc_flags & 1) != 0,
 244                                   (data->ioc_flags & 2) != 0);
 245                break;
 246
 247        case IOC_LIBCFS_LWT_SNAPSHOT: {
 248                cfs_cycles_t   now;
 249                int         ncpu;
 250                int         total_size;
 251
 252                err = lwt_snapshot (&now, &ncpu, &total_size,
 253                                    data->ioc_pbuf1, data->ioc_plen1);
 254                data->ioc_u64[0] = now;
 255                data->ioc_u32[0] = ncpu;
 256                data->ioc_u32[1] = total_size;
 257
 258                /* Hedge against broken user/kernel typedefs (e.g. cycles_t) */
 259                data->ioc_u32[2] = sizeof(lwt_event_t);
 260                data->ioc_u32[3] = offsetof(lwt_event_t, lwte_where);
 261
 262                if (err == 0 &&
 263                    libcfs_ioctl_popdata(arg, data, sizeof (*data)))
 264                        err = -EFAULT;
 265                break;
 266        }
 267
 268        case IOC_LIBCFS_LWT_LOOKUP_STRING:
 269                err = lwt_lookup_string (&data->ioc_count, data->ioc_pbuf1,
 270                                         data->ioc_pbuf2, data->ioc_plen2);
 271                if (err == 0 &&
 272                    libcfs_ioctl_popdata(arg, data, sizeof (*data)))
 273                        err = -EFAULT;
 274                break;
 275#endif
 276        case IOC_LIBCFS_MEMHOG:
 277                if (pfile->private_data == NULL) {
 278                        err = -EINVAL;
 279                } else {
 280                        kportal_memhog_free(pfile->private_data);
 281                        /* XXX The ioc_flags is not GFP flags now, need to be fixed */
 282                        err = kportal_memhog_alloc(pfile->private_data,
 283                                                   data->ioc_count,
 284                                                   data->ioc_flags);
 285                        if (err != 0)
 286                                kportal_memhog_free(pfile->private_data);
 287                }
 288                break;
 289
 290        case IOC_LIBCFS_PING_TEST: {
 291                extern void (kping_client)(struct libcfs_ioctl_data *);
 292                void (*ping)(struct libcfs_ioctl_data *);
 293
 294                CDEBUG(D_IOCTL, "doing %d pings to nid %s (%s)\n",
 295                       data->ioc_count, libcfs_nid2str(data->ioc_nid),
 296                       libcfs_nid2str(data->ioc_nid));
 297                ping = symbol_get(kping_client);
 298                if (!ping)
 299                        CERROR("symbol_get failed\n");
 300                else {
 301                        ping(data);
 302                        symbol_put(kping_client);
 303                }
 304                RETURN(0);
 305        }
 306
 307        default: {
 308                struct libcfs_ioctl_handler *hand;
 309                err = -EINVAL;
 310                down_read(&ioctl_list_sem);
 311                list_for_each_entry(hand, &ioctl_list, item) {
 312                        err = hand->handle_ioctl(cmd, data);
 313                        if (err != -EINVAL) {
 314                                if (err == 0)
 315                                        err = libcfs_ioctl_popdata(arg,
 316                                                        data, sizeof (*data));
 317                                break;
 318                        }
 319                }
 320                up_read(&ioctl_list_sem);
 321                break;
 322        }
 323        }
 324
 325        RETURN(err);
 326}
 327
 328static int libcfs_ioctl(struct cfs_psdev_file *pfile, unsigned long cmd, void *arg)
 329{
 330        char    *buf;
 331        struct libcfs_ioctl_data *data;
 332        int err = 0;
 333        ENTRY;
 334
 335        LIBCFS_ALLOC_GFP(buf, 1024, GFP_IOFS);
 336        if (buf == NULL)
 337                RETURN(-ENOMEM);
 338
 339        /* 'cmd' and permissions get checked in our arch-specific caller */
 340        if (libcfs_ioctl_getdata(buf, buf + 800, (void *)arg)) {
 341                CERROR("PORTALS ioctl: data error\n");
 342                GOTO(out, err = -EINVAL);
 343        }
 344        data = (struct libcfs_ioctl_data *)buf;
 345
 346        err = libcfs_ioctl_int(pfile, cmd, arg, data);
 347
 348out:
 349        LIBCFS_FREE(buf, 1024);
 350        RETURN(err);
 351}
 352
 353
 354struct cfs_psdev_ops libcfs_psdev_ops = {
 355        libcfs_psdev_open,
 356        libcfs_psdev_release,
 357        NULL,
 358        NULL,
 359        libcfs_ioctl
 360};
 361
 362extern int insert_proc(void);
 363extern void remove_proc(void);
 364MODULE_AUTHOR("Peter J. Braam <braam@clusterfs.com>");
 365MODULE_DESCRIPTION("Portals v3.1");
 366MODULE_LICENSE("GPL");
 367
 368extern psdev_t libcfs_dev;
 369extern struct rw_semaphore cfs_tracefile_sem;
 370extern struct mutex cfs_trace_thread_mutex;
 371extern struct cfs_wi_sched *cfs_sched_rehash;
 372
 373extern void libcfs_init_nidstrings(void);
 374extern int libcfs_arch_init(void);
 375extern void libcfs_arch_cleanup(void);
 376
 377static int init_libcfs_module(void)
 378{
 379        int rc;
 380
 381        libcfs_arch_init();
 382        libcfs_init_nidstrings();
 383        init_rwsem(&cfs_tracefile_sem);
 384        mutex_init(&cfs_trace_thread_mutex);
 385        init_rwsem(&ioctl_list_sem);
 386        INIT_LIST_HEAD(&ioctl_list);
 387        init_waitqueue_head(&cfs_race_waitq);
 388
 389        rc = libcfs_debug_init(5 * 1024 * 1024);
 390        if (rc < 0) {
 391                printk(KERN_ERR "LustreError: libcfs_debug_init: %d\n", rc);
 392                return (rc);
 393        }
 394
 395        rc = cfs_cpu_init();
 396        if (rc != 0)
 397                goto cleanup_debug;
 398
 399#if LWT_SUPPORT
 400        rc = lwt_init();
 401        if (rc != 0) {
 402                CERROR("lwt_init: error %d\n", rc);
 403                goto cleanup_debug;
 404        }
 405#endif
 406        rc = misc_register(&libcfs_dev);
 407        if (rc) {
 408                CERROR("misc_register: error %d\n", rc);
 409                goto cleanup_lwt;
 410        }
 411
 412        rc = cfs_wi_startup();
 413        if (rc) {
 414                CERROR("initialize workitem: error %d\n", rc);
 415                goto cleanup_deregister;
 416        }
 417
 418        /* max to 4 threads, should be enough for rehash */
 419        rc = min(cfs_cpt_weight(cfs_cpt_table, CFS_CPT_ANY), 4);
 420        rc = cfs_wi_sched_create("cfs_rh", cfs_cpt_table, CFS_CPT_ANY,
 421                                 rc, &cfs_sched_rehash);
 422        if (rc != 0) {
 423                CERROR("Startup workitem scheduler: error: %d\n", rc);
 424                goto cleanup_deregister;
 425        }
 426
 427        rc = cfs_crypto_register();
 428        if (rc) {
 429                CERROR("cfs_crypto_regster: error %d\n", rc);
 430                goto cleanup_wi;
 431        }
 432
 433
 434        rc = insert_proc();
 435        if (rc) {
 436                CERROR("insert_proc: error %d\n", rc);
 437                goto cleanup_crypto;
 438        }
 439
 440        CDEBUG (D_OTHER, "portals setup OK\n");
 441        return 0;
 442 cleanup_crypto:
 443        cfs_crypto_unregister();
 444 cleanup_wi:
 445        cfs_wi_shutdown();
 446 cleanup_deregister:
 447        misc_deregister(&libcfs_dev);
 448 cleanup_lwt:
 449#if LWT_SUPPORT
 450        lwt_fini();
 451#endif
 452 cleanup_debug:
 453        libcfs_debug_cleanup();
 454        return rc;
 455}
 456
 457static void exit_libcfs_module(void)
 458{
 459        int rc;
 460
 461        remove_proc();
 462
 463        CDEBUG(D_MALLOC, "before Portals cleanup: kmem %d\n",
 464               atomic_read(&libcfs_kmemory));
 465
 466        if (cfs_sched_rehash != NULL) {
 467                cfs_wi_sched_destroy(cfs_sched_rehash);
 468                cfs_sched_rehash = NULL;
 469        }
 470
 471        cfs_crypto_unregister();
 472        cfs_wi_shutdown();
 473
 474        rc = misc_deregister(&libcfs_dev);
 475        if (rc)
 476                CERROR("misc_deregister error %d\n", rc);
 477
 478#if LWT_SUPPORT
 479        lwt_fini();
 480#endif
 481        cfs_cpu_fini();
 482
 483        if (atomic_read(&libcfs_kmemory) != 0)
 484                CERROR("Portals memory leaked: %d bytes\n",
 485                       atomic_read(&libcfs_kmemory));
 486
 487        rc = libcfs_debug_cleanup();
 488        if (rc)
 489                printk(KERN_ERR "LustreError: libcfs_debug_cleanup: %d\n",
 490                       rc);
 491
 492        fini_rwsem(&ioctl_list_sem);
 493        fini_rwsem(&cfs_tracefile_sem);
 494
 495        libcfs_arch_cleanup();
 496}
 497
 498cfs_module(libcfs, "1.0.0", init_libcfs_module, exit_libcfs_module);
 499