bz253089 Make gfs2_writepage use trylock on the log_flush lock
PATCH 1/1 bz253089 Make gfs2_writepage use trylock on the log_flush lock
gfs2 was deadlocking because most code paths acquire the sd_log_flush_lock and then the page locks, while code paths going through gfs2_writepage acquire the page locks and then the log flush lock.
This patch makes gfs2_writepage do a trylock on the sd_log_flush_lock. If it fails, writepage simply redirtys the page and gives up. This should keep the deadlock from happening, however it might cause a performance hit.
PATCH 1/1 bz253089 Make gfs2_writepage use trylock on the log_flush lock
Quoted 9 lines · Benjamin Marzinski
gfs2 was deadlocking because most code paths acquire the
sd_log_flush_lockand then the page locks, while code paths going throughgfs2_writepageacquire the page locks and then the log flush lock.This patch makes
gfs2_writepagedo a trylock on thesd_log_flush_lock. If it fails, writepage simply redirtys the page and gives up. This should keep the deadlock from happening, however it might cause a performance hit.Signed-off-by Benjamin E. Marzinski <[email protected]>
And here is the actual patch
-------------- next part --------------
fs/gfs2/log.c +19 -4
@@ -288,7 +288,7 @@ static void ail2_empty(struct gfs2_sbd ** Returns: errno */ -int gfs2_log_reserve (struct gfs2_sbd *sdp,unsigned int blks) +int gfs2_log_reserve (struct gfs2_sbd *sdp,unsigned int blks,int wait) {unsigned int try =0 ;unsigned reserved_blks =6 * (4096 / sdp->sd_vfs->s_blocksize);
@@ -301,6 +301,10 @@ int gfs2_log_reserve(struct gfs2_sbd *sdgfs2_log_lock (sdp);while (sdp->sd_log_blks_free <= (blks + reserved_blks)) {gfs2_log_unlock (sdp); +if (!wait) { +mutex_unlock (&sdp->sd_log_reserve_mutex); +return -EBUSY ; + }gfs2_ail1_empty (sdp,0 );gfs2_log_flush (sdp,NULL );
@@ -310,10 +314,21 @@ int gfs2_log_reserve(struct gfs2_sbd *sd } sdp->sd_log_blks_free -= blks;gfs2_log_unlock (sdp); -mutex_unlock (&sdp->sd_log_reserve_mutex); - -down_read (&sdp->sd_log_flush_lock); +if (wait){ +mutex_unlock (&sdp->sd_log_reserve_mutex); +down_read (&sdp->sd_log_flush_lock); + } +else { +if (!down_read_trylock (&sdp->sd_log_flush_lock)) { +gfs2_log_lock (sdp); + sdp->sd_log_blks_free += blks; +gfs2_log_unlock (sdp); +mutex_unlock (&sdp->sd_log_reserve_mutex); +return -EBUSY ; + } +mutex_unlock (&sdp->sd_log_reserve_mutex); + }return 0 ; }
fs/gfs2/log.h +1 -1
@@ -50,7 +50,7 @@ unsigned int gfs2_struct2blk(struct gfs2int gfs2_ail1_empty (struct gfs2_sbd *sdp,int flags); -int gfs2_log_reserve (struct gfs2_sbd *sdp,unsigned int blks); +int gfs2_log_reserve (struct gfs2_sbd *sdp,unsigned int blks,int wait);void gfs2_log_release (struct gfs2_sbd *sdp,unsigned int blks);struct buffer_head *gfs2_log_get_buf (struct gfs2_sbd *sdp);
fs/gfs2/ops_address.c +1 -1
@@ -140,7 +140,7 @@ static int gfs2_writepage(struct page *pif ((sdp->sd_args.ar_data ==GFS2_DATA_ORDERED ||gfs2_is_jdata (ip)) &&PageChecked (page)) {ClearPageChecked (page); - error =gfs2_trans_begin (sdp,RES_DINODE +1 ,0 ); + error =gfs2_do_trans_begin (sdp,RES_DINODE +1 ,0 ,0 );if (error) goto out_ignore;if (!page_has_buffers (page)) {
fs/gfs2/trans.c +3 -3
@@ -25,8 +25,8 @@#include "trans.h" #include "util.h" -int gfs2_trans_begin (struct gfs2_sbd *sdp,unsigned int blocks, -unsigned int revokes) +int gfs2_do_trans_begin (struct gfs2_sbd *sdp,unsigned int blocks, +unsigned int revokes,int wait) {struct gfs2_trans *tr;int error;
@@ -61,7 +61,7 @@ int gfs2_trans_begin(struct gfs2_sbd *sd goto fail_gunlock; } - error =gfs2_log_reserve (sdp, tr->tr_reserved); + error =gfs2_log_reserve (sdp, tr->tr_reserved, wait);if (error) goto fail_gunlock;
fs/gfs2/trans.h +9 -2
@@ -25,8 +25,8 @@ struct gfs2_glock;#define RES_STATFS 1#define RES_QUOTA 2 -int gfs2_trans_begin (struct gfs2_sbd *sdp,unsigned int blocks, -unsigned int revokes); +int gfs2_do_trans_begin (struct gfs2_sbd *sdp,unsigned int blocks, +unsigned int revokes,int wait);void gfs2_trans_end (struct gfs2_sbd *sdp);
@@ -36,4 +36,11 @@ void gfs2_trans_add_revoke(struct gfs2_svoid gfs2_trans_add_unrevoke (struct gfs2_sbd *sdp,u64 blkno);void gfs2_trans_add_rg (struct gfs2_rgrpd *rgd); + +static inline int gfs2_trans_begin (struct gfs2_sbd *sdp,unsigned int blocks, +unsigned int revokes) +{ +return gfs2_do_trans_begin (sdp, blocks, revokes,1 ); +} +#endif /* __TRANS_DOT_H__ */
PATCH 1/1 bz253089 Make gfs2_writepage use trylock on the log_flush lock
Hi,
Quoted 5 lines · Benjamin Marzinski
Quoted 4 lines · Benjamin Marzinski
gfs2 was deadlocking because most code paths acquire the
sd_log_flush_lockand then the page locks, while code paths going throughgfs2_writepageacquire the page locks and then the log flush lock.
Quoted 8 lines
Quoted 5 lines
This patch makes
gfs2_writepagedo a trylock on thesd_log_flush_lock. If it fails, writepage simply redirtys the page and gives up. This should keep the deadlock from happening, however it might cause a performance hit.Signed-off-by Benjamin E. Marzinski <[email protected]>And here is the actual patch
Now in the -nmw git tree. Thanks,
Steve.
Quoted 122 lines
plain text document attachment (253089_try4.patch)
diff -urpN --exclude-from=linux-2.6.18-44.gfs2abhi.003_test_clean/Documentation/dontdifflinux-2.6.18-44.gfs2abhi.003_test_clean/fs/gfs2/log.clinux-2.6.18-44.gfs2abhi.003_test/fs/gfs2/log.cfs/gfs2/log.c +19
-4@@ -288,7 +288,7 @@ static void ail2_empty(struct gfs2_sbd ** Returns: errno */ -int gfs2_log_reserve (struct gfs2_sbd *sdp,unsigned int blks) +int gfs2_log_reserve (struct gfs2_sbd *sdp,unsigned int blks,int wait) {unsigned int try =0 ;unsigned reserved_blks =6 * (4096 / sdp->sd_vfs->s_blocksize);@@ -301,6 +301,10 @@ int gfs2_log_reserve(struct gfs2_sbd *sdgfs2_log_lock (sdp);while (sdp->sd_log_blks_free <= (blks + reserved_blks)) {gfs2_log_unlock (sdp); +if (!wait) { +mutex_unlock (&sdp->sd_log_reserve_mutex); +return -EBUSY ; + }gfs2_ail1_empty (sdp,0 );gfs2_log_flush (sdp,NULL );@@ -310,10 +314,21 @@ int gfs2_log_reserve(struct gfs2_sbd *sd } sdp->sd_log_blks_free -= blks;gfs2_log_unlock (sdp); -mutex_unlock (&sdp->sd_log_reserve_mutex); - -down_read (&sdp->sd_log_flush_lock); +if (wait){ +mutex_unlock (&sdp->sd_log_reserve_mutex); +down_read (&sdp->sd_log_flush_lock); + } +else { +if (!down_read_trylock (&sdp->sd_log_flush_lock)) { +gfs2_log_lock (sdp); + sdp->sd_log_blks_free += blks; +gfs2_log_unlock (sdp); +mutex_unlock (&sdp->sd_log_reserve_mutex); +return -EBUSY ; + } +mutex_unlock (&sdp->sd_log_reserve_mutex); + }return 0 ; }diff -urpN --exclude-from=linux-2.6.18-44.gfs2abhi.003_test_clean/Documentation/dontdiff
linux-2.6.18-44.gfs2abhi.003_test_clean/fs/gfs2/log.hlinux-2.6.18-44.gfs2abhi.003_test/fs/gfs2/log.hfs/gfs2/log.h +1
-1@@ -50,7 +50,7 @@ unsigned int gfs2_struct2blk(struct gfs2int gfs2_ail1_empty (struct gfs2_sbd *sdp,int flags); -int gfs2_log_reserve (struct gfs2_sbd *sdp,unsigned int blks); +int gfs2_log_reserve (struct gfs2_sbd *sdp,unsigned int blks,int wait);void gfs2_log_release (struct gfs2_sbd *sdp,unsigned int blks);struct buffer_head *gfs2_log_get_buf (struct gfs2_sbd *sdp);diff -urpN --exclude-from=linux-2.6.18-44.gfs2abhi.003_test_clean/Documentation/dontdiff
linux-2.6.18-44.gfs2abhi.003_test_clean/fs/gfs2/ops_address.clinux-2.6.18-44.gfs2abhi.003_test/fs/gfs2/ops_address.cfs/gfs2/ops_address.c +1
-1@@ -140,7 +140,7 @@ static int gfs2_writepage(struct page *pif ((sdp->sd_args.ar_data ==GFS2_DATA_ORDERED ||gfs2_is_jdata (ip)) &&PageChecked (page)) {ClearPageChecked (page); - error =gfs2_trans_begin (sdp,RES_DINODE +1 ,0 ); + error =gfs2_do_trans_begin (sdp,RES_DINODE +1 ,0 ,0 );if (error) goto out_ignore;if (!page_has_buffers (page)) {diff -urpN --exclude-from=linux-2.6.18-44.gfs2abhi.003_test_clean/Documentation/dontdiff
linux-2.6.18-44.gfs2abhi.003_test_clean/fs/gfs2/trans.clinux-2.6.18-44.gfs2abhi.003_test/fs/gfs2/trans.cfs/gfs2/trans.c +3
-3@@ -25,8 +25,8 @@#include "trans.h" #include "util.h" -int gfs2_trans_begin (struct gfs2_sbd *sdp,unsigned int blocks, -unsigned int revokes) +int gfs2_do_trans_begin (struct gfs2_sbd *sdp,unsigned int blocks, +unsigned int revokes,int wait) {struct gfs2_trans *tr;int error;@@ -61,7 +61,7 @@ int gfs2_trans_begin(struct gfs2_sbd *sd goto fail_gunlock; } - error =gfs2_log_reserve (sdp, tr->tr_reserved); + error =gfs2_log_reserve (sdp, tr->tr_reserved, wait);if (error) goto fail_gunlock;diff -urpN --exclude-from=linux-2.6.18-44.gfs2abhi.003_test_clean/Documentation/dontdiff
linux-2.6.18-44.gfs2abhi.003_test_clean/fs/gfs2/trans.hlinux-2.6.18-44.gfs2abhi.003_test/fs/gfs2/trans.hfs/gfs2/trans.h +9
-2@@ -25,8 +25,8 @@ struct gfs2_glock;#define RES_STATFS 1#define RES_QUOTA 2 -int gfs2_trans_begin (struct gfs2_sbd *sdp,unsigned int blocks, -unsigned int revokes); +int gfs2_do_trans_begin (struct gfs2_sbd *sdp,unsigned int blocks, +unsigned int revokes,int wait);void gfs2_trans_end (struct gfs2_sbd *sdp);@@ -36,4 +36,11 @@ void gfs2_trans_add_revoke(struct gfs2_svoid gfs2_trans_add_unrevoke (struct gfs2_sbd *sdp,u64 blkno);void gfs2_trans_add_rg (struct gfs2_rgrpd *rgd); + +static inline int gfs2_trans_begin (struct gfs2_sbd *sdp,unsigned int blocks, +unsigned int revokes) +{ +return gfs2_do_trans_begin (sdp, blocks, revokes,1 ); +} +#endif /* __TRANS_DOT_H__ */