Whamcloud - gitweb
1d04567b20aeed650632c6e4d485395b3a3c1c3b
[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  * kthread_run
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  *   name:  thread name to create
92  *
93  * Return Value:
94  *   cfs_task_t:   0 on success or error codes
95  *
96  * Notes:
97  *   N/A
98  */
99
100 cfs_task_t kthread_run(int (*func)(void *), void *arg, char *name)
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 ERR_PTR(-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 ERR_PTR(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 (cfs_task_t)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 int unshare_fs_struct()
533 {
534         return 0;
535 }
536
537 /*
538  *  routine related with sigals
539  */
540
541 cfs_sigset_t cfs_block_allsigs()
542 {
543         return 0;
544 }
545
546 cfs_sigset_t cfs_block_sigs(sigset_t bit)
547 {
548         return 0;
549 }
550
551 /* Block all signals except for the @sigs. It's only used in
552  * Linux kernel, just a dummy here. */
553 cfs_sigset_t cfs_block_sigsinv(unsigned long sigs)
554 {
555         return 0;
556 }
557
558 void cfs_restore_sigs(cfs_sigset_t old)
559 {
560 }
561
562 int cfs_signal_pending(void)
563 {
564     return 0;
565 }
566
567 void cfs_clear_sigpending(void)
568 {
569     return;
570 }
571
572 /*
573  *  thread cpu affinity routines
574  */
575
576 typedef struct _THREAD_BASIC_INFORMATION {
577     NTSTATUS ExitStatus;
578     PVOID TebBaseAddress;
579     CLIENT_ID ClientId;
580     ULONG_PTR AffinityMask;
581     KPRIORITY Priority;
582     LONG BasePriority;
583 } THREAD_BASIC_INFORMATION;
584
585 typedef THREAD_BASIC_INFORMATION *PTHREAD_BASIC_INFORMATION;
586
587 #define THREAD_QUERY_INFORMATION       (0x0040)
588
589 NTSYSAPI
590 NTSTATUS
591 NTAPI
592 ZwOpenThread (
593     __out PHANDLE ThreadHandle,
594     __in ACCESS_MASK DesiredAccess,
595     __in POBJECT_ATTRIBUTES ObjectAttributes,
596     __in_opt PCLIENT_ID ClientId
597     );
598
599 NTSYSAPI
600 NTSTATUS
601 NTAPI
602 ZwQueryInformationThread (
603     __in HANDLE ThreadHandle,
604     __in THREADINFOCLASS ThreadInformationClass,
605     __out_bcount(ThreadInformationLength) PVOID ThreadInformation,
606     __in ULONG ThreadInformationLength,
607     __out_opt PULONG ReturnLength
608     );
609
610 NTSYSAPI
611 NTSTATUS
612 NTAPI
613 ZwSetInformationThread (
614     __in HANDLE ThreadHandle,
615     __in THREADINFOCLASS ThreadInformationClass,
616     __in_bcount(ThreadInformationLength) PVOID ThreadInformation,
617     __in ULONG ThreadInformationLength
618     );
619
620 HANDLE
621 cfs_open_current_thread()
622 {
623     NTSTATUS         status;
624     HANDLE           handle = NULL;
625     OBJECT_ATTRIBUTES oa;
626     CLIENT_ID        cid;
627
628     /* initialize object attributes */
629     InitializeObjectAttributes( &oa, NULL, OBJ_KERNEL_HANDLE |
630                                 OBJ_CASE_INSENSITIVE, NULL, NULL);
631
632     /* initialize client id */
633     cid.UniqueProcess = PsGetCurrentProcessId();
634     cid.UniqueThread  = PsGetCurrentThreadId();
635
636     /* get thread handle */
637     status = ZwOpenThread( &handle, THREAD_QUERY_INFORMATION |
638                            THREAD_SET_INFORMATION, &oa, &cid);
639     if (!NT_SUCCESS(status)) {
640         handle = NULL;
641     }
642
643     return handle;
644 }
645
646 void
647 cfs_close_thread_handle(HANDLE handle)
648 {
649     if (handle)
650         ZwClose(handle);
651 }
652
653 KAFFINITY
654 cfs_query_thread_affinity()
655 {
656     NTSTATUS         status;
657     HANDLE           handle = NULL;
658     DWORD            size;
659     THREAD_BASIC_INFORMATION TBI = {0};
660
661     /* open current thread */
662     handle = cfs_open_current_thread();
663     if (!handle) {
664         goto errorout;
665     }
666
667     /* query thread cpu affinity */
668     status = ZwQueryInformationThread(handle, ThreadBasicInformation,
669                        &TBI, sizeof(THREAD_BASIC_INFORMATION), &size);
670     if (!NT_SUCCESS(status)) {
671         goto errorout;
672     }
673
674 errorout:
675
676     cfs_close_thread_handle(handle);
677     return TBI.AffinityMask;
678 }
679
680 int
681 cfs_set_thread_affinity(KAFFINITY affinity)
682 {
683     NTSTATUS         status;
684     HANDLE           handle = NULL;
685
686     /* open current thread */
687     handle = cfs_open_current_thread();
688     if (!handle) {
689         goto errorout;
690     }
691
692     /* set thread cpu affinity */
693     status = ZwSetInformationThread(handle, ThreadAffinityMask,
694                                     &affinity, sizeof(KAFFINITY));
695     if (!NT_SUCCESS(status)) {
696         goto errorout;
697     }
698
699 errorout:
700
701     cfs_close_thread_handle(handle);
702     return NT_SUCCESS(status);
703 }
704
705 int
706 cfs_tie_thread_to_cpu(int cpu)
707 {
708     return cfs_set_thread_affinity((KAFFINITY) (1 << cpu));
709 }
710
711 int
712 cfs_set_thread_priority(KPRIORITY priority)
713 {
714     NTSTATUS         status;
715     HANDLE           handle = NULL;
716
717     /* open current thread */
718     handle = cfs_open_current_thread();
719     if (!handle) {
720         goto errorout;
721     }
722
723     /* set thread cpu affinity */
724     status = ZwSetInformationThread(handle, ThreadPriority,
725                                     &priority, sizeof(KPRIORITY));
726     if (!NT_SUCCESS(status)) {
727         KdPrint(("set_thread_priority failed: %xh\n", status));
728         goto errorout;
729     }
730
731 errorout:
732
733     cfs_close_thread_handle(handle);
734     return NT_SUCCESS(status);
735 }
736
737 int cfs_need_resched(void)
738 {
739         return 0;
740 }
741
742 void cfs_cond_resched(void)
743 {
744 }
745
746 /**
747  **  Initialize routines
748  **/
749
750 void cfs_libc_init();
751
752 int
753 libcfs_arch_init(void)
754 {
755         int             rc;
756         spinlock_t      lock;
757
758         /* Workground to check the system is MP build or UP build */
759         spin_lock_init(&lock);
760         spin_lock(&lock);
761         libcfs_is_mp_system = (int)lock.lock;
762         /* MP build system: it's a real spin, for UP build system, it
763          * only raises the IRQL to DISPATCH_LEVEL */
764         spin_unlock(&lock);
765
766     /* initialize libc routines (confliction between libcnptr.lib
767        and kernel ntoskrnl.lib) */
768     cfs_libc_init();
769
770     /* create slab memory caches for page alloctors */
771     cfs_page_t_slab = cfs_mem_cache_create(
772         "CPGT", sizeof(cfs_page_t), 0, 0 );
773
774     cfs_page_p_slab = cfs_mem_cache_create(
775         "CPGP", CFS_PAGE_SIZE, 0, 0 );
776
777     if ( cfs_page_t_slab == NULL ||
778          cfs_page_p_slab == NULL ){
779         rc = -ENOMEM;
780         goto errorout;
781     }
782
783     rc = init_task_manager();
784     if (rc != 0) {
785         cfs_enter_debugger();
786         KdPrint(("winnt-prim.c:libcfs_arch_init: error initializing task manager ...\n"));
787         goto errorout;
788     }
789
790     /* initialize the proc file system */
791     rc = proc_init_fs();
792     if (rc != 0) {
793         cfs_enter_debugger();
794         KdPrint(("winnt-prim.c:libcfs_arch_init: error initializing proc fs ...\n"));
795         cleanup_task_manager();
796         goto errorout;
797     }
798
799     /* initialize the tdi data */
800     rc = ks_init_tdi_data();
801     if (rc != 0) {
802         cfs_enter_debugger();
803         KdPrint(("winnt-prim.c:libcfs_arch_init: failed to initialize tdi.\n"));
804         proc_destroy_fs();
805         cleanup_task_manager();
806         goto errorout;
807     }
808
809     rc = start_shrinker_timer();
810
811 errorout:
812
813     if (rc != 0) {
814         /* destroy the taskslot cache slab */
815         if (cfs_page_t_slab) {
816             cfs_mem_cache_destroy(cfs_page_t_slab);
817         }
818         if (cfs_page_p_slab) {
819             cfs_mem_cache_destroy(cfs_page_p_slab);
820         }
821     }
822
823     return rc;
824 }
825
826 void
827 libcfs_arch_cleanup(void)
828 {
829     /* stop shrinker timer */
830     stop_shrinker_timer();
831
832     /* finialize the tdi data */
833     ks_fini_tdi_data();
834
835     /* detroy the whole proc fs tree and nodes */
836     proc_destroy_fs();
837
838     /* cleanup context of task manager */
839     cleanup_task_manager();
840
841     /* destroy the taskslot cache slab */
842     if (cfs_page_t_slab) {
843         cfs_mem_cache_destroy(cfs_page_t_slab);
844     }
845
846     if (cfs_page_p_slab) {
847         cfs_mem_cache_destroy(cfs_page_p_slab);
848     }
849
850     return;
851 }
852
853 EXPORT_SYMBOL(libcfs_arch_init);
854 EXPORT_SYMBOL(libcfs_arch_cleanup);