Linux: Use atomics for credential reference counts
authorSimon Wilkinson <sxw@inf.ed.ac.uk>
Sat, 24 Oct 2009 14:08:52 +0000 (15:08 +0100)
committerDerrick Brashear <shadow|account-1000005@unknown>
Fri, 20 Nov 2009 12:39:23 +0000 (04:39 -0800)
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 <shadow@dementia.org>
Tested-by: Derrick Brashear <shadow@dementia.org>

src/afs/LINUX/osi_cred.c
src/afs/LINUX/osi_machdep.h
src/afs/afs_osi_gcpags.c

index 69b2614..f402a57 100644 (file)
@@ -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
 }
 
index 52d4ea2..bfd11c1 100644 (file)
@@ -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) */
 
index 6d8f3ba..0c34297 100644 (file)
@@ -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)