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