linux-mutex-changes-20060812
[openafs.git] / src / afs / LINUX / osi_cred.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 /*
11  * osi_cred.c - Linux cred handling routines.
12  *
13  */
14 #include <afsconfig.h>
15 #include "afs/param.h"
16
17 RCSID
18     ("$Header$");
19
20 #include "afs/sysincludes.h"
21 #include "afsincludes.h"
22
23 /* Setup a pool for creds. Allocate several at a time. */
24 #define CRED_ALLOC_STEP 29      /* at 140 bytes/cred = 4060 bytes. */
25
26
27 static cred_t *cred_pool = NULL;
28 int cred_allocs = 0;
29 int ncreds_inuse = 0;
30
31 /* Cred locking assumes current single threaded non-preemptive kernel.
32  * Also assuming a fast path through both down and up if no waiters. Otherwise,
33  * test if no creds in pool before grabbing lock in crfree().
34  */
35 #if defined(AFS_LINUX24_ENV)
36 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
37 static DEFINE_MUTEX(linux_cred_pool_lock);
38 #else
39 static DECLARE_MUTEX(linux_cred_pool_lock);
40 #endif
41 #else
42 static struct semaphore linux_cred_pool_lock = MUTEX;
43 #endif
44 #define CRED_LOCK() down(&linux_cred_pool_lock)
45 #define CRED_UNLOCK() up(&linux_cred_pool_lock)
46
47 cred_t *
48 crget(void)
49 {
50     cred_t *tmp;
51     int i;
52
53     CRED_LOCK();
54     if (!cred_pool) {
55         cred_allocs++;
56         cred_pool = (cred_t *) osi_Alloc(CRED_ALLOC_STEP * sizeof(cred_t));
57         if (!cred_pool)
58             osi_Panic("crget: No more memory for creds!\n");
59
60         for (i = 0; i < CRED_ALLOC_STEP - 1; i++)
61             cred_pool[i].cr_next = (cred_t *) &cred_pool[i + 1];
62         cred_pool[i].cr_next = NULL;
63     }
64     tmp = cred_pool;
65     cred_pool = (cred_t *) tmp->cr_next;
66     ncreds_inuse++;
67     CRED_UNLOCK();
68
69     memset(tmp, 0, sizeof(cred_t));
70     tmp->cr_ref = 1;
71     return tmp;
72 }
73
74 void
75 crfree(cred_t * cr)
76 {
77     if (cr->cr_ref > 1) {
78         cr->cr_ref--;
79         return;
80     }
81
82 #if defined(AFS_LINUX26_ENV)
83     put_group_info(cr->cr_group_info);
84 #endif
85     CRED_LOCK();
86     cr->cr_next = (cred_t *) cred_pool;
87     cred_pool = cr;
88     CRED_UNLOCK();
89     ncreds_inuse--;
90 }
91
92
93 /* Return a duplicate of the cred. */
94 cred_t *
95 crdup(cred_t * cr)
96 {
97     cred_t *tmp = crget();
98
99     tmp->cr_uid = cr->cr_uid;
100     tmp->cr_ruid = cr->cr_ruid;
101     tmp->cr_gid = cr->cr_gid;
102
103 #if defined(AFS_LINUX26_ENV)
104     get_group_info(cr->cr_group_info);
105     tmp->cr_group_info = cr->cr_group_info;
106 #else
107     memcpy(tmp->cr_groups, cr->cr_groups, NGROUPS * sizeof(gid_t));
108     tmp->cr_ngroups = cr->cr_ngroups;
109 #endif
110
111     tmp->cr_ref = 1;
112     return tmp;
113 }
114
115 cred_t *
116 crref(void)
117 {
118     cred_t *cr = crget();
119
120     cr->cr_uid = current->fsuid;
121     cr->cr_ruid = current->uid;
122     cr->cr_gid = current->fsgid;
123     cr->cr_rgid = current->gid;
124
125 #if defined(AFS_LINUX26_ENV)
126     task_lock(current);
127     get_group_info(current->group_info);
128     cr->cr_group_info = current->group_info;
129     task_unlock(current);
130 #else
131     memcpy(cr->cr_groups, current->groups, NGROUPS * sizeof(gid_t));
132     cr->cr_ngroups = current->ngroups;
133 #endif
134     return cr;
135 }
136
137
138 /* Set the cred info into the current task */
139 void
140 crset(cred_t * cr)
141 {
142     current->fsuid = cr->cr_uid;
143     current->uid = cr->cr_ruid;
144     current->fsgid = cr->cr_gid;
145     current->gid = cr->cr_rgid;
146 #if defined(AFS_LINUX26_ENV)
147 {
148     struct group_info *old_info;
149
150     /* using set_current_groups() will sort the groups */
151     get_group_info(cr->cr_group_info);
152
153     task_lock(current);
154     old_info = current->group_info;
155     current->group_info = cr->cr_group_info;
156     task_unlock(current);
157
158     put_group_info(old_info);
159 }
160 #else
161     memcpy(current->groups, cr->cr_groups, NGROUPS * sizeof(gid_t));
162     current->ngroups = cr->cr_ngroups;
163 #endif
164 }