f7ec4d81e1ab9cf557b18fc5a621ec5a16817e9c
[openafs.git] / src / afs / afs_osi_gcpags.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include "afs/param.h"
12
13
14 #include "afs/sysincludes.h"    /* Standard vendor system headers */
15 #include "afsincludes.h"        /* Afs-based standard headers */
16 #include "afs/afs_stats.h"      /* afs statistics */
17 #ifdef AFS_AIX_ENV
18 #include <sys/adspace.h>        /* for vm_att(), vm_det() */
19 #endif
20
21 #if AFS_GCPAGS
22
23 /* afs_osi_TraverseProcTable() - Walk through the systems process
24  * table, calling afs_GCPAGs_perproc_func() for each process.
25  */
26
27 #if defined(AFS_SUN5_ENV)
28 void
29 afs_osi_TraverseProcTable(void)
30 {
31     struct proc *prp;
32     for (prp = practive; prp != NULL; prp = prp->p_next) {
33         afs_GCPAGs_perproc_func(prp);
34     }
35 }
36 #endif
37
38 #if defined(AFS_HPUX_ENV)
39
40 /*
41  * NOTE: h/proc_private.h gives the process table locking rules
42  * It indicates that access to p_cred must be protected by
43  * mp_mtproc_lock(p);
44  * mp_mtproc_unlock(p);
45  *
46  * The code in sys/pm_prot.c uses pcred_lock() to protect access to
47  * the process creds, and uses mp_mtproc_lock() only for audit-related
48  * changes.  To be safe, we use both.
49  */
50
51 void
52 afs_osi_TraverseProcTable(void)
53 {
54     register proc_t *p;
55     int endchain = 0;
56
57     MP_SPINLOCK(activeproc_lock);
58     MP_SPINLOCK(sched_lock);
59     pcred_lock();
60
61     /*
62      * Instead of iterating through all of proc[], traverse only
63      * the list of active processes.  As an example of this,
64      * see foreach_process() in sys/vm_sched.c.
65      *
66      * We hold the locks for the entire scan in order to get a
67      * consistent view of the current set of creds.
68      */
69
70     for (p = proc; endchain == 0; p = &proc[p->p_fandx]) {
71         if (p->p_fandx == 0) {
72             endchain = 1;
73         }
74
75         if (system_proc(p))
76             continue;
77
78         mp_mtproc_lock(p);
79         afs_GCPAGs_perproc_func(p);
80         mp_mtproc_unlock(p);
81     }
82
83     pcred_unlock();
84     MP_SPINUNLOCK(sched_lock);
85     MP_SPINUNLOCK(activeproc_lock);
86 }
87 #endif
88
89 #if defined(AFS_SGI_ENV)
90
91 #ifdef AFS_SGI65_ENV
92 /* TODO: Fix this later. */
93 static int
94 SGI_ProcScanFunc(void *p, void *arg, int mode)
95 {
96     return 0;
97 }
98 #else /* AFS_SGI65_ENV */
99 static int
100 SGI_ProcScanFunc(proc_t * p, void *arg, int mode)
101 {
102     afs_int32(*perproc_func) (struct proc *) = arg;
103     int code = 0;
104     /* we pass in the function pointer for arg,
105      * mode ==0 for startup call, ==1 for each valid proc,
106      * and ==2 for terminate call.
107      */
108     if (mode == 1) {
109         code = perproc_func(p);
110     }
111     return code;
112 }
113 #endif /* AFS_SGI65_ENV */
114
115 void
116 afs_osi_TraverseProcTable(void)
117 {
118     procscan(SGI_ProcScanFunc, afs_GCPAGs_perproc_func);
119 }
120 #endif /* AFS_SGI_ENV */
121
122 #if defined(AFS_AIX_ENV)
123 #ifdef AFS_AIX51_ENV
124 #define max_proc v.ve_proc
125 #endif
126 void
127 afs_osi_TraverseProcTable(void)
128 {
129     struct proc *p;
130     int i;
131
132     /*
133      * For binary compatibility, on AIX we need to be careful to use the
134      * proper size of a struct proc, even if it is different from what
135      * we were compiled with.
136      */
137     if (!afs_gcpags_procsize)
138         return;
139
140 #ifndef AFS_AIX51_ENV
141     simple_lock(&proc_tbl_lock);
142 #endif
143     for (p = (struct proc *)v.vb_proc, i = 0; p < max_proc;
144          p = (struct proc *)((char *)p + afs_gcpags_procsize), i++) {
145
146 #ifdef AFS_AIX51_ENV
147         if (p->p_pvprocp->pv_stat == SNONE)
148             continue;
149         if (p->p_pvprocp->pv_stat == SIDL)
150             continue;
151         if (p->p_pvprocp->pv_stat == SEXIT)
152             continue;
153 #else
154         if (p->p_stat == SNONE)
155             continue;
156         if (p->p_stat == SIDL)
157             continue;
158         if (p->p_stat == SEXIT)
159             continue;
160 #endif
161
162         /* sanity check */
163
164         if (PROCMASK(p->p_pid) != i) {
165             afs_gcpags = AFS_GCPAGS_EPIDCHECK;
166             break;
167         }
168
169         /* sanity check */
170
171         if ((p->p_nice < P_NICE_MIN) || (P_NICE_MAX < p->p_nice)) {
172             afs_gcpags = AFS_GCPAGS_ENICECHECK;
173             break;
174         }
175
176         afs_GCPAGs_perproc_func(p);
177     }
178 #ifndef AFS_AIX51_ENV
179     simple_unlock(&proc_tbl_lock);
180 #endif
181 }
182 #endif
183
184 #if defined(AFS_OSF_ENV)
185
186 #ifdef AFS_DUX50_ENV
187 extern struct pid_entry *pidtab;
188 extern int npid; 
189 #endif
190
191 void
192 afs_osi_TraverseProcTable(void)
193 {
194     struct pid_entry *pe;
195 #ifdef AFS_DUX50_ENV
196 #define pidNPID (pidtab + npid)
197 #define PID_LOCK()
198 #define PID_UNLOCK()
199 #endif
200     PID_LOCK();
201     for (pe = pidtab; pe < pidNPID; ++pe) {
202         if (pe->pe_proc != PROC_NULL)
203             afs_GCPAGs_perproc_func(pe->pe_proc);
204     }
205     PID_UNLOCK();
206 }
207 #endif
208
209 #if (defined(AFS_DARWIN_ENV) && !defined(AFS_DARWIN80_ENV)) || defined(AFS_FBSD_ENV)
210 void
211 afs_osi_TraverseProcTable(void)
212 {
213     struct proc *p;
214     LIST_FOREACH(p, &allproc, p_list) {
215         if (p->p_stat == SIDL)
216             continue;
217         if (p->p_stat == SZOMB)
218             continue;
219         if (p->p_flag & P_SYSTEM)
220             continue;
221         afs_GCPAGs_perproc_func(p);
222     }
223 }
224 #endif
225
226 #if defined(AFS_LINUX22_ENV)
227 #ifdef EXPORTED_TASKLIST_LOCK
228 extern rwlock_t tasklist_lock __attribute__((weak));
229 #endif
230 void
231 afs_osi_TraverseProcTable()
232 {
233 #if !defined(LINUX_KEYRING_SUPPORT) && (!defined(STRUCT_TASK_HAS_CRED) || defined(EXPORTED_RCU_READ_LOCK))
234     struct task_struct *p;
235
236 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) && defined(EXPORTED_TASKLIST_LOCK)
237     if (&tasklist_lock)
238         read_lock(&tasklist_lock);
239 #endif /* EXPORTED_TASKLIST_LOCK */
240 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) 
241 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) && defined(EXPORTED_TASKLIST_LOCK)
242     else
243 #endif /* EXPORTED_TASKLIST_LOCK && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) */
244         rcu_read_lock();
245 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) */
246     
247 #ifdef DEFINED_FOR_EACH_PROCESS
248     for_each_process(p) if (p->pid) {
249 #ifdef STRUCT_TASK_STRUCT_HAS_EXIT_STATE
250         if (p->exit_state)
251             continue;
252 #else
253         if (p->state & TASK_ZOMBIE)
254             continue;
255 #endif
256         afs_GCPAGs_perproc_func(p);
257     }
258 #else
259     for_each_task(p) if (p->pid) {
260 #ifdef STRUCT_TASK_STRUCT_HAS_EXIT_STATE
261         if (p->exit_state)
262             continue;
263 #else
264         if (p->state & TASK_ZOMBIE)
265             continue;
266 #endif
267         afs_GCPAGs_perproc_func(p);
268     }
269 #endif
270 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) && defined(EXPORTED_TASKLIST_LOCK)
271     if (&tasklist_lock)
272         read_unlock(&tasklist_lock);
273 #endif /* EXPORTED_TASKLIST_LOCK */
274 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) 
275 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) && defined(EXPORTED_TASKLIST_LOCK)
276     else
277 #endif /* EXPORTED_TASKLIST_LOCK && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) */
278         rcu_read_unlock();
279 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) */
280 #endif
281 }
282 #endif
283
284 /* return a pointer (sometimes a static copy ) to the cred for a
285  * given AFS_PROC.
286  * subsequent calls may overwrite the previously returned value.
287  */
288
289 #if defined(AFS_SGI65_ENV)
290 const AFS_UCRED *
291 afs_osi_proc2cred(AFS_PROC * p)
292 {
293     return NULL;
294 }
295 #elif defined(AFS_HPUX_ENV)
296 const AFS_UCRED *
297 afs_osi_proc2cred(AFS_PROC * p)
298 {
299     if (!p)
300         return;
301
302     /*
303      * Cannot use afs_warnuser() here, as the code path
304      * eventually wants to grab sched_lock, which is
305      * already held here
306      */
307
308     return p_cred(p);
309 }
310 #elif defined(AFS_AIX_ENV)
311
312 /* GLOBAL DECLARATIONS */
313
314 /*
315  * LOCKS: the caller must do
316  *  simple_lock(&proc_tbl_lock);
317  *  simple_unlock(&proc_tbl_lock);
318  * around calls to this function.
319  */
320
321 const AFS_UCRED *
322 afs_osi_proc2cred(AFS_PROC * pproc)
323 {
324     AFS_UCRED *pcred = 0;
325
326     /*
327      * pointer to process user structure valid in *our*
328      * address space
329      *
330      * The user structure for a process is stored in the user
331      * address space (as distinct from the kernel address
332      * space), and so to refer to the user structure of a
333      * different process we must employ special measures.
334      *
335      * I followed the example used in the AIX getproc() system
336      * call in bos/kernel/proc/getproc.c
337      */
338     struct user *xmem_userp;
339
340     struct xmem dp;             /* ptr to xmem descriptor */
341     int xm;                     /* xmem result */
342
343     if (!pproc) {
344         return pcred;
345     }
346
347     /*
348      * The process private segment in which the user
349      * area is located may disappear. We need to increment
350      * its use count. Therefore we
351      *    - get the proc_tbl_lock to hold the segment.
352      *    - get the p_lock to lockout vm_cleardata.
353      *    - vm_att to load the segment register (no check)
354      *    - xmattach to bump its use count.
355      *    - release the p_lock.
356      *    - release the proc_tbl_lock.
357      *    - do whatever we need.
358      *    - xmdetach to decrement the use count.
359      *    - vm_det to free the segment register (no check)
360      */
361
362     xmem_userp = NULL;
363     xm = XMEM_FAIL;
364     /* simple_lock(&proc_tbl_lock); */
365 #ifdef __64BIT__
366     if (pproc->p_adspace != vm_handle(NULLSEGID, (int32long64_t) 0)) {
367 #else
368     if (pproc->p_adspace != NULLSEGVAL) {
369 #endif
370
371 #ifdef AFS_AIX51_ENV
372         simple_lock(&pproc->p_pvprocp->pv_lock);
373 #else
374         simple_lock(&pproc->p_lock);
375 #endif
376
377         if (pproc->p_threadcount &&
378 #ifdef AFS_AIX51_ENV
379             pproc->p_pvprocp->pv_threadlist) {
380 #else
381             pproc->p_threadlist) {
382 #endif
383
384             /*
385              * arbitrarily pick the first thread in pproc
386              */
387             struct thread *pproc_thread =
388 #ifdef AFS_AIX51_ENV
389                 pproc->p_pvprocp->pv_threadlist;
390 #else
391                 pproc->p_threadlist;
392 #endif
393
394             /*
395              * location of 'struct user' in pproc's
396              * address space
397              */
398             struct user *pproc_userp = pproc_thread->t_userp;
399
400             /*
401              * create a pointer valid in my own address space
402              */
403
404             xmem_userp = (struct user *)vm_att(pproc->p_adspace, pproc_userp);
405
406             dp.aspace_id = XMEM_INVAL;
407             xm = xmattach(xmem_userp, sizeof(*xmem_userp), &dp, SYS_ADSPACE);
408         }
409
410 #ifdef AFS_AIX51_ENV
411         simple_unlock(&pproc->p_pvprocp->pv_lock);
412 #else
413         simple_unlock(&pproc->p_lock);
414 #endif
415     }
416     /* simple_unlock(&proc_tbl_lock); */
417     if (xm == XMEM_SUCC) {
418
419         static AFS_UCRED cred;
420
421         /*
422          * What locking should we use to protect access to the user
423          * area?  If needed also change the code in AIX/osi_groups.c.
424          */
425
426         /* copy cred to local address space */
427         cred = *xmem_userp->U_cred;
428         pcred = &cred;
429
430         xmdetach(&dp);
431     }
432     if (xmem_userp) {
433         vm_det((void *)xmem_userp);
434     }
435
436     return pcred;
437 }
438
439 #elif defined(AFS_OSF_ENV)
440 const AFS_UCRED *
441 afs_osi_proc2cred(AFS_PROC * pr)
442 {
443     AFS_UCRED *rv = NULL;
444
445     if (pr == NULL) {
446         return NULL;
447     }
448
449     if ((pr->p_stat == SSLEEP) || (pr->p_stat == SRUN)
450         || (pr->p_stat == SSTOP))
451         rv = pr->p_rcred;
452
453     return rv;
454 }
455 #elif defined(AFS_DARWIN80_ENV) 
456 const AFS_UCRED *
457 afs_osi_proc2cred(AFS_PROC * pr)
458 {
459     AFS_UCRED *rv = NULL;
460     static AFS_UCRED cr;
461     struct ucred *pcred;
462
463     if (pr == NULL) {
464         return NULL;
465     }
466     pcred = proc_ucred(pr);
467     cr.cr_ref = 1;
468     cr.cr_uid = pcred->cr_uid;
469     cr.cr_ngroups = pcred->cr_ngroups;
470     memcpy(cr.cr_groups, pcred->cr_groups,
471            NGROUPS * sizeof(gid_t));
472     return &cr;
473 }
474 #elif defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
475 const AFS_UCRED *
476 afs_osi_proc2cred(AFS_PROC * pr)
477 {
478     AFS_UCRED *rv = NULL;
479     static AFS_UCRED cr;
480
481     if (pr == NULL) {
482         return NULL;
483     }
484
485     if ((pr->p_stat == SSLEEP) || (pr->p_stat == SRUN)
486         || (pr->p_stat == SSTOP)) {
487         pcred_readlock(pr);
488         cr.cr_ref = 1;
489         cr.cr_uid = pr->p_cred->pc_ucred->cr_uid;
490         cr.cr_ngroups = pr->p_cred->pc_ucred->cr_ngroups;
491         memcpy(cr.cr_groups, pr->p_cred->pc_ucred->cr_groups,
492                NGROUPS * sizeof(gid_t));
493         pcred_unlock(pr);
494         rv = &cr;
495     }
496
497     return rv;
498 }
499 #elif defined(AFS_LINUX22_ENV)
500 #if !defined(LINUX_KEYRING_SUPPORT) && (!defined(STRUCT_TASK_HAS_CRED) || defined(EXPORTED_RCU_READ_LOCK))
501 const AFS_UCRED *
502 afs_osi_proc2cred(AFS_PROC * pr)
503 {
504     AFS_UCRED *rv = NULL;
505     static AFS_UCRED cr;
506
507     if (pr == NULL) {
508         return NULL;
509     }
510
511     if ((pr->state == TASK_RUNNING) || (pr->state == TASK_INTERRUPTIBLE)
512         || (pr->state == TASK_UNINTERRUPTIBLE)
513         || (pr->state == TASK_STOPPED)) {
514         cr.cr_ref = 1;
515         cr.cr_uid = task_uid(pr);
516 #if defined(AFS_LINUX26_ENV)
517 #if defined(STRUCT_TASK_HAS_CRED)
518         get_group_info(pr->cred->group_info);
519         cr.cr_group_info = pr->cred->group_info;
520 #else
521         get_group_info(pr->group_info);
522         cr.cr_group_info = pr->group_info;
523 #endif
524 #else
525         cr.cr_ngroups = pr->ngroups;
526         memcpy(cr.cr_groups, pr->groups, NGROUPS * sizeof(gid_t));
527 #endif
528         rv = &cr;
529     }
530
531     return rv;
532 }
533 #endif
534 #else
535 const AFS_UCRED *
536 afs_osi_proc2cred(AFS_PROC * pr)
537 {
538     AFS_UCRED *rv = NULL;
539
540     if (pr == NULL) {
541         return NULL;
542     }
543     rv = pr->p_cred;
544
545     return rv;
546 }
547 #endif
548
549 #endif /* AFS_GCPAGS */