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