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