aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ceph/caps.c
diff options
context:
space:
mode:
authorHenry C Chang <henry.cy.chang@gmail.com>2011-05-11 06:29:54 -0400
committerSage Weil <sage@newdream.net>2011-05-11 13:44:48 -0400
commitd3d0720d4a7a46e93e055e5b0f1a8bd612743ed6 (patch)
tree39d657139336012f05d7573116a0ba2405e85de7 /fs/ceph/caps.c
parenta26a185d27b49e1656b335ef8ad1a32f7a0e7d7f (diff)
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>
Diffstat (limited to 'fs/ceph/caps.c')
-rw-r--r--fs/ceph/caps.c16
1 files changed, 8 insertions, 8 deletions
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
index 9fa08662a88d..2a5404c1c42f 100644
--- a/fs/ceph/caps.c
+++ b/fs/ceph/caps.c
@@ -819,7 +819,7 @@ int __ceph_caps_used(struct ceph_inode_info *ci)
819 used |= CEPH_CAP_FILE_CACHE; 819 used |= CEPH_CAP_FILE_CACHE;
820 if (ci->i_wr_ref) 820 if (ci->i_wr_ref)
821 used |= CEPH_CAP_FILE_WR; 821 used |= CEPH_CAP_FILE_WR;
822 if (ci->i_wrbuffer_ref) 822 if (ci->i_wb_ref || ci->i_wrbuffer_ref)
823 used |= CEPH_CAP_FILE_BUFFER; 823 used |= CEPH_CAP_FILE_BUFFER;
824 return used; 824 return used;
825} 825}
@@ -1990,11 +1990,11 @@ static void __take_cap_refs(struct ceph_inode_info *ci, int got)
1990 if (got & CEPH_CAP_FILE_WR) 1990 if (got & CEPH_CAP_FILE_WR)
1991 ci->i_wr_ref++; 1991 ci->i_wr_ref++;
1992 if (got & CEPH_CAP_FILE_BUFFER) { 1992 if (got & CEPH_CAP_FILE_BUFFER) {
1993 if (ci->i_wrbuffer_ref == 0) 1993 if (ci->i_wb_ref == 0)
1994 ihold(&ci->vfs_inode); 1994 ihold(&ci->vfs_inode);
1995 ci->i_wrbuffer_ref++; 1995 ci->i_wb_ref++;
1996 dout("__take_cap_refs %p wrbuffer %d -> %d (?)\n", 1996 dout("__take_cap_refs %p wb %d -> %d (?)\n",
1997 &ci->vfs_inode, ci->i_wrbuffer_ref-1, ci->i_wrbuffer_ref); 1997 &ci->vfs_inode, ci->i_wb_ref-1, ci->i_wb_ref);
1998 } 1998 }
1999} 1999}
2000 2000
@@ -2169,12 +2169,12 @@ void ceph_put_cap_refs(struct ceph_inode_info *ci, int had)
2169 if (--ci->i_rdcache_ref == 0) 2169 if (--ci->i_rdcache_ref == 0)
2170 last++; 2170 last++;
2171 if (had & CEPH_CAP_FILE_BUFFER) { 2171 if (had & CEPH_CAP_FILE_BUFFER) {
2172 if (--ci->i_wrbuffer_ref == 0) { 2172 if (--ci->i_wb_ref == 0) {
2173 last++; 2173 last++;
2174 put++; 2174 put++;
2175 } 2175 }
2176 dout("put_cap_refs %p wrbuffer %d -> %d (?)\n", 2176 dout("put_cap_refs %p wb %d -> %d (?)\n",
2177 inode, ci->i_wrbuffer_ref+1, ci->i_wrbuffer_ref); 2177 inode, ci->i_wb_ref+1, ci->i_wb_ref);
2178 } 2178 }
2179 if (had & CEPH_CAP_FILE_WR) 2179 if (had & CEPH_CAP_FILE_WR)
2180 if (--ci->i_wr_ref == 0) { 2180 if (--ci->i_wr_ref == 0) {