* osi_cred.c - Linux cred handling routines.
*
*/
-#include "../afs/param.h"
#include <afsconfig.h>
+#include "afs/param.h"
-RCSID("$Header$");
-#include "../afs/sysincludes.h"
-#include "../afs/afsincludes.h"
+#include "afs/sysincludes.h"
+#include "afsincludes.h"
-/* Setup a pool for creds. Allocate several at a time. */
-#define CRED_ALLOC_STEP 29 /* at 140 bytes/cred = 4060 bytes. */
-
-
-static cred_t *cred_pool = NULL;
-int cred_allocs = 0;
-int ncreds_inuse = 0;
-
-/* Cred locking assumes current single threaded non-preemptive kernel.
- * Also assuming a fast path through both down and up if no waiters. Otherwise,
- * test if no creds in pool before grabbing lock in crfree().
- */
-#if defined(AFS_LINUX24_ENV)
-static DECLARE_MUTEX(linux_cred_pool_lock);
+/* Copy one credential structure to another, being careful about references */
+static inline void
+afs_copy_creds(cred_t *to_cred, const cred_t *from_cred) {
+#if defined(STRUCT_TASK_STRUCT_HAS_CRED)
+ /* Skip afs_from_kuid/afs_make_kuid round trip */
+ to_cred->fsuid = from_cred->fsuid;
+ to_cred->fsgid = from_cred->fsgid;
+ to_cred->uid = from_cred->uid;
+ to_cred->gid = from_cred->gid;
#else
-static struct semaphore linux_cred_pool_lock = MUTEX;
+ afs_set_cr_uid(to_cred, afs_cr_uid(from_cred));
+ afs_set_cr_gid(to_cred, afs_cr_gid(from_cred));
+ afs_set_cr_ruid(to_cred, afs_cr_ruid(from_cred));
+ afs_set_cr_rgid(to_cred, afs_cr_rgid(from_cred));
#endif
-#define CRED_LOCK() down(&linux_cred_pool_lock)
-#define CRED_UNLOCK() up(&linux_cred_pool_lock)
+ get_group_info(afs_cr_group_info(from_cred));
+ afs_set_cr_group_info(to_cred, afs_cr_group_info(from_cred));
+}
-cred_t *crget(void)
+cred_t *
+crget(void)
{
cred_t *tmp;
- int i;
-
- CRED_LOCK();
- if (!cred_pool) {
- cred_allocs++;
- cred_pool = (cred_t*)osi_Alloc(CRED_ALLOC_STEP * sizeof(cred_t));
- if (!cred_pool)
- osi_Panic("crget: No more memory for creds!\n");
-
- for (i=0; i < CRED_ALLOC_STEP-1; i++)
- cred_pool[i].cr_ref = (long)&cred_pool[i+1];
- cred_pool[i].cr_ref = 0;
- }
- tmp = cred_pool;
- cred_pool = (cred_t*)tmp->cr_ref;
- ncreds_inuse++;
- CRED_UNLOCK();
+
+ tmp = kmalloc(sizeof(cred_t), GFP_NOFS);
+ if (!tmp)
+ osi_Panic("crget: No more memory for creds!\n");
- memset(tmp, 0, sizeof(cred_t));
- tmp->cr_ref = 1;
+#if defined(STRUCT_TASK_STRUCT_HAS_CRED)
+ get_cred(tmp);
+#else
+ atomic_set(&tmp->cr_ref, 1);
+#endif
return tmp;
}
-void crfree(cred_t *cr)
+void
+crfree(cred_t * cr)
{
- if (cr->cr_ref > 1) {
- cr->cr_ref--;
- return;
+#if defined(STRUCT_TASK_STRUCT_HAS_CRED)
+ put_cred(cr);
+#else
+ if (atomic_dec_and_test(&cr->cr_ref)) {
+ put_group_info(afs_cr_group_info(cr));
+ kfree(cr);
}
-
- CRED_LOCK();
- cr->cr_ref = (long)cred_pool;
- cred_pool = cr;
- CRED_UNLOCK();
- ncreds_inuse --;
+#endif
}
/* Return a duplicate of the cred. */
-cred_t *crdup(cred_t *cr)
+cred_t *
+crdup(cred_t * cr)
{
cred_t *tmp = crget();
- *tmp = *cr;
- tmp->cr_ref = 1;
+#if defined(STRUCT_TASK_STRUCT_HAS_CRED)
+ afs_copy_creds(tmp, cr);
+#else
+ afs_set_cr_uid(tmp, afs_cr_uid(cr));
+ afs_set_cr_ruid(tmp, afs_cr_ruid(cr));
+ afs_set_cr_gid(tmp, afs_cr_gid(cr));
+ afs_set_cr_rgid(tmp, afs_cr_rgid(cr));
+
+ get_group_info(afs_cr_group_info(cr));
+ afs_set_cr_group_info(tmp, afs_cr_group_info(cr));
+#endif
return tmp;
}
-cred_t *crref(void)
+cred_t *
+crref(void)
{
+#if defined(STRUCT_TASK_STRUCT_HAS_CRED)
+ return (cred_t *)get_current_cred();
+#else
cred_t *cr = crget();
- cr->cr_uid = current->fsuid;
- cr->cr_ruid = current->uid;
- cr->cr_gid = current->fsgid;
- cr->cr_rgid = current->gid;
- memcpy(cr->cr_groups, current->groups, NGROUPS * sizeof(gid_t));
- cr->cr_ngroups = current->ngroups;
+
+ afs_set_cr_uid(cr, current_fsuid());
+ afs_set_cr_ruid(cr, current_uid());
+ afs_set_cr_gid(cr, current_fsgid());
+ afs_set_cr_rgid(cr, current_gid());
+
+ task_lock(current);
+ get_group_info(current_group_info());
+ afs_set_cr_group_info(cr, current_group_info());
+ task_unlock(current);
+
return cr;
+#endif
}
-
/* Set the cred info into the current task */
-void crset(cred_t *cr)
+void
+crset(cred_t * cr)
{
- current->fsuid = cr->cr_uid;
- current->uid = cr->cr_ruid;
- current->fsgid = cr->cr_gid;
- current->gid = cr->cr_rgid;
- memcpy(current->groups, cr->cr_groups, NGROUPS * sizeof(gid_t));
- current->ngroups = cr->cr_ngroups;
+#if defined(STRUCT_TASK_STRUCT_HAS_CRED)
+ struct cred *new_creds;
+
+ /* If our current task doesn't have identical real and effective
+ * credentials, commit_cred won't let us change them, so we just
+ * bail here.
+ */
+ if (current->cred != current->real_cred)
+ return;
+ new_creds = prepare_creds();
+ /* Drop the reference to group_info - we'll overwrite it in afs_copy_creds */
+ put_group_info(new_creds->group_info);
+ afs_copy_creds(new_creds, cr);
+
+ commit_creds(new_creds);
+#else
+ struct group_info *old_info;
+
+ current->fsuid = afs_cr_uid(cr);
+ current->uid = afs_cr_ruid(cr);
+ current->fsgid = afs_cr_gid(cr);
+ current->gid = afs_cr_rgid(cr);
+
+ get_group_info(afs_cr_group_info(cr));
+ task_lock(current);
+ old_info = current->group_info;
+ current->group_info = afs_cr_group_info(cr);
+ task_unlock(current);
+ put_group_info(old_info);
+#endif
}