linux-osi-alloc-up-alloc-sem-while-alloc-to-avoid-deadlock-against-glock-20020215
[openafs.git] / src / afs / LINUX / osi_alloc.c
index ab0352d..154fce5 100644 (file)
  * osi_alloc.c - Linux memory allocation routines.
  *
  */
+#include <afsconfig.h>
 #include "../afs/param.h"
+
+RCSID("$Header$");
+
 #include "../afs/sysincludes.h"
 #include "../afs/afsincludes.h"
 #include "../h/mm.h"
+#include "../h/slab.h"
 
 #include "../afs/afs_atomlist.h"
 #include "../afs/afs_lhash.h"
@@ -32,8 +37,8 @@ struct osi_linux_mem {
 };
 
 /* These assume 32-bit pointers */
-#define MEMTYPE(A) (((unsigned int)A) & 0x3)
-#define MEMADDR(A) (void *)((unsigned int)(A) & (~0x3))
+#define MEMTYPE(A) (((unsigned long)A) & 0x3)
+#define MEMADDR(A) (void *)((unsigned long)(A) & (~0x3))
 
 /* globals */
 afs_atomlist *al_mem_pool; /* pool of osi_linux_mem structures */
@@ -82,9 +87,15 @@ static void *linux_alloc(unsigned int asize)
 
     /*  if we can use kmalloc use it to allocate the required memory. */
     if (asize <  MAX_KMALLOC_SIZE) {
-        new = (void *)kmalloc(asize, GFP_KERNEL);
+        new = (void *)(unsigned long)kmalloc(asize, 
+#ifdef GFP_NOFS
+                                            GFP_NOFS
+#else
+                                            GFP_KERNEL
+#endif
+                                            );
         if (new) /* piggy back alloc type */
-            (unsigned int)new |= KM_TYPE;
+            (unsigned long)new |= KM_TYPE;
     }
     if (!new) { /* otherwise use vmalloc  */
        int max_wait = 10;
@@ -92,10 +103,15 @@ static void *linux_alloc(unsigned int asize)
             if (--max_wait <=0) {
                break;
             }
-           schedule();
+#ifdef set_current_state
+           set_current_state(TASK_INTERRUPTIBLE);
+#else
+           current->state = TASK_INTERRUPTIBLE;
+#endif
+           schedule_timeout(HZ);
         }
        if (new) /* piggy back alloc type */
-           (unsigned int)new |= VM_TYPE;
+           (unsigned long)new |= VM_TYPE;
     }
     if (new)
        memset(MEMADDR(new), 0, asize);
@@ -139,7 +155,7 @@ static unsigned hash_chunk(void *p)
 {
     unsigned int key;
 
-    key = (unsigned int)p >> 2;
+    key = (unsigned int)(long)p >> 2;
     key = (key * HASH_CONST)%HASH_PRIME;
 
     return key;
@@ -199,14 +215,15 @@ static int linux_alloc_init()
 {
     /* initiate our pool of osi_linux_mem structs */
     al_mem_pool = afs_atomlist_create(sizeof(struct osi_linux_mem),
-                                  sizeof(long)*1024, vmalloc, local_free);
+                                     sizeof(long)*1024, (void *)vmalloc, 
+                                     local_free);
     if (!al_mem_pool) {
         printf("afs_osi_Alloc: Error in initialization(atomlist_create)\n");
         return 0;
     }
 
     /* initialize the hash table to hold references to alloc'ed chunks */
-    lh_mem_htab = afs_lhash_create(hash_equal, vmalloc, local_free);
+    lh_mem_htab = afs_lhash_create(hash_equal, (void *)vmalloc, local_free);
     if (!lh_mem_htab) {
         printf("afs_osi_Alloc: Error in initialization(lhash_create)\n");
         return 0;
@@ -273,7 +290,9 @@ void *osi_linux_alloc(unsigned int asize)
        allocator_init = 1; /* initialization complete */
     }
 
+    up(&afs_linux_alloc_sem);
     new = linux_alloc(asize); /* get a chunk of memory of size asize */
+    down(&afs_linux_alloc_sem);
     if (!new) {
        printf("afs_osi_Alloc: Can't vmalloc %d bytes.\n", asize);
        goto error;
@@ -303,8 +322,11 @@ void *osi_linux_alloc(unsigned int asize)
     return MEMADDR(new);
 
   free_error:
-    if (new)
-        linux_free(new);
+    if (new) {
+       up(&afs_linux_alloc_sem);
+       linux_free(new);
+       down(&afs_linux_alloc_sem);
+    }
     new = NULL;
     goto error;
 
@@ -339,20 +361,21 @@ void osi_linux_free_afs_memory(void)
 {
     down(&afs_linux_alloc_sem);
 
-    /* iterate through all elements in the hash table and free both 
-     * the chunk and the atom associated with it.
-     */
-    afs_lhash_iter(lh_mem_htab, hash_free);
+    if (allocator_init) {
+       /* iterate through all elements in the hash table and free both 
+        * the chunk and the atom associated with it.
+        */
+       afs_lhash_iter(lh_mem_htab, hash_free);
 
-    /*  free the atomlist. */
-    afs_atomlist_destroy(al_mem_pool);
-
-    /* free the hashlist. */
-    afs_lhash_destroy(lh_mem_htab);
-
-    /* change the state so that the allocator is now uninitialized. */
-    allocator_init = 0;
+       /*  free the atomlist. */
+       afs_atomlist_destroy(al_mem_pool);
 
+       /* free the hashlist. */
+       afs_lhash_destroy(lh_mem_htab);
+       
+       /* change the state so that the allocator is now uninitialized. */
+       allocator_init = 0;
+    }
     up(&afs_linux_alloc_sem);    
 }