chas williams - CONTRACTOR wrote:


kmalloc() should be running under GFP_NOFS which should keep the
the filesystem from deadlocking on AFS_GLOCK.  however, for large


What?

I'm admittedly no kernel freak but from what I read in slab.c and page_alloc.c GFP_NOFS does *not* protect you from sleeping and waiting for kswapd when you run out of free pages. Nor does GFP_KERNEL for that matter. And then you're in trouble if you hold the global lock as we know already that through put_inode kswapd might re-enter AFS and deadlock.

GFP_ATOMIC would probably.

You've got a point however in that osi_linux_alloc() is obviously prepared to drop the global lock - however this is only attempted *after* a kmalloc() failed!

Perhaps the fix would be to simply drop the global lock if held and re-acquire it afterwards in osi_alloc.c. Don't know how expensive that would be or whether simply avoiding the whole scanerio isn't the cheaper solution in the long run.

Or use GFP_ATOMIC if we hold the global lock and GFP_NOFS otherwise - is that starting to become a matter of taste? What do the "penguins" say?

Let me know what you'd think of the attached patch. (incomplete yet, as the case "not allowed to drop lock" has yet to be handled as well).


--
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Rainer Toebbicke
European Laboratory for Particle Physics(CERN) - Geneva, Switzerland
Phone: +41 22 767 8985       Fax: +41 22 767 7155
--- openafs/src/afs/LINUX/osi_alloc.c.o141      2004-12-07 07:12:12.000000000 
+0100
+++ openafs/src/afs/LINUX/osi_alloc.c   2006-01-31 09:30:07.000000000 +0100
@@ -87,6 +87,7 @@
 
     /*  if we can use kmalloc use it to allocate the required memory. */
     while (!new && max_retry) {
+       if (drop_glock && haveGlock) AFS_GUNLOCK();     /* kmalloc may sleep */
        if (asize <= MAX_KMALLOC_SIZE) {
            new = (void *)(unsigned long)kmalloc(asize,
 #ifdef GFP_NOFS
@@ -102,6 +103,7 @@
            if (new)            /* piggy back alloc type */
                new = (void *)(VM_TYPE | (unsigned long)new);
        }
+       if (drop_glock && haveGlock) AFS_GUNLOCK();
 
        if (!new) {
 #ifdef set_current_state

Reply via email to