From mboxrd@z Thu Jan 1 00:00:00 1970 From: Steven Whitehouse Date: Thu, 30 May 2013 14:11:02 +0100 Subject: [Cluster-devel] [GFS2 PATCH] GFS2: Fall back to vmalloc if kmalloc fails for dir hash tables In-Reply-To: <78919513.31195296.1369919295427.JavaMail.root@redhat.com> References: <78919513.31195296.1369919295427.JavaMail.root@redhat.com> Message-ID: <1369919462.2733.12.camel@menhir> List-Id: To: cluster-devel.redhat.com MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Hi, On Thu, 2013-05-30 at 09:08 -0400, Bob Peterson wrote: > Hi, > > 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 an 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 > --- > diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c > index c3e82bd..cf662fd 100644 > --- a/fs/gfs2/dir.c > +++ b/fs/gfs2/dir.c > @@ -355,21 +355,30 @@ static __be64 *gfs2_dir_get_hash_table(struct gfs2_inode *ip) > } > > hc = kmalloc(hsize, GFP_NOFS); This should have GFP_NOWARN in addition to GFP_NOFS I think. Otherwise looks good, Steve. > - ret = -ENOMEM; > + if (hc == NULL) > + hc = vmalloc(hsize); > + > 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) > @@ -1114,6 +1126,9 @@ static int dir_double_exhash(struct gfs2_inode *dip) > return PTR_ERR(hc); > > h = hc2 = kmalloc(hsize_bytes * 2, GFP_NOFS); > + if (hc2 == NULL) > + hc2 = vmalloc(hsize_bytes * 2); > + > 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; > } > >