From 4f91de7cf429db63bcf67466cf3fb36feb990643 Mon Sep 17 00:00:00 2001 From: Simon Wilkinson Date: Sat, 24 Oct 2009 15:08:52 +0100 Subject: [PATCH] Linux: Use atomics for credential reference counts The reference count maintained as part of the afs_cred structure wasn't being maintained atomically, requiring that crfree and crhold always be called with the GLOCK held. This patch just switches to using Linux's inbuilt atomic types to maintain the reference count. Change-Id: I1787061afbb48e234b4839b38b8801168ea2f25f Reviewed-on: http://gerrit.openafs.org/726 Reviewed-by: Derrick Brashear Tested-by: Derrick Brashear --- src/afs/LINUX/osi_cred.c | 10 ++++------ src/afs/LINUX/osi_machdep.h | 4 ++-- src/afs/afs_osi_gcpags.c | 5 ++++- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/afs/LINUX/osi_cred.c b/src/afs/LINUX/osi_cred.c index 69b261496..f402a5746 100644 --- a/src/afs/LINUX/osi_cred.c +++ b/src/afs/LINUX/osi_cred.c @@ -45,7 +45,7 @@ crget(void) #if defined(STRUCT_TASK_HAS_CRED) get_cred(tmp); #else - tmp->cr_ref = 1; + atomic_set(&tmp->cr_ref, 1); #endif return tmp; } @@ -56,12 +56,10 @@ crfree(cred_t * cr) #if defined(STRUCT_TASK_HAS_CRED) put_cred(cr); #else - if (cr->cr_ref > 1) { - cr->cr_ref--; - return; + if (atomic_dec_and_test(&cr->cr_ref)) { + put_group_info(afs_cr_group_info(cr)); + kfree(cr); } - put_group_info(afs_cr_group_info(cr)); - kfree(cr); #endif } diff --git a/src/afs/LINUX/osi_machdep.h b/src/afs/LINUX/osi_machdep.h index 52d4ea20d..bfd11c1ab 100644 --- a/src/afs/LINUX/osi_machdep.h +++ b/src/afs/LINUX/osi_machdep.h @@ -197,7 +197,7 @@ afs_set_cr_group_info(cred_t *cred, struct group_info *group_info) { #else typedef struct afs_cred { - int cr_ref; + atomic_t cr_ref; uid_t cr_uid; uid_t cr_ruid; gid_t cr_gid; @@ -222,7 +222,7 @@ afs_set_cr_group_info(cred_t *cred, struct group_info *group_info) { #define task_user(task) (task->user) #define task_session_keyring(task) (task->signal->session_keyring) #define current_session_keyring() (current->signal->session_keyring) -#define crhold(c) (c)->cr_ref++ +#define crhold(c) atomic_inc(&(c)->cr_ref) #endif /* defined(STRUCT_TASK_HAS_CRED) */ diff --git a/src/afs/afs_osi_gcpags.c b/src/afs/afs_osi_gcpags.c index 6d8f3bae5..0c34297ae 100644 --- a/src/afs/afs_osi_gcpags.c +++ b/src/afs/afs_osi_gcpags.c @@ -470,7 +470,10 @@ afs_osi_proc2cred(afs_proc_t * pr) if ((pr->state == TASK_RUNNING) || (pr->state == TASK_INTERRUPTIBLE) || (pr->state == TASK_UNINTERRUPTIBLE) || (pr->state == TASK_STOPPED)) { - cr.cr_ref = 1; + /* This is dangerous. If anyone ever crfree's the cred that's + * returned from here, we'll go boom, because it's statically + * allocated. */ + atomic_set(&cr.cr_ref, 1); afs_set_cr_uid(&cr, task_uid(pr)); #if defined(AFS_LINUX26_ENV) #if defined(STRUCT_TASK_HAS_CRED) -- 2.39.5