ceph: do not use i_wrbuffer_ref as refcount for Fb cap
We increments i_wrbuffer_ref when taking the Fb cap. This breaks the dirty page accounting and causes looping in __ceph_do_pending_vmtruncate, and ceph client hangs. This bug can be reproduced occasionally by running blogbench. Add a new field i_wb_ref to inode and dedicate it to Fb reference counting. Signed-off-by: Henry C Chang <henry.cy.chang@gmail.com> Signed-off-by: Sage Weil <sage@newdream.net>
This commit is contained in:
parent
a26a185d27
commit
d3d0720d4a
3 changed files with 10 additions and 9 deletions
|
@ -819,7 +819,7 @@ int __ceph_caps_used(struct ceph_inode_info *ci)
|
||||||
used |= CEPH_CAP_FILE_CACHE;
|
used |= CEPH_CAP_FILE_CACHE;
|
||||||
if (ci->i_wr_ref)
|
if (ci->i_wr_ref)
|
||||||
used |= CEPH_CAP_FILE_WR;
|
used |= CEPH_CAP_FILE_WR;
|
||||||
if (ci->i_wrbuffer_ref)
|
if (ci->i_wb_ref || ci->i_wrbuffer_ref)
|
||||||
used |= CEPH_CAP_FILE_BUFFER;
|
used |= CEPH_CAP_FILE_BUFFER;
|
||||||
return used;
|
return used;
|
||||||
}
|
}
|
||||||
|
@ -1990,11 +1990,11 @@ static void __take_cap_refs(struct ceph_inode_info *ci, int got)
|
||||||
if (got & CEPH_CAP_FILE_WR)
|
if (got & CEPH_CAP_FILE_WR)
|
||||||
ci->i_wr_ref++;
|
ci->i_wr_ref++;
|
||||||
if (got & CEPH_CAP_FILE_BUFFER) {
|
if (got & CEPH_CAP_FILE_BUFFER) {
|
||||||
if (ci->i_wrbuffer_ref == 0)
|
if (ci->i_wb_ref == 0)
|
||||||
ihold(&ci->vfs_inode);
|
ihold(&ci->vfs_inode);
|
||||||
ci->i_wrbuffer_ref++;
|
ci->i_wb_ref++;
|
||||||
dout("__take_cap_refs %p wrbuffer %d -> %d (?)\n",
|
dout("__take_cap_refs %p wb %d -> %d (?)\n",
|
||||||
&ci->vfs_inode, ci->i_wrbuffer_ref-1, ci->i_wrbuffer_ref);
|
&ci->vfs_inode, ci->i_wb_ref-1, ci->i_wb_ref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2169,12 +2169,12 @@ void ceph_put_cap_refs(struct ceph_inode_info *ci, int had)
|
||||||
if (--ci->i_rdcache_ref == 0)
|
if (--ci->i_rdcache_ref == 0)
|
||||||
last++;
|
last++;
|
||||||
if (had & CEPH_CAP_FILE_BUFFER) {
|
if (had & CEPH_CAP_FILE_BUFFER) {
|
||||||
if (--ci->i_wrbuffer_ref == 0) {
|
if (--ci->i_wb_ref == 0) {
|
||||||
last++;
|
last++;
|
||||||
put++;
|
put++;
|
||||||
}
|
}
|
||||||
dout("put_cap_refs %p wrbuffer %d -> %d (?)\n",
|
dout("put_cap_refs %p wb %d -> %d (?)\n",
|
||||||
inode, ci->i_wrbuffer_ref+1, ci->i_wrbuffer_ref);
|
inode, ci->i_wb_ref+1, ci->i_wb_ref);
|
||||||
}
|
}
|
||||||
if (had & CEPH_CAP_FILE_WR)
|
if (had & CEPH_CAP_FILE_WR)
|
||||||
if (--ci->i_wr_ref == 0) {
|
if (--ci->i_wr_ref == 0) {
|
||||||
|
|
|
@ -355,6 +355,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
|
||||||
ci->i_rd_ref = 0;
|
ci->i_rd_ref = 0;
|
||||||
ci->i_rdcache_ref = 0;
|
ci->i_rdcache_ref = 0;
|
||||||
ci->i_wr_ref = 0;
|
ci->i_wr_ref = 0;
|
||||||
|
ci->i_wb_ref = 0;
|
||||||
ci->i_wrbuffer_ref = 0;
|
ci->i_wrbuffer_ref = 0;
|
||||||
ci->i_wrbuffer_ref_head = 0;
|
ci->i_wrbuffer_ref_head = 0;
|
||||||
ci->i_shared_gen = 0;
|
ci->i_shared_gen = 0;
|
||||||
|
|
|
@ -293,7 +293,7 @@ struct ceph_inode_info {
|
||||||
|
|
||||||
/* held references to caps */
|
/* held references to caps */
|
||||||
int i_pin_ref;
|
int i_pin_ref;
|
||||||
int i_rd_ref, i_rdcache_ref, i_wr_ref;
|
int i_rd_ref, i_rdcache_ref, i_wr_ref, i_wb_ref;
|
||||||
int i_wrbuffer_ref, i_wrbuffer_ref_head;
|
int i_wrbuffer_ref, i_wrbuffer_ref_head;
|
||||||
u32 i_shared_gen; /* increment each time we get FILE_SHARED */
|
u32 i_shared_gen; /* increment each time we get FILE_SHARED */
|
||||||
u32 i_rdcache_gen; /* incremented each time we get FILE_CACHE. */
|
u32 i_rdcache_gen; /* incremented each time we get FILE_CACHE. */
|
||||||
|
|
Loading…
Reference in a new issue