cluster-devel.redhat.com archive mirror
 help / color / mirror / Atom feed
* [Cluster-devel] [GFS2 PATCH][TRY #3] GFS2: Fall back to vmalloc if kmalloc fails for dir hash tables
       [not found] <84854163.31243094.1369921613652.JavaMail.root@redhat.com>
@ 2013-05-30 13:48 ` Bob Peterson
  2013-05-30 14:12   ` Steven Whitehouse
  0 siblings, 1 reply; 2+ messages in thread
From: Bob Peterson @ 2013-05-30 13:48 UTC (permalink / raw)
  To: cluster-devel.redhat.com

Hi,

This version has one more correction: the vmalloc calls are replaced
by __vmalloc calls to preserve the GFP_NOFS flag.

When GFS2's directory management code allocates buffers for a
directory hash table, if it can't get the memory it needs, it
currently gives a bad return code. Rather than giving an error,
this patch allows it to use virtual memory rather than kernel
memory for the hash table. This should make it possible for
directories to function properly, even when kernel memory becomes
very fragmented.

Regards,

Bob Peterson
Red Hat File Systems

Signed-off-by: Bob Peterson <rpeterso@redhat.com> 
---
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index c3e82bd..b631c90 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -354,22 +354,31 @@ static __be64 *gfs2_dir_get_hash_table(struct gfs2_inode *ip)
 		return ERR_PTR(-EIO);
 	}
 
-	hc = kmalloc(hsize, GFP_NOFS);
-	ret = -ENOMEM;
+	hc = kmalloc(hsize, GFP_NOFS | __GFP_NOWARN);
+	if (hc == NULL)
+		hc = __vmalloc(hsize, GFP_NOFS, PAGE_KERNEL);
+
 	if (hc == NULL)
 		return ERR_PTR(-ENOMEM);
 
 	ret = gfs2_dir_read_data(ip, hc, hsize);
 	if (ret < 0) {
-		kfree(hc);
+		if (is_vmalloc_addr(hc))
+			vfree(hc);
+		else
+			kfree(hc);
 		return ERR_PTR(ret);
 	}
 
 	spin_lock(&inode->i_lock);
-	if (ip->i_hash_cache)
-		kfree(hc);
-	else
+	if (ip->i_hash_cache) {
+		if (is_vmalloc_addr(hc))
+			vfree(hc);
+		else
+			kfree(hc);
+	} else {
 		ip->i_hash_cache = hc;
+	}
 	spin_unlock(&inode->i_lock);
 
 	return ip->i_hash_cache;
@@ -385,7 +394,10 @@ void gfs2_dir_hash_inval(struct gfs2_inode *ip)
 {
 	__be64 *hc = ip->i_hash_cache;
 	ip->i_hash_cache = NULL;
-	kfree(hc);
+	if (is_vmalloc_addr(hc))
+		vfree(hc);
+	else
+		kfree(hc);
 }
 
 static inline int gfs2_dirent_sentinel(const struct gfs2_dirent *dent)
@@ -1113,7 +1125,10 @@ static int dir_double_exhash(struct gfs2_inode *dip)
 	if (IS_ERR(hc))
 		return PTR_ERR(hc);
 
-	h = hc2 = kmalloc(hsize_bytes * 2, GFP_NOFS);
+	h = hc2 = kmalloc(hsize_bytes * 2, GFP_NOFS | __GFP_NOWARN);
+	if (hc2 == NULL)
+		hc2 = __vmalloc(hsize_bytes * 2, GFP_NOFS, PAGE_KERNEL);
+
 	if (!hc2)
 		return -ENOMEM;
 
@@ -1145,7 +1160,10 @@ fail:
 	gfs2_dinode_out(dip, dibh->b_data);
 	brelse(dibh);
 out_kfree:
-	kfree(hc2);
+	if (is_vmalloc_addr(hc2))
+		vfree(hc2);
+	else
+		kfree(hc2);
 	return error;
 }
 
@@ -1846,6 +1864,8 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
 	memset(&rlist, 0, sizeof(struct gfs2_rgrp_list));
 
 	ht = kzalloc(size, GFP_NOFS);
+	if (ht == NULL)
+		ht = vzalloc(size);
 	if (!ht)
 		return -ENOMEM;
 
@@ -1933,7 +1953,10 @@ out_rlist:
 	gfs2_rlist_free(&rlist);
 	gfs2_quota_unhold(dip);
 out:
-	kfree(ht);
+	if (is_vmalloc_addr(ht))
+		vfree(ht);
+	else
+		kfree(ht);
 	return error;
 }
 



^ permalink raw reply related	[flat|nested] 2+ messages in thread

* [Cluster-devel] [GFS2 PATCH][TRY #3] GFS2: Fall back to vmalloc if kmalloc fails for dir hash tables
  2013-05-30 13:48 ` [Cluster-devel] [GFS2 PATCH][TRY #3] GFS2: Fall back to vmalloc if kmalloc fails for dir hash tables Bob Peterson
@ 2013-05-30 14:12   ` Steven Whitehouse
  0 siblings, 0 replies; 2+ messages in thread
From: Steven Whitehouse @ 2013-05-30 14:12 UTC (permalink / raw)
  To: cluster-devel.redhat.com

Hi,

Now in the -nmw tree. Thanks,

Steve.

On Thu, 2013-05-30 at 09:48 -0400, Bob Peterson wrote:
> Hi,
> 
> This version has one more correction: the vmalloc calls are replaced
> by __vmalloc calls to preserve the GFP_NOFS flag.
> 
> When GFS2's directory management code allocates buffers for a
> directory hash table, if it can't get the memory it needs, it
> currently gives a bad return code. Rather than giving an error,
> this patch allows it to use virtual memory rather than kernel
> memory for the hash table. This should make it possible for
> directories to function properly, even when kernel memory becomes
> very fragmented.
> 
> Regards,
> 
> Bob Peterson
> Red Hat File Systems
> 
> Signed-off-by: Bob Peterson <rpeterso@redhat.com> 
> ---
> diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
> index c3e82bd..b631c90 100644
> --- a/fs/gfs2/dir.c
> +++ b/fs/gfs2/dir.c
> @@ -354,22 +354,31 @@ static __be64 *gfs2_dir_get_hash_table(struct gfs2_inode *ip)
>  		return ERR_PTR(-EIO);
>  	}
>  
> -	hc = kmalloc(hsize, GFP_NOFS);
> -	ret = -ENOMEM;
> +	hc = kmalloc(hsize, GFP_NOFS | __GFP_NOWARN);
> +	if (hc == NULL)
> +		hc = __vmalloc(hsize, GFP_NOFS, PAGE_KERNEL);
> +
>  	if (hc == NULL)
>  		return ERR_PTR(-ENOMEM);
>  
>  	ret = gfs2_dir_read_data(ip, hc, hsize);
>  	if (ret < 0) {
> -		kfree(hc);
> +		if (is_vmalloc_addr(hc))
> +			vfree(hc);
> +		else
> +			kfree(hc);
>  		return ERR_PTR(ret);
>  	}
>  
>  	spin_lock(&inode->i_lock);
> -	if (ip->i_hash_cache)
> -		kfree(hc);
> -	else
> +	if (ip->i_hash_cache) {
> +		if (is_vmalloc_addr(hc))
> +			vfree(hc);
> +		else
> +			kfree(hc);
> +	} else {
>  		ip->i_hash_cache = hc;
> +	}
>  	spin_unlock(&inode->i_lock);
>  
>  	return ip->i_hash_cache;
> @@ -385,7 +394,10 @@ void gfs2_dir_hash_inval(struct gfs2_inode *ip)
>  {
>  	__be64 *hc = ip->i_hash_cache;
>  	ip->i_hash_cache = NULL;
> -	kfree(hc);
> +	if (is_vmalloc_addr(hc))
> +		vfree(hc);
> +	else
> +		kfree(hc);
>  }
>  
>  static inline int gfs2_dirent_sentinel(const struct gfs2_dirent *dent)
> @@ -1113,7 +1125,10 @@ static int dir_double_exhash(struct gfs2_inode *dip)
>  	if (IS_ERR(hc))
>  		return PTR_ERR(hc);
>  
> -	h = hc2 = kmalloc(hsize_bytes * 2, GFP_NOFS);
> +	h = hc2 = kmalloc(hsize_bytes * 2, GFP_NOFS | __GFP_NOWARN);
> +	if (hc2 == NULL)
> +		hc2 = __vmalloc(hsize_bytes * 2, GFP_NOFS, PAGE_KERNEL);
> +
>  	if (!hc2)
>  		return -ENOMEM;
>  
> @@ -1145,7 +1160,10 @@ fail:
>  	gfs2_dinode_out(dip, dibh->b_data);
>  	brelse(dibh);
>  out_kfree:
> -	kfree(hc2);
> +	if (is_vmalloc_addr(hc2))
> +		vfree(hc2);
> +	else
> +		kfree(hc2);
>  	return error;
>  }
>  
> @@ -1846,6 +1864,8 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
>  	memset(&rlist, 0, sizeof(struct gfs2_rgrp_list));
>  
>  	ht = kzalloc(size, GFP_NOFS);
> +	if (ht == NULL)
> +		ht = vzalloc(size);
>  	if (!ht)
>  		return -ENOMEM;
>  
> @@ -1933,7 +1953,10 @@ out_rlist:
>  	gfs2_rlist_free(&rlist);
>  	gfs2_quota_unhold(dip);
>  out:
> -	kfree(ht);
> +	if (is_vmalloc_addr(ht))
> +		vfree(ht);
> +	else
> +		kfree(ht);
>  	return error;
>  }
>  
> 




^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2013-05-30 14:12 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <84854163.31243094.1369921613652.JavaMail.root@redhat.com>
2013-05-30 13:48 ` [Cluster-devel] [GFS2 PATCH][TRY #3] GFS2: Fall back to vmalloc if kmalloc fails for dir hash tables Bob Peterson
2013-05-30 14:12   ` Steven Whitehouse

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).