Whamcloud - gitweb
LU-2446 build: Update Whamcloud copyright messages for Intel
[fs/lustre-release.git] / libcfs / libcfs / winnt / winnt-prim.c
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) 2011, 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 <libcfs/libcfs.h>
40
41
42 /*
43  *  Thread routines
44  */
45
46 /*
47  * cfs_thread_proc
48  *   Lustre thread procedure wrapper routine (It's an internal routine)
49  *
50  * Arguments:
51  *   context:  a structure of cfs_thread_context_t, containing
52  *             all the necessary parameters
53  *
54  * Return Value:
55  *   void: N/A
56  *
57  * Notes:
58  *   N/A
59  */
60
61 void
62 cfs_thread_proc(
63     void * context
64     )
65 {
66     cfs_thread_context_t * thread_context =
67         (cfs_thread_context_t *) context;
68
69     /* Execute the specified function ... */
70
71     if (thread_context->func) {
72         (thread_context->func)(thread_context->arg);
73     }
74
75     /* Free the context memory */
76
77     cfs_free(context);
78
79     /* Terminate this system thread */
80
81     PsTerminateSystemThread(STATUS_SUCCESS);
82 }
83
84 /*
85  * cfs_create_thread
86  *   Create a system thread to execute the routine specified
87  *
88  * Arguments:
89  *   func:  function to be executed in the thread
90  *   arg:   argument transferred to func function
91  *   flag:  thread creation flags.
92  *
93  * Return Value:
94  *   int:   0 on success or error codes
95  *
96  * Notes:
97  *   N/A
98  */
99
100 int cfs_create_thread(int (*func)(void *), void *arg, unsigned long flag)
101 {
102     cfs_handle_t  thread = NULL;
103     NTSTATUS      status;
104     cfs_thread_context_t * context = NULL;
105
106     /* Allocate the context to be transferred to system thread */
107
108     context = cfs_alloc(sizeof(cfs_thread_context_t), CFS_ALLOC_ZERO);
109
110     if (!context) {
111         return -ENOMEM;
112     }
113
114     context->func  = func;
115     context->arg   = arg;
116
117     /* Create system thread with the cfs_thread_proc wrapper */
118
119     status = PsCreateSystemThread(
120                 &thread,
121                 (ACCESS_MASK)0L,
122                 0, 0, 0,
123                 cfs_thread_proc,
124                 context);
125
126     if (!NT_SUCCESS(status)) {
127
128
129         cfs_free(context);
130
131         /* We need translate the nt status to linux error code */
132
133         return cfs_error_code(status);
134     }
135
136     //
137     //  Query the thread id of the newly created thread
138     //
139
140     ZwClose(thread);
141
142     return 0;
143 }
144
145
146 /*
147  * Symbols routines
148  */
149
150
151 static DECLARE_RWSEM(cfs_symbol_lock);
152 CFS_LIST_HEAD(cfs_symbol_list);
153
154 int libcfs_is_mp_system = FALSE;
155
156 /*
157  * cfs_symbol_get
158  *   To query the specified symbol form the symbol table
159  *
160  * Arguments:
161  *   name:  the symbol name to be queried
162  *
163  * Return Value:
164  *   If the symbol is in the table, return the address of it.
165  *   If not, return NULL.
166  *
167  * Notes:
168  *   N/A
169  */
170
171 void *
172 cfs_symbol_get(const char *name)
173 {
174     cfs_list_t              *walker;
175     struct cfs_symbol       *sym = NULL;
176
177         down_read(&cfs_symbol_lock);
178     cfs_list_for_each(walker, &cfs_symbol_list) {
179         sym = cfs_list_entry (walker, struct cfs_symbol, sym_list);
180         if (!strcmp(sym->name, name)) {
181             sym->ref ++;
182             break;
183         }
184     }
185         up_read(&cfs_symbol_lock);
186
187     if (sym != NULL)
188         return sym->value;
189
190     return NULL;
191 }
192
193 /*
194  * cfs_symbol_put
195  *   To decrease the reference of  the specified symbol
196  *
197  * Arguments:
198  *   name:  the symbol name to be dereferred
199  *
200  * Return Value:
201  *   N/A
202  *
203  * Notes:
204  *   N/A
205  */
206
207 void
208 cfs_symbol_put(const char *name)
209 {
210     cfs_list_t              *walker;
211     struct cfs_symbol       *sym = NULL;
212
213         down_read(&cfs_symbol_lock);
214     cfs_list_for_each(walker, &cfs_symbol_list) {
215         sym = cfs_list_entry (walker, struct cfs_symbol, sym_list);
216         if (!strcmp(sym->name, name)) {
217             LASSERT(sym->ref > 0);
218             sym->ref--;
219             break;
220         }
221     }
222         up_read(&cfs_symbol_lock);
223
224     LASSERT(sym != NULL);
225 }
226
227
228 /*
229  * cfs_symbol_register
230  *   To register the specified symbol infromation
231  *
232  * Arguments:
233  *   name:  the symbol name to be dereferred
234  *   value: the value that the symbol stands for
235  *
236  * Return Value:
237  *   N/A
238  *
239  * Notes:
240  *   Zero: Succeed to register
241  *   Non-Zero: Fail to register the symbol
242  */
243
244 int
245 cfs_symbol_register(const char *name, const void *value)
246 {
247     cfs_list_t              *walker;
248     struct cfs_symbol       *sym = NULL;
249     struct cfs_symbol       *new = NULL;
250
251     new = cfs_alloc(sizeof(struct cfs_symbol), CFS_ALLOC_ZERO);
252     if (!new) {
253         return (-ENOMEM);
254     }
255     strncpy(new->name, name, CFS_SYMBOL_LEN);
256     new->value = (void *)value;
257     new->ref = 0;
258     CFS_INIT_LIST_HEAD(&new->sym_list);
259
260         down_write(&cfs_symbol_lock);
261         cfs_list_for_each(walker, &cfs_symbol_list) {
262                 sym = cfs_list_entry (walker, struct cfs_symbol, sym_list);
263                 if (!strcmp(sym->name, name)) {
264                         up_write(&cfs_symbol_lock);
265                         cfs_free(new);
266                         return 0; /* alreay registerred */
267                 }
268         }
269         cfs_list_add_tail(&new->sym_list, &cfs_symbol_list);
270         up_write(&cfs_symbol_lock);
271
272     return 0;
273 }
274
275 /*
276  * cfs_symbol_unregister
277  *   To unregister/remove the specified symbol
278  *
279  * Arguments:
280  *   name:  the symbol name to be dereferred
281  *
282  * Return Value:
283  *   N/A
284  *
285  * Notes:
286  *   N/A
287  */
288
289 void
290 cfs_symbol_unregister(const char *name)
291 {
292     cfs_list_t              *walker;
293     cfs_list_t              *nxt;
294     struct cfs_symbol       *sym = NULL;
295
296         down_write(&cfs_symbol_lock);
297     cfs_list_for_each_safe(walker, nxt, &cfs_symbol_list) {
298         sym = cfs_list_entry (walker, struct cfs_symbol, sym_list);
299         if (!strcmp(sym->name, name)) {
300             LASSERT(sym->ref == 0);
301             cfs_list_del (&sym->sym_list);
302             cfs_free(sym);
303             break;
304         }
305     }
306         up_write(&cfs_symbol_lock);
307 }
308
309 /*
310  * cfs_symbol_clean
311  *   To clean all the symbols
312  *
313  * Arguments:
314  *   N/A
315  *
316  * Return Value:
317  *   N/A
318  *
319  * Notes:
320  *   N/A
321  */
322
323 void
324 cfs_symbol_clean()
325 {
326     cfs_list_t          *walker;
327     struct cfs_symbol   *sym = NULL;
328
329         down_write(&cfs_symbol_lock);
330         cfs_list_for_each(walker, &cfs_symbol_list) {
331                 sym = cfs_list_entry (walker, struct cfs_symbol, sym_list);
332                 LASSERT(sym->ref == 0);
333                 cfs_list_del (&sym->sym_list);
334                 cfs_free(sym);
335         }
336         up_write(&cfs_symbol_lock);
337         return;
338 }
339
340
341
342 /*
343  * Timer routines
344  */
345
346
347 /* Timer dpc procedure */
348
349 static void
350 cfs_timer_dpc_proc (
351     IN PKDPC Dpc,
352     IN PVOID DeferredContext,
353     IN PVOID SystemArgument1,
354     IN PVOID SystemArgument2)
355 {
356     cfs_timer_t *   timer;
357     KIRQL           Irql;
358
359     timer = (cfs_timer_t *) DeferredContext;
360
361     /* clear the flag */
362     KeAcquireSpinLock(&(timer->Lock), &Irql);
363     cfs_clear_flag(timer->Flags, CFS_TIMER_FLAG_TIMERED);
364     KeReleaseSpinLock(&(timer->Lock), Irql);
365
366     /* call the user specified timer procedure */
367     timer->proc((long_ptr_t)timer->arg);
368 }
369
370 void cfs_init_timer(cfs_timer_t *timer)
371 {
372     memset(timer, 0, sizeof(cfs_timer_t));
373 }
374
375 /*
376  * cfs_timer_init
377  *   To initialize the cfs_timer_t
378  *
379  * Arguments:
380  *   timer:  the cfs_timer to be initialized
381  *   func:   the timer callback procedure
382  *   arg:    argument for the callback proc
383  *
384  * Return Value:
385  *   N/A
386  *
387  * Notes:
388  *   N/A
389  */
390
391 void cfs_timer_init(cfs_timer_t *timer, void (*func)(ulong_ptr_t), void *arg)
392 {
393     memset(timer, 0, sizeof(cfs_timer_t));
394
395     timer->proc = func;
396     timer->arg  = arg;
397
398     KeInitializeSpinLock(&(timer->Lock));
399     KeInitializeTimer(&timer->Timer);
400     KeInitializeDpc (&timer->Dpc, cfs_timer_dpc_proc, timer);
401
402     cfs_set_flag(timer->Flags, CFS_TIMER_FLAG_INITED);
403 }
404
405 /*
406  * cfs_timer_done
407  *   To finialize the cfs_timer_t (unused)
408  *
409  * Arguments:
410  *   timer:  the cfs_timer to be cleaned up
411  *
412  * Return Value:
413  *   N/A
414  *
415  * Notes:
416  *   N/A
417  */
418
419 void cfs_timer_done(cfs_timer_t *timer)
420 {
421     return;
422 }
423
424 /*
425  * cfs_timer_arm
426  *   To schedule the timer while touching @deadline
427  *
428  * Arguments:
429  *   timer:  the cfs_timer to be freed
430  *   dealine: timeout value to wake up the timer
431  *
432  * Return Value:
433  *   N/A
434  *
435  * Notes:
436  *   N/A
437  */
438
439 void cfs_timer_arm(cfs_timer_t *timer, cfs_time_t deadline)
440 {
441     LARGE_INTEGER   timeout;
442     KIRQL           Irql;
443
444     KeAcquireSpinLock(&(timer->Lock), &Irql);
445     if (!cfs_is_flag_set(timer->Flags, CFS_TIMER_FLAG_TIMERED)){
446
447         timeout.QuadPart = (LONGLONG)-1*1000*1000*10/CFS_HZ*deadline;
448
449         if (KeSetTimer(&timer->Timer, timeout, &timer->Dpc)) {
450             cfs_set_flag(timer->Flags, CFS_TIMER_FLAG_TIMERED);
451         }
452
453         timer->deadline = deadline;
454     }
455
456     KeReleaseSpinLock(&(timer->Lock), Irql);
457 }
458
459 /*
460  * cfs_timer_disarm
461  *   To discard the timer to be scheduled
462  *
463  * Arguments:
464  *   timer:  the cfs_timer to be discarded
465  *
466  * Return Value:
467  *   N/A
468  *
469  * Notes:
470  *   N/A
471  */
472
473 void cfs_timer_disarm(cfs_timer_t *timer)
474 {
475     KIRQL   Irql;
476
477     KeAcquireSpinLock(&(timer->Lock), &Irql);
478     KeCancelTimer(&(timer->Timer));
479     cfs_clear_flag(timer->Flags, CFS_TIMER_FLAG_TIMERED);
480     KeReleaseSpinLock(&(timer->Lock), Irql);
481 }
482
483
484 /*
485  * cfs_timer_is_armed
486  *   To check the timer is scheduled or not
487  *
488  * Arguments:
489  *   timer:  the cfs_timer to be checked
490  *
491  * Return Value:
492  *   1:  if it's armed.
493  *   0:  if it's not.
494  *
495  * Notes:
496  *   N/A
497  */
498
499 int cfs_timer_is_armed(cfs_timer_t *timer)
500 {
501     int     rc = 0;
502     KIRQL   Irql;
503
504     KeAcquireSpinLock(&(timer->Lock), &Irql);
505     if (cfs_is_flag_set(timer->Flags, CFS_TIMER_FLAG_TIMERED)) {
506         rc = 1;
507     }
508     KeReleaseSpinLock(&(timer->Lock), Irql);
509
510     return rc;
511 }
512
513 /*
514  * cfs_timer_deadline
515  *   To query the deadline of the timer
516  *
517  * Arguments:
518  *   timer:  the cfs_timer to be queried
519  *
520  * Return Value:
521  *   the deadline value
522  *
523  * Notes:
524  *   N/A
525  */
526
527 cfs_time_t cfs_timer_deadline(cfs_timer_t * timer)
528 {
529     return timer->deadline;
530 }
531
532 /*
533  * daemonize routine stub
534  */
535
536 void cfs_daemonize(char *str)
537 {
538     return;
539 }
540
541 int cfs_daemonize_ctxt(char *str) {
542     cfs_daemonize(str);
543     return 0;
544 }
545
546 /*
547  *  routine related with sigals
548  */
549
550 cfs_sigset_t cfs_block_allsigs()
551 {
552         return 0;
553 }
554
555 cfs_sigset_t cfs_block_sigs(sigset_t bit)
556 {
557         return 0;
558 }
559
560 /* Block all signals except for the @sigs. It's only used in
561  * Linux kernel, just a dummy here. */
562 cfs_sigset_t cfs_block_sigsinv(unsigned long sigs)
563 {
564         return 0;
565 }
566
567 void cfs_restore_sigs(cfs_sigset_t old)
568 {
569 }
570
571 int cfs_signal_pending(void)
572 {
573     return 0;
574 }
575
576 void cfs_clear_sigpending(void)
577 {
578     return;
579 }
580
581 /*
582  *  thread cpu affinity routines
583  */
584
585 typedef struct _THREAD_BASIC_INFORMATION {
586     NTSTATUS ExitStatus;
587     PVOID TebBaseAddress;
588     CLIENT_ID ClientId;
589     ULONG_PTR AffinityMask;
590     KPRIORITY Priority;
591     LONG BasePriority;
592 } THREAD_BASIC_INFORMATION;
593
594 typedef THREAD_BASIC_INFORMATION *PTHREAD_BASIC_INFORMATION;
595
596 #define THREAD_QUERY_INFORMATION       (0x0040)
597
598 NTSYSAPI
599 NTSTATUS
600 NTAPI
601 ZwOpenThread (
602     __out PHANDLE ThreadHandle,
603     __in ACCESS_MASK DesiredAccess,
604     __in POBJECT_ATTRIBUTES ObjectAttributes,
605     __in_opt PCLIENT_ID ClientId
606     );
607
608 NTSYSAPI
609 NTSTATUS
610 NTAPI
611 ZwQueryInformationThread (
612     __in HANDLE ThreadHandle,
613     __in THREADINFOCLASS ThreadInformationClass,
614     __out_bcount(ThreadInformationLength) PVOID ThreadInformation,
615     __in ULONG ThreadInformationLength,
616     __out_opt PULONG ReturnLength
617     );
618
619 NTSYSAPI
620 NTSTATUS
621 NTAPI
622 ZwSetInformationThread (
623     __in HANDLE ThreadHandle,
624     __in THREADINFOCLASS ThreadInformationClass,
625     __in_bcount(ThreadInformationLength) PVOID ThreadInformation,
626     __in ULONG ThreadInformationLength
627     );
628
629 HANDLE
630 cfs_open_current_thread()
631 {
632     NTSTATUS         status;
633     HANDLE           handle = NULL;
634     OBJECT_ATTRIBUTES oa;
635     CLIENT_ID        cid;
636
637     /* initialize object attributes */
638     InitializeObjectAttributes( &oa, NULL, OBJ_KERNEL_HANDLE |
639                                 OBJ_CASE_INSENSITIVE, NULL, NULL);
640
641     /* initialize client id */
642     cid.UniqueProcess = PsGetCurrentProcessId();
643     cid.UniqueThread  = PsGetCurrentThreadId();
644
645     /* get thread handle */
646     status = ZwOpenThread( &handle, THREAD_QUERY_INFORMATION |
647                            THREAD_SET_INFORMATION, &oa, &cid);
648     if (!NT_SUCCESS(status)) {
649         handle = NULL;
650     }
651
652     return handle;
653 }
654
655 void
656 cfs_close_thread_handle(HANDLE handle)
657 {
658     if (handle)
659         ZwClose(handle);
660 }
661
662 KAFFINITY
663 cfs_query_thread_affinity()
664 {
665     NTSTATUS         status;
666     HANDLE           handle = NULL;
667     DWORD            size;
668     THREAD_BASIC_INFORMATION TBI = {0};
669
670     /* open current thread */
671     handle = cfs_open_current_thread();
672     if (!handle) {
673         goto errorout;
674     }
675
676     /* query thread cpu affinity */
677     status = ZwQueryInformationThread(handle, ThreadBasicInformation,
678                        &TBI, sizeof(THREAD_BASIC_INFORMATION), &size);
679     if (!NT_SUCCESS(status)) {
680         goto errorout;
681     }
682
683 errorout:
684
685     cfs_close_thread_handle(handle);
686     return TBI.AffinityMask;
687 }
688
689 int
690 cfs_set_thread_affinity(KAFFINITY affinity)
691 {
692     NTSTATUS         status;
693     HANDLE           handle = NULL;
694
695     /* open current thread */
696     handle = cfs_open_current_thread();
697     if (!handle) {
698         goto errorout;
699     }
700
701     /* set thread cpu affinity */
702     status = ZwSetInformationThread(handle, ThreadAffinityMask,
703                                     &affinity, sizeof(KAFFINITY));
704     if (!NT_SUCCESS(status)) {
705         goto errorout;
706     }
707
708 errorout:
709
710     cfs_close_thread_handle(handle);
711     return NT_SUCCESS(status);
712 }
713
714 int
715 cfs_tie_thread_to_cpu(int cpu)
716 {
717     return cfs_set_thread_affinity((KAFFINITY) (1 << cpu));
718 }
719
720 int
721 cfs_set_thread_priority(KPRIORITY priority)
722 {
723     NTSTATUS         status;
724     HANDLE           handle = NULL;
725
726     /* open current thread */
727     handle = cfs_open_current_thread();
728     if (!handle) {
729         goto errorout;
730     }
731
732     /* set thread cpu affinity */
733     status = ZwSetInformationThread(handle, ThreadPriority,
734                                     &priority, sizeof(KPRIORITY));
735     if (!NT_SUCCESS(status)) {
736         KdPrint(("set_thread_priority failed: %xh\n", status));
737         goto errorout;
738     }
739
740 errorout:
741
742     cfs_close_thread_handle(handle);
743     return NT_SUCCESS(status);
744 }
745
746 int cfs_need_resched(void)
747 {
748         return 0;
749 }
750
751 void cfs_cond_resched(void)
752 {
753 }
754
755 /**
756  **  Initialize routines
757  **/
758
759 void cfs_libc_init();
760
761 int
762 libcfs_arch_init(void)
763 {
764         int             rc;
765         spinlock_t      lock;
766
767         /* Workground to check the system is MP build or UP build */
768         spin_lock_init(&lock);
769         spin_lock(&lock);
770         libcfs_is_mp_system = (int)lock.lock;
771         /* MP build system: it's a real spin, for UP build system, it
772          * only raises the IRQL to DISPATCH_LEVEL */
773         spin_unlock(&lock);
774
775     /* initialize libc routines (confliction between libcnptr.lib
776        and kernel ntoskrnl.lib) */
777     cfs_libc_init();
778
779     /* create slab memory caches for page alloctors */
780     cfs_page_t_slab = cfs_mem_cache_create(
781         "CPGT", sizeof(cfs_page_t), 0, 0 );
782
783     cfs_page_p_slab = cfs_mem_cache_create(
784         "CPGP", CFS_PAGE_SIZE, 0, 0 );
785
786     if ( cfs_page_t_slab == NULL ||
787          cfs_page_p_slab == NULL ){
788         rc = -ENOMEM;
789         goto errorout;
790     }
791
792     rc = init_task_manager();
793     if (rc != 0) {
794         cfs_enter_debugger();
795         KdPrint(("winnt-prim.c:libcfs_arch_init: error initializing task manager ...\n"));
796         goto errorout;
797     }
798
799     /* initialize the proc file system */
800     rc = proc_init_fs();
801     if (rc != 0) {
802         cfs_enter_debugger();
803         KdPrint(("winnt-prim.c:libcfs_arch_init: error initializing proc fs ...\n"));
804         cleanup_task_manager();
805         goto errorout;
806     }
807
808     /* initialize the tdi data */
809     rc = ks_init_tdi_data();
810     if (rc != 0) {
811         cfs_enter_debugger();
812         KdPrint(("winnt-prim.c:libcfs_arch_init: failed to initialize tdi.\n"));
813         proc_destroy_fs();
814         cleanup_task_manager();
815         goto errorout;
816     }
817
818     rc = start_shrinker_timer();
819
820 errorout:
821
822     if (rc != 0) {
823         /* destroy the taskslot cache slab */
824         if (cfs_page_t_slab) {
825             cfs_mem_cache_destroy(cfs_page_t_slab);
826         }
827         if (cfs_page_p_slab) {
828             cfs_mem_cache_destroy(cfs_page_p_slab);
829         }
830     }
831
832     return rc;
833 }
834
835 void
836 libcfs_arch_cleanup(void)
837 {
838     /* stop shrinker timer */
839     stop_shrinker_timer();
840
841     /* finialize the tdi data */
842     ks_fini_tdi_data();
843
844     /* detroy the whole proc fs tree and nodes */
845     proc_destroy_fs();
846
847     /* cleanup context of task manager */
848     cleanup_task_manager();
849
850     /* destroy the taskslot cache slab */
851     if (cfs_page_t_slab) {
852         cfs_mem_cache_destroy(cfs_page_t_slab);
853     }
854
855     if (cfs_page_p_slab) {
856         cfs_mem_cache_destroy(cfs_page_p_slab);
857     }
858
859     return;
860 }
861
862 EXPORT_SYMBOL(libcfs_arch_init);
863 EXPORT_SYMBOL(libcfs_arch_cleanup);