4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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
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
27 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Use is subject to license terms.
30 * Copyright (c) 2011, 2012, Intel Corporation.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
37 #define DEBUG_SUBSYSTEM S_LNET
39 #include <libcfs/libcfs.h>
48 * Lustre thread procedure wrapper routine (It's an internal routine)
51 * context: a structure of cfs_thread_context_t, containing
52 * all the necessary parameters
62 cfs_thread_proc(void *context)
64 cfs_thread_context_t * thread_context =
65 (cfs_thread_context_t *) context;
67 /* Execute the specified function ... */
69 if (thread_context->func) {
70 (thread_context->func)(thread_context->arg);
73 /* Free the context memory */
77 /* Terminate this system thread */
79 PsTerminateSystemThread(STATUS_SUCCESS);
84 * Create a system thread to execute the routine specified
87 * func: function to be executed in the thread
88 * arg: argument transferred to func function
89 * name: thread name to create
92 * struct task_struct: 0 on success or error codes
98 struct task_struct kthread_run(int (*func)(void *), void *arg, char *name)
100 cfs_handle_t thread = NULL;
102 cfs_thread_context_t *context = NULL;
104 /* Allocate the context to be transferred to system thread */
106 context = kmalloc(sizeof(cfs_thread_context_t), __GFP_ZERO);
109 return ERR_PTR(-ENOMEM);
112 context->func = func;
115 /* Create system thread with the cfs_thread_proc wrapper */
117 status = PsCreateSystemThread(
124 if (!NT_SUCCESS(status)) {
129 /* We need translate the nt status to linux error code */
131 return ERR_PTR(cfs_error_code(status));
135 // Query the thread id of the newly created thread
140 return (struct task_struct)0;
149 static DECLARE_RWSEM(cfs_symbol_lock);
150 CFS_LIST_HEAD(cfs_symbol_list);
152 int libcfs_is_mp_system = FALSE;
156 * To query the specified symbol form the symbol table
159 * name: the symbol name to be queried
162 * If the symbol is in the table, return the address of it.
163 * If not, return NULL.
170 cfs_symbol_get(const char *name)
173 struct cfs_symbol *sym = NULL;
175 down_read(&cfs_symbol_lock);
176 cfs_list_for_each(walker, &cfs_symbol_list) {
177 sym = cfs_list_entry (walker, struct cfs_symbol, sym_list);
178 if (!strcmp(sym->name, name)) {
183 up_read(&cfs_symbol_lock);
193 * To decrease the reference of the specified symbol
196 * name: the symbol name to be dereferred
206 cfs_symbol_put(const char *name)
209 struct cfs_symbol *sym = NULL;
211 down_read(&cfs_symbol_lock);
212 cfs_list_for_each(walker, &cfs_symbol_list) {
213 sym = cfs_list_entry (walker, struct cfs_symbol, sym_list);
214 if (!strcmp(sym->name, name)) {
215 LASSERT(sym->ref > 0);
220 up_read(&cfs_symbol_lock);
222 LASSERT(sym != NULL);
227 * cfs_symbol_register
228 * To register the specified symbol infromation
231 * name: the symbol name to be dereferred
232 * value: the value that the symbol stands for
238 * Zero: Succeed to register
239 * Non-Zero: Fail to register the symbol
243 cfs_symbol_register(const char *name, const void *value)
246 struct cfs_symbol *sym = NULL;
247 struct cfs_symbol *new = NULL;
249 new = kmalloc(sizeof(struct cfs_symbol), __GFP_ZERO);
253 strncpy(new->name, name, CFS_SYMBOL_LEN);
254 new->value = (void *)value;
256 CFS_INIT_LIST_HEAD(&new->sym_list);
258 down_write(&cfs_symbol_lock);
259 cfs_list_for_each(walker, &cfs_symbol_list) {
260 sym = cfs_list_entry (walker, struct cfs_symbol, sym_list);
261 if (!strcmp(sym->name, name)) {
262 up_write(&cfs_symbol_lock);
264 return 0; /* alreay registerred */
267 cfs_list_add_tail(&new->sym_list, &cfs_symbol_list);
268 up_write(&cfs_symbol_lock);
274 * cfs_symbol_unregister
275 * To unregister/remove the specified symbol
278 * name: the symbol name to be dereferred
288 cfs_symbol_unregister(const char *name)
292 struct cfs_symbol *sym = NULL;
294 down_write(&cfs_symbol_lock);
295 cfs_list_for_each_safe(walker, nxt, &cfs_symbol_list) {
296 sym = cfs_list_entry (walker, struct cfs_symbol, sym_list);
297 if (!strcmp(sym->name, name)) {
298 LASSERT(sym->ref == 0);
299 cfs_list_del (&sym->sym_list);
304 up_write(&cfs_symbol_lock);
309 * To clean all the symbols
325 struct cfs_symbol *sym = NULL;
327 down_write(&cfs_symbol_lock);
328 cfs_list_for_each(walker, &cfs_symbol_list) {
329 sym = cfs_list_entry (walker, struct cfs_symbol, sym_list);
330 LASSERT(sym->ref == 0);
331 cfs_list_del (&sym->sym_list);
334 up_write(&cfs_symbol_lock);
345 /* Timer dpc procedure */
350 IN PVOID DeferredContext,
351 IN PVOID SystemArgument1,
352 IN PVOID SystemArgument2)
354 struct timer_list * timer;
357 timer = (struct timer_list *) DeferredContext;
360 KeAcquireSpinLock(&(timer->Lock), &Irql);
361 cfs_clear_flag(timer->Flags, CFS_TIMER_FLAG_TIMERED);
362 KeReleaseSpinLock(&(timer->Lock), Irql);
364 /* call the user specified timer procedure */
365 timer->proc((long_ptr_t)timer->arg);
368 void cfs_init_timer(struct timer_list *timer)
370 memset(timer, 0, sizeof(struct timer_list));
375 * To initialize the struct timer_list
378 * timer: the cfs_timer to be initialized
379 * func: the timer callback procedure
380 * arg: argument for the callback proc
389 void cfs_timer_init(struct timer_list *timer, void (*func)(ulong_ptr_t), void *arg)
391 memset(timer, 0, sizeof(struct timer_list));
396 KeInitializeSpinLock(&(timer->Lock));
397 KeInitializeTimer(&timer->Timer);
398 KeInitializeDpc (&timer->Dpc, cfs_timer_dpc_proc, timer);
400 cfs_set_flag(timer->Flags, CFS_TIMER_FLAG_INITED);
405 * To finialize the struct timer_list (unused)
408 * timer: the cfs_timer to be cleaned up
417 void cfs_timer_done(struct timer_list *timer)
424 * To schedule the timer while touching @deadline
427 * timer: the cfs_timer to be freed
428 * dealine: timeout value to wake up the timer
437 void cfs_timer_arm(struct timer_list *timer, cfs_time_t deadline)
439 LARGE_INTEGER timeout;
442 KeAcquireSpinLock(&(timer->Lock), &Irql);
443 if (!cfs_is_flag_set(timer->Flags, CFS_TIMER_FLAG_TIMERED)){
445 timeout.QuadPart = (LONGLONG)-1*1000*1000*10/HZ*deadline;
447 if (KeSetTimer(&timer->Timer, timeout, &timer->Dpc)) {
448 cfs_set_flag(timer->Flags, CFS_TIMER_FLAG_TIMERED);
451 timer->deadline = deadline;
454 KeReleaseSpinLock(&(timer->Lock), Irql);
459 * To discard the timer to be scheduled
462 * timer: the cfs_timer to be discarded
471 void cfs_timer_disarm(struct timer_list *timer)
475 KeAcquireSpinLock(&(timer->Lock), &Irql);
476 KeCancelTimer(&(timer->Timer));
477 cfs_clear_flag(timer->Flags, CFS_TIMER_FLAG_TIMERED);
478 KeReleaseSpinLock(&(timer->Lock), Irql);
484 * To check the timer is scheduled or not
487 * timer: the cfs_timer to be checked
497 int cfs_timer_is_armed(struct timer_list *timer)
502 KeAcquireSpinLock(&(timer->Lock), &Irql);
503 if (cfs_is_flag_set(timer->Flags, CFS_TIMER_FLAG_TIMERED)) {
506 KeReleaseSpinLock(&(timer->Lock), Irql);
513 * To query the deadline of the timer
516 * timer: the cfs_timer to be queried
525 cfs_time_t cfs_timer_deadline(struct timer_list * timer)
527 return timer->deadline;
530 int unshare_fs_struct()
536 * routine related with sigals
539 sigset_t cfs_block_allsigs()
544 sigset_t cfs_block_sigs(sigset_t bit)
549 /* Block all signals except for the @sigs. It's only used in
550 * Linux kernel, just a dummy here. */
551 sigset_t cfs_block_sigsinv(unsigned long sigs)
556 void cfs_restore_sigs(sigset_t old)
560 int cfs_signal_pending(void)
565 void cfs_clear_sigpending(void)
571 * thread cpu affinity routines
574 typedef struct _THREAD_BASIC_INFORMATION {
576 PVOID TebBaseAddress;
578 ULONG_PTR AffinityMask;
581 } THREAD_BASIC_INFORMATION;
583 typedef THREAD_BASIC_INFORMATION *PTHREAD_BASIC_INFORMATION;
585 #define THREAD_QUERY_INFORMATION (0x0040)
591 __out PHANDLE ThreadHandle,
592 __in ACCESS_MASK DesiredAccess,
593 __in POBJECT_ATTRIBUTES ObjectAttributes,
594 __in_opt PCLIENT_ID ClientId
600 ZwQueryInformationThread (
601 __in HANDLE ThreadHandle,
602 __in THREADINFOCLASS ThreadInformationClass,
603 __out_bcount(ThreadInformationLength) PVOID ThreadInformation,
604 __in ULONG ThreadInformationLength,
605 __out_opt PULONG ReturnLength
611 ZwSetInformationThread (
612 __in HANDLE ThreadHandle,
613 __in THREADINFOCLASS ThreadInformationClass,
614 __in_bcount(ThreadInformationLength) PVOID ThreadInformation,
615 __in ULONG ThreadInformationLength
619 cfs_open_current_thread()
622 HANDLE handle = NULL;
623 OBJECT_ATTRIBUTES oa;
626 /* initialize object attributes */
627 InitializeObjectAttributes( &oa, NULL, OBJ_KERNEL_HANDLE |
628 OBJ_CASE_INSENSITIVE, NULL, NULL);
630 /* initialize client id */
631 cid.UniqueProcess = PsGetCurrentProcessId();
632 cid.UniqueThread = PsGetCurrentThreadId();
634 /* get thread handle */
635 status = ZwOpenThread( &handle, THREAD_QUERY_INFORMATION |
636 THREAD_SET_INFORMATION, &oa, &cid);
637 if (!NT_SUCCESS(status)) {
645 cfs_close_thread_handle(HANDLE handle)
652 cfs_query_thread_affinity()
655 HANDLE handle = NULL;
657 THREAD_BASIC_INFORMATION TBI = {0};
659 /* open current thread */
660 handle = cfs_open_current_thread();
665 /* query thread cpu affinity */
666 status = ZwQueryInformationThread(handle, ThreadBasicInformation,
667 &TBI, sizeof(THREAD_BASIC_INFORMATION), &size);
668 if (!NT_SUCCESS(status)) {
674 cfs_close_thread_handle(handle);
675 return TBI.AffinityMask;
679 cfs_set_thread_affinity(KAFFINITY affinity)
682 HANDLE handle = NULL;
684 /* open current thread */
685 handle = cfs_open_current_thread();
690 /* set thread cpu affinity */
691 status = ZwSetInformationThread(handle, ThreadAffinityMask,
692 &affinity, sizeof(KAFFINITY));
693 if (!NT_SUCCESS(status)) {
699 cfs_close_thread_handle(handle);
700 return NT_SUCCESS(status);
704 cfs_tie_thread_to_cpu(int cpu)
706 return cfs_set_thread_affinity((KAFFINITY) (1 << cpu));
710 cfs_set_thread_priority(KPRIORITY priority)
713 HANDLE handle = NULL;
715 /* open current thread */
716 handle = cfs_open_current_thread();
721 /* set thread cpu affinity */
722 status = ZwSetInformationThread(handle, ThreadPriority,
723 &priority, sizeof(KPRIORITY));
724 if (!NT_SUCCESS(status)) {
725 KdPrint(("set_thread_priority failed: %xh\n", status));
731 cfs_close_thread_handle(handle);
732 return NT_SUCCESS(status);
735 int need_resched(void)
740 void cond_resched(void)
745 ** Initialize routines
748 void cfs_libc_init();
751 libcfs_arch_init(void)
756 /* Workground to check the system is MP build or UP build */
757 spin_lock_init(&lock);
759 libcfs_is_mp_system = (int)lock.lock;
760 /* MP build system: it's a real spin, for UP build system, it
761 * only raises the IRQL to DISPATCH_LEVEL */
764 /* initialize libc routines (confliction between libcnptr.lib
765 and kernel ntoskrnl.lib) */
768 /* create slab memory caches for page alloctors */
769 cfs_page_t_slab = kmem_cache_create("CPGT", sizeof(struct page),
772 cfs_page_p_slab = kmem_cache_create("CPGP", PAGE_CACHE_SIZE,
775 if ( cfs_page_t_slab == NULL ||
776 cfs_page_p_slab == NULL ){
781 rc = init_task_manager();
783 cfs_enter_debugger();
784 KdPrint(("winnt-prim.c:libcfs_arch_init: error initializing task manager ...\n"));
788 /* initialize the proc file system */
791 cfs_enter_debugger();
792 KdPrint(("winnt-prim.c:libcfs_arch_init: error initializing proc fs ...\n"));
793 cleanup_task_manager();
797 /* initialize the tdi data */
798 rc = ks_init_tdi_data();
800 cfs_enter_debugger();
801 KdPrint(("winnt-prim.c:libcfs_arch_init: failed to initialize tdi.\n"));
803 cleanup_task_manager();
807 rc = start_shrinker_timer();
812 /* destroy the taskslot cache slab */
814 kmem_cache_destroy(cfs_page_t_slab);
816 kmem_cache_destroy(cfs_page_p_slab);
823 libcfs_arch_cleanup(void)
825 /* stop shrinker timer */
826 stop_shrinker_timer();
828 /* finialize the tdi data */
831 /* detroy the whole proc fs tree and nodes */
834 /* cleanup context of task manager */
835 cleanup_task_manager();
837 /* destroy the taskslot cache slab */
838 if (cfs_page_t_slab) {
839 kmem_cache_destroy(cfs_page_t_slab);
842 if (cfs_page_p_slab) {
843 kmem_cache_destroy(cfs_page_p_slab);
849 EXPORT_SYMBOL(libcfs_arch_init);
850 EXPORT_SYMBOL(libcfs_arch_cleanup);