Commit 6f66f900 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-fixes

Pull gfs2 fixes from Steven Whitehouse:
 "There are four patches this time.

  The first fixes a problem where the wrong descriptor type was being
  written into the log for journaled data blocks.

  The second fixes a race relating to the deallocation of allocator
  data.

  The third provides a fallback if kmalloc is unable to satisfy a
  request to allocate a directory hash table.

  The fourth fixes the iopen glock caching so that inodes are deleted in
  a more timely manner after rmdir/unlink"

* git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-fixes:
  GFS2: Don't cache iopen glocks
  GFS2: Fall back to vmalloc if kmalloc fails for dir hash tables
  GFS2: Increase i_writecount during gfs2_setattr_size
  GFS2: Set log descriptor type for jdata blocks
parents 8764d861 a6a4d98b
...@@ -1286,17 +1286,26 @@ int gfs2_setattr_size(struct inode *inode, u64 newsize) ...@@ -1286,17 +1286,26 @@ int gfs2_setattr_size(struct inode *inode, u64 newsize)
if (ret) if (ret)
return ret; return ret;
ret = get_write_access(inode);
if (ret)
return ret;
inode_dio_wait(inode); inode_dio_wait(inode);
ret = gfs2_rs_alloc(GFS2_I(inode)); ret = gfs2_rs_alloc(GFS2_I(inode));
if (ret) if (ret)
return ret; goto out;
oldsize = inode->i_size; oldsize = inode->i_size;
if (newsize >= oldsize) if (newsize >= oldsize) {
return do_grow(inode, newsize); ret = do_grow(inode, newsize);
goto out;
}
return do_shrink(inode, oldsize, newsize); ret = do_shrink(inode, oldsize, newsize);
out:
put_write_access(inode);
return ret;
} }
int gfs2_truncatei_resume(struct gfs2_inode *ip) int gfs2_truncatei_resume(struct gfs2_inode *ip)
......
...@@ -354,22 +354,31 @@ static __be64 *gfs2_dir_get_hash_table(struct gfs2_inode *ip) ...@@ -354,22 +354,31 @@ static __be64 *gfs2_dir_get_hash_table(struct gfs2_inode *ip)
return ERR_PTR(-EIO); return ERR_PTR(-EIO);
} }
hc = kmalloc(hsize, GFP_NOFS); hc = kmalloc(hsize, GFP_NOFS | __GFP_NOWARN);
ret = -ENOMEM; if (hc == NULL)
hc = __vmalloc(hsize, GFP_NOFS, PAGE_KERNEL);
if (hc == NULL) if (hc == NULL)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
ret = gfs2_dir_read_data(ip, hc, hsize); ret = gfs2_dir_read_data(ip, hc, hsize);
if (ret < 0) { if (ret < 0) {
if (is_vmalloc_addr(hc))
vfree(hc);
else
kfree(hc); kfree(hc);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
if (ip->i_hash_cache) if (ip->i_hash_cache) {
kfree(hc); if (is_vmalloc_addr(hc))
vfree(hc);
else else
kfree(hc);
} else {
ip->i_hash_cache = hc; ip->i_hash_cache = hc;
}
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
return ip->i_hash_cache; return ip->i_hash_cache;
...@@ -385,6 +394,9 @@ void gfs2_dir_hash_inval(struct gfs2_inode *ip) ...@@ -385,6 +394,9 @@ void gfs2_dir_hash_inval(struct gfs2_inode *ip)
{ {
__be64 *hc = ip->i_hash_cache; __be64 *hc = ip->i_hash_cache;
ip->i_hash_cache = NULL; ip->i_hash_cache = NULL;
if (is_vmalloc_addr(hc))
vfree(hc);
else
kfree(hc); kfree(hc);
} }
...@@ -1113,7 +1125,10 @@ static int dir_double_exhash(struct gfs2_inode *dip) ...@@ -1113,7 +1125,10 @@ static int dir_double_exhash(struct gfs2_inode *dip)
if (IS_ERR(hc)) if (IS_ERR(hc))
return PTR_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) if (!hc2)
return -ENOMEM; return -ENOMEM;
...@@ -1145,6 +1160,9 @@ static int dir_double_exhash(struct gfs2_inode *dip) ...@@ -1145,6 +1160,9 @@ static int dir_double_exhash(struct gfs2_inode *dip)
gfs2_dinode_out(dip, dibh->b_data); gfs2_dinode_out(dip, dibh->b_data);
brelse(dibh); brelse(dibh);
out_kfree: out_kfree:
if (is_vmalloc_addr(hc2))
vfree(hc2);
else
kfree(hc2); kfree(hc2);
return error; return error;
} }
...@@ -1846,6 +1864,8 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, ...@@ -1846,6 +1864,8 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
memset(&rlist, 0, sizeof(struct gfs2_rgrp_list)); memset(&rlist, 0, sizeof(struct gfs2_rgrp_list));
ht = kzalloc(size, GFP_NOFS); ht = kzalloc(size, GFP_NOFS);
if (ht == NULL)
ht = vzalloc(size);
if (!ht) if (!ht)
return -ENOMEM; return -ENOMEM;
...@@ -1933,6 +1953,9 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, ...@@ -1933,6 +1953,9 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
gfs2_rlist_free(&rlist); gfs2_rlist_free(&rlist);
gfs2_quota_unhold(dip); gfs2_quota_unhold(dip);
out: out:
if (is_vmalloc_addr(ht))
vfree(ht);
else
kfree(ht); kfree(ht);
return error; return error;
} }
......
...@@ -402,16 +402,20 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -402,16 +402,20 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
/* Update file times before taking page lock */ /* Update file times before taking page lock */
file_update_time(vma->vm_file); file_update_time(vma->vm_file);
ret = get_write_access(inode);
if (ret)
goto out;
ret = gfs2_rs_alloc(ip); ret = gfs2_rs_alloc(ip);
if (ret) if (ret)
return ret; goto out_write_access;
gfs2_size_hint(vma->vm_file, pos, PAGE_CACHE_SIZE); gfs2_size_hint(vma->vm_file, pos, PAGE_CACHE_SIZE);
gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
ret = gfs2_glock_nq(&gh); ret = gfs2_glock_nq(&gh);
if (ret) if (ret)
goto out; goto out_uninit;
set_bit(GLF_DIRTY, &ip->i_gl->gl_flags); set_bit(GLF_DIRTY, &ip->i_gl->gl_flags);
set_bit(GIF_SW_PAGED, &ip->i_flags); set_bit(GIF_SW_PAGED, &ip->i_flags);
...@@ -480,12 +484,15 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -480,12 +484,15 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
gfs2_quota_unlock(ip); gfs2_quota_unlock(ip);
out_unlock: out_unlock:
gfs2_glock_dq(&gh); gfs2_glock_dq(&gh);
out: out_uninit:
gfs2_holder_uninit(&gh); gfs2_holder_uninit(&gh);
if (ret == 0) { if (ret == 0) {
set_page_dirty(page); set_page_dirty(page);
wait_for_stable_page(page); wait_for_stable_page(page);
} }
out_write_access:
put_write_access(inode);
out:
sb_end_pagefault(inode->i_sb); sb_end_pagefault(inode->i_sb);
return block_page_mkwrite_return(ret); return block_page_mkwrite_return(ret);
} }
...@@ -594,10 +601,10 @@ static int gfs2_release(struct inode *inode, struct file *file) ...@@ -594,10 +601,10 @@ static int gfs2_release(struct inode *inode, struct file *file)
kfree(file->private_data); kfree(file->private_data);
file->private_data = NULL; file->private_data = NULL;
if ((file->f_mode & FMODE_WRITE) && if (!(file->f_mode & FMODE_WRITE))
(atomic_read(&inode->i_writecount) == 1)) return 0;
gfs2_rs_delete(ip);
gfs2_rs_delete(ip);
return 0; return 0;
} }
......
...@@ -189,6 +189,7 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, ...@@ -189,6 +189,7 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
return inode; return inode;
fail_refresh: fail_refresh:
ip->i_iopen_gh.gh_flags |= GL_NOCACHE;
ip->i_iopen_gh.gh_gl->gl_object = NULL; ip->i_iopen_gh.gh_gl->gl_object = NULL;
gfs2_glock_dq_uninit(&ip->i_iopen_gh); gfs2_glock_dq_uninit(&ip->i_iopen_gh);
fail_iopen: fail_iopen:
......
...@@ -419,7 +419,9 @@ static void gfs2_before_commit(struct gfs2_sbd *sdp, unsigned int limit, ...@@ -419,7 +419,9 @@ static void gfs2_before_commit(struct gfs2_sbd *sdp, unsigned int limit,
if (total > limit) if (total > limit)
num = limit; num = limit;
gfs2_log_unlock(sdp); gfs2_log_unlock(sdp);
page = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_METADATA, num + 1, num); page = gfs2_get_log_desc(sdp,
is_databuf ? GFS2_LOG_DESC_JDATA :
GFS2_LOG_DESC_METADATA, num + 1, num);
ld = page_address(page); ld = page_address(page);
gfs2_log_lock(sdp); gfs2_log_lock(sdp);
ptr = (__be64 *)(ld + 1); ptr = (__be64 *)(ld + 1);
......
...@@ -638,8 +638,10 @@ void gfs2_rs_deltree(struct gfs2_blkreserv *rs) ...@@ -638,8 +638,10 @@ void gfs2_rs_deltree(struct gfs2_blkreserv *rs)
*/ */
void gfs2_rs_delete(struct gfs2_inode *ip) void gfs2_rs_delete(struct gfs2_inode *ip)
{ {
struct inode *inode = &ip->i_inode;
down_write(&ip->i_rw_mutex); down_write(&ip->i_rw_mutex);
if (ip->i_res) { if (ip->i_res && atomic_read(&inode->i_writecount) <= 1) {
gfs2_rs_deltree(ip->i_res); gfs2_rs_deltree(ip->i_res);
BUG_ON(ip->i_res->rs_free); BUG_ON(ip->i_res->rs_free);
kmem_cache_free(gfs2_rsrv_cachep, ip->i_res); kmem_cache_free(gfs2_rsrv_cachep, ip->i_res);
......
...@@ -1444,6 +1444,7 @@ static void gfs2_evict_inode(struct inode *inode) ...@@ -1444,6 +1444,7 @@ static void gfs2_evict_inode(struct inode *inode)
/* Must not read inode block until block type has been verified */ /* Must not read inode block until block type has been verified */
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, &gh); error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, &gh);
if (unlikely(error)) { if (unlikely(error)) {
ip->i_iopen_gh.gh_flags |= GL_NOCACHE;
gfs2_glock_dq_uninit(&ip->i_iopen_gh); gfs2_glock_dq_uninit(&ip->i_iopen_gh);
goto out; goto out;
} }
...@@ -1514,8 +1515,10 @@ static void gfs2_evict_inode(struct inode *inode) ...@@ -1514,8 +1515,10 @@ static void gfs2_evict_inode(struct inode *inode)
if (gfs2_rs_active(ip->i_res)) if (gfs2_rs_active(ip->i_res))
gfs2_rs_deltree(ip->i_res); gfs2_rs_deltree(ip->i_res);
if (test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) if (test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) {
ip->i_iopen_gh.gh_flags |= GL_NOCACHE;
gfs2_glock_dq(&ip->i_iopen_gh); gfs2_glock_dq(&ip->i_iopen_gh);
}
gfs2_holder_uninit(&ip->i_iopen_gh); gfs2_holder_uninit(&ip->i_iopen_gh);
gfs2_glock_dq_uninit(&gh); gfs2_glock_dq_uninit(&gh);
if (error && error != GLR_TRYFAILED && error != -EROFS) if (error && error != GLR_TRYFAILED && error != -EROFS)
...@@ -1534,6 +1537,7 @@ static void gfs2_evict_inode(struct inode *inode) ...@@ -1534,6 +1537,7 @@ static void gfs2_evict_inode(struct inode *inode)
ip->i_gl = NULL; ip->i_gl = NULL;
if (ip->i_iopen_gh.gh_gl) { if (ip->i_iopen_gh.gh_gl) {
ip->i_iopen_gh.gh_gl->gl_object = NULL; ip->i_iopen_gh.gh_gl->gl_object = NULL;
ip->i_iopen_gh.gh_flags |= GL_NOCACHE;
gfs2_glock_dq_uninit(&ip->i_iopen_gh); gfs2_glock_dq_uninit(&ip->i_iopen_gh);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment