Pre-pull patch posting
Subsystems (2)
Hi,
Since it seems that another merge window will probably be opening shortly this is a posting of the current content of the GFS2/DLM -nmw git tree.
There are no new features this time, its all fixes and cleanups. I have a few patches that I'm holding back which I'm intending to start off the new -nmw git tree with after this merge, those include:
o Patch to use page_mkwrite() on page faults (and thus allow us to use the filemap_fault() function rather than having a special GFS2 version of this like we do at the moment)
o Patch to clean up gfs2_internal_read() as requested by Christoph Hellwig
o Patches to separate the GFS2 aops into three separate operations structures (for writeback, ordered & jdata) as per ext3 which is waiting for the merge of Nick Piggin's AOP changes so that I don't land up creating a merge conflict.
Anyhow, back to what is in this set of patches... the major area of change is the journalling code where there has been a lot of clean up. Other than that, its mostly fixes for individual bugs and clean ups that other people have sent to me,
Steve.
PATCH 1/51 Fix two races relating to glock callbacks
From: Steven Whitehouse <[email protected]>
One of the races relates to referencing a variable while not holding its protecting spinlock. The patch simply moves the test inside the spin lock. The other races occurs when a demote to unlocked request occurs during the time a demote to shared request is already running. This of course only happens in the case that the lock was in the exclusive mode to start with. The patch adds a check to see if another demote request has occurred in the mean time and if it has, then it performs a second demote.
fs/gfs2/glock.c +18 -6
@@ -545,12 +545,14 @@ static int rq_demote(struct gfs2_glock *gl)return 0 ; }set_bit (GLF_LOCK , &gl->gl_flags); -spin_unlock (&gl->gl_spin);if (gl->gl_demote_state ==LM_ST_UNLOCKED || - gl->gl_state !=LM_ST_EXCLUSIVE ) + gl->gl_state !=LM_ST_EXCLUSIVE ) { +spin_unlock (&gl->gl_spin);gfs2_glock_drop_th (gl); -else + }else { +spin_unlock (&gl->gl_spin);gfs2_glock_xmote_th (gl,NULL ); + }spin_lock (&gl->gl_spin);return 0 ;
@@ -760,10 +762,20 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret)if (!gh) { gl->gl_stamp = jiffies; -if (ret &LM_OUT_CANCELED ) +if (ret &LM_OUT_CANCELED ) { op_done =0 ; -else + }else { +spin_lock (&gl->gl_spin); +if (gl->gl_state != gl->gl_demote_state) { + gl->gl_req_bh =NULL ; +spin_unlock (&gl->gl_spin); +gfs2_glock_drop_th (gl); +gfs2_glock_put (gl); +return ; + }gfs2_demote_wake (gl); +spin_unlock (&gl->gl_spin); + } }else {spin_lock (&gl->gl_spin);list_del_init (&gh->gh_list);
@@ -817,7 +829,7 @@ out:* */ -void gfs2_glock_xmote_th (struct gfs2_glock *gl,struct gfs2_holder *gh) +static void gfs2_glock_xmote_th (struct gfs2_glock *gl,struct gfs2_holder *gh) {struct gfs2_sbd *sdp = gl->gl_sbd;int flags = gh ? gh->gh_flags :0 ;
Signature · 1 line
1.5.1.2
PATCH 2/51 Fix calculation of demote state
From: Josef Whiter <[email protected]>
If a glock is in the exclusive state and a request for demote to deferred has been received, then further requests for demote to shared are being ignored. This patch fixes that by ensuring that we demote to unlocked in that case.
fs/gfs2/glock.c +3 -2
@@ -697,8 +697,9 @@ static void handle_callback(struct gfs2_glock *gl, unsigned int state, int remot }return ; } - }else if (gl->gl_demote_state !=LM_ST_UNLOCKED ) { - gl->gl_demote_state = state; + }else if (gl->gl_demote_state !=LM_ST_UNLOCKED && + gl->gl_demote_state != state) { + gl->gl_demote_state =LM_ST_UNLOCKED ; }spin_unlock (&gl->gl_spin); }
Signature · 1 line
1.5.1.2
PATCH 3/51 Clean up duplicate includes in fs/gfs2/
From: Jesper Juhl <[email protected]>
This patch cleans up duplicate includes in
fs/gfs2/
fs/gfs2/glock.c +0 -2
@@ -25,8 +25,6 @@#include <asm/uaccess.h> #include <linux/seq_file.h> #include <linux/debugfs.h> -#include <linux/module.h> -#include <linux/kallsyms.h> #include "gfs2.h" #include "incore.h"
fs/gfs2/locking/dlm/lock_dlm.h +0 -1
@@ -13,7 +13,6 @@#include <linux/module.h> #include <linux/slab.h> #include <linux/spinlock.h> -#include <linux/module.h> #include <linux/types.h> #include <linux/string.h> #include <linux/list.h>
fs/gfs2/locking/nolock/main.c +0 -1
@@ -9,7 +9,6 @@#include <linux/module.h> #include <linux/slab.h> -#include <linux/module.h> #include <linux/init.h> #include <linux/types.h> #include <linux/fs.h>
Signature · 1 line
1.5.1.2
PATCH 4/51 GFS2 not checking pointer on create when running under nfsd
From: Steve French <[email protected]>
When looking at an unrelated problem, I noticed that nfsd does not set nameidata pointer on create (ie nd is NULL). This should cause an oops in some cases in which when NFSd is mounted over GFS2.
fs/gfs2/ops_inode.c +1 -1
@@ -69,7 +69,7 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry,mark_inode_dirty (inode);break ; }else if (PTR_ERR (inode) != -EEXIST || - (nd->intent.open.flags &O_EXCL )) { + (nd && (nd->intent.open.flags &O_EXCL ))) {gfs2_holder_uninit (ghs);return PTR_ERR (inode); }
Signature · 1 line
1.5.1.2
PATCH 5/51 Fix an oops in glock dumping
From: Steven Whitehouse <[email protected]>
This fixes an oops which was occurring during glock dumping due to the seq file code not taking a reference to the glock. Also this fixes a memory leak which occurred in certain cases, in turn preventing the filesystem from unmounting.
fs/gfs2/glock.c +35 -38
@@ -46,7 +46,6 @@ struct glock_iter {int hash;/* hash bucket index */ struct gfs2_sbd *sdp;/* incore superblock */ struct gfs2_glock *gl;/* current glock struct */ -struct hlist_head *hb_list;/* current hash bucket ptr */ struct seq_file *seq;/* sequence file for debugfs */ char string[512 ];/* scratch space */ };
@@ -1990,47 +1989,38 @@ int __init gfs2_glock_init(void)static int gfs2_glock_iter_next (struct glock_iter *gi) { +struct gfs2_glock *gl; +read_lock (gl_lock_addr (gi->hash)); -while (1 ) { -if (!gi->hb_list) {/* If we don't have a hash bucket yet */ - gi->hb_list = &gl_hash_table[gi->hash].hb_list; -if (hlist_empty (gi->hb_list)) { -read_unlock (gl_lock_addr (gi->hash)); - gi->hash++; -read_lock (gl_lock_addr (gi->hash)); - gi->hb_list =NULL ; -if (gi->hash >=GFS2_GL_HASH_SIZE ) { -read_unlock (gl_lock_addr (gi->hash)); -return 1 ; - } -else -continue ; - } -if (!hlist_empty (gi->hb_list)) { - gi->gl =list_entry (gi->hb_list->first, - struct gfs2_glock, - gl_list); - } - }else { -if (gi->gl->gl_list.next ==NULL ) { -read_unlock (gl_lock_addr (gi->hash)); - gi->hash++; -read_lock (gl_lock_addr (gi->hash)); - gi->hb_list =NULL ; -continue ; - } - gi->gl =list_entry (gi->gl->gl_list.next, - struct gfs2_glock, gl_list); - } + gl = gi->gl; +if (gl) { + gi->gl = hlist_entry(gl->gl_list.next, struct gfs2_glock, + gl_list);if (gi->gl) -break ; +gfs2_glock_hold (gi->gl); }read_unlock (gl_lock_addr (gi->hash)); +if (gl) +gfs2_glock_put (gl); + +while (gi->gl ==NULL ) { + gi->hash++; +if (gi->hash >=GFS2_GL_HASH_SIZE ) +return 1 ; +read_lock (gl_lock_addr (gi->hash)); + gi->gl =hlist_entry (gl_hash_table[gi->hash].hb_list.first, + struct gfs2_glock, gl_list); +if (gi->gl) +gfs2_glock_hold (gi->gl); +read_unlock (gl_lock_addr (gi->hash)); + }return 0 ; }static void gfs2_glock_iter_free (struct glock_iter *gi) { +if (gi->gl) +gfs2_glock_put (gi->gl);kfree (gi); }
@@ -2044,12 +2034,17 @@ static struct glock_iter *gfs2_glock_iter_init(struct gfs2_sbd *sdp) gi->sdp = sdp; gi->hash =0 ; - gi->gl =NULL ; - gi->hb_list =NULL ; gi->seq =NULL ;memset (gi->string,0 ,sizeof (gi->string)); -if (gfs2_glock_iter_next (gi)) { +read_lock (gl_lock_addr (gi->hash)); + gi->gl =hlist_entry (gl_hash_table[gi->hash].hb_list.first, + struct gfs2_glock, gl_list); +if (gi->gl) +gfs2_glock_hold (gi->gl); +read_unlock (gl_lock_addr (gi->hash)); + +if (!gi->gl &&gfs2_glock_iter_next (gi)) {gfs2_glock_iter_free (gi);return NULL ; }
@@ -2066,7 +2061,7 @@ static void *gfs2_glock_seq_start(struct seq_file *file, loff_t *pos)if (!gi)return NULL ; -while (n--) { +while (n--) {if (gfs2_glock_iter_next (gi)) {gfs2_glock_iter_free (gi);return NULL ;
@@ -2093,7 +2088,9 @@ static void *gfs2_glock_seq_next(struct seq_file *file, void *iter_ptr,static void gfs2_glock_seq_stop (struct seq_file *file,void *iter_ptr) { -/* nothing for now */ +struct glock_iter *gi = iter_ptr; +if (gi) +gfs2_glock_iter_free (gi); }static int gfs2_glock_seq_show (struct seq_file *file,void *iter_ptr)
Signature · 1 line
1.5.1.2
PATCH 6/51 Move some code inside the log lock
From: Bob Peterson <[email protected]>
This is the first of five patches for bug #248176:
There were still some critical variables being manipulated outside the log_lock spinlock. That usually resulted in a hang.
fs/gfs2/lops.c +14 -3
@@ -117,7 +117,7 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp)struct buffer_head *bh;struct gfs2_log_descriptor *ld;struct gfs2_bufdata *bd1 =NULL , *bd2; -unsigned int total = sdp->sd_log_num_buf; +unsigned int total;unsigned int offset =BUF_OFFSET ;unsigned int limit;unsigned int num;
@@ -127,12 +127,16 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp) limit =buf_limit (sdp);/* for 4k blocks, limit = 503 */ +gfs2_log_lock (sdp); + total = sdp->sd_log_num_buf; bd1 = bd2 =list_prepare_entry (bd1, &sdp->sd_log_le_buf, bd_le.le_list);while (total) { num = total;if (total > limit) num = limit; +gfs2_log_unlock (sdp); bh =gfs2_log_get_buf (sdp); +gfs2_log_lock (sdp); ld = (struct gfs2_log_descriptor *)bh->b_data; ptr = (__be64 *)(bh->b_data + offset); ld->ld_header.mh_magic =cpu_to_be32 (GFS2_MAGIC );
@@ -152,21 +156,27 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp)break ; } +gfs2_log_unlock (sdp);set_buffer_dirty (bh);ll_rw_block (WRITE ,1 , &bh); +gfs2_log_lock (sdp); n =0 ;list_for_each_entry_continue (bd2, &sdp->sd_log_le_buf, bd_le.le_list) { +gfs2_log_unlock (sdp); bh =gfs2_log_fake_buf (sdp, bd2->bd_bh);set_buffer_dirty (bh);ll_rw_block (WRITE ,1 , &bh); +gfs2_log_lock (sdp);if (++n >= num)break ; } +BUG_ON (total < num); total -= num; } +gfs2_log_unlock (sdp); }static void buf_lo_after_commit (struct gfs2_sbd *sdp,struct gfs2_ail *ai)
@@ -524,7 +534,7 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp)struct gfs2_log_descriptor *ld;unsigned int limit;unsigned int total_dbuf; -unsigned int total_jdata = sdp->sd_log_num_jdata; +unsigned int total_jdata;unsigned int num, n;__be64 *ptr =NULL ;
@@ -536,6 +546,7 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp)*/ gfs2_log_lock (sdp); total_dbuf = sdp->sd_log_num_databuf; + total_jdata = sdp->sd_log_num_jdata; bd2 = bd1 =list_prepare_entry (bd1, &sdp->sd_log_le_databuf, bd_le.le_list);while (total_dbuf) {
@@ -621,10 +632,10 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) }gfs2_log_unlock (sdp);if (bh) { -set_buffer_mapped (bh);set_buffer_dirty (bh);ll_rw_block (WRITE ,1 , &bh); bh =NULL ; + ptr =NULL ; } n =0 ;gfs2_log_lock (sdp);
Signature · 1 line
1.5.1.2
PATCH 7/51 Revert part of earlier log.c changes
From: Bob Peterson <[email protected]>
This is patch 2 of 5 for bug #248176.
The list_move code previously concocted in log.c for bug #238162 (see https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=238162#c23)
never runs as bh can now never be NULL at this point.
fs/gfs2/log.c +2 -11
@@ -83,11 +83,6 @@ static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)gfs2_assert (sdp, bd->bd_ail == ai); -if (!bh){ -list_move (&bd->bd_ail_st_list, &ai->ai_ail2_list); -continue ; - } -if (!buffer_busy (bh)) {if (!buffer_uptodate (bh)) {gfs2_log_unlock (sdp);
@@ -130,11 +125,6 @@ static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int fl bd_ail_st_list) { bh = bd->bd_bh; -if (!bh){ -list_move (&bd->bd_ail_st_list, &ai->ai_ail2_list); -continue ; - } -gfs2_assert (sdp, bd->bd_ail == ai);if (buffer_busy (bh)) {
@@ -155,13 +145,14 @@ static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int flstatic void gfs2_ail1_start (struct gfs2_sbd *sdp,int flags) { -struct list_head *head = &sdp->sd_ail1_list; +struct list_head *head;u64 sync_gen;struct list_head *first;struct gfs2_ail *first_ai, *ai, *tmp;int done =0 ;gfs2_log_lock (sdp); + head = &sdp->sd_ail1_list;if (list_empty (head)) {gfs2_log_unlock (sdp);return ;
Signature · 1 line
1.5.1.2
PATCH 8/51 Prevent infinite loop in try_rgrp_unlink()
From: Bob Peterson <[email protected]>
This is patch three of five for bug #248176.
The try_rgrp_unlink code in rgrp.c had an infinite loop. This was caused because the bitmap function rgblk_search can return a block less than the "goal" block, in which case it was looping. The fix is to make it always march forward as needed.
fs/gfs2/rgrp.c +17 -13
@@ -31,6 +31,7 @@#include "inode.h" #define BFITNOENT ((u32)~0) +#define NO_BLOCK ((u64)~0)/* * These routines are used by the resource group routines (rgrp.c)
@@ -116,8 +117,7 @@ static unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer,* @buffer: the buffer that holds the bitmaps * @buflen: the length (in bytes) of the buffer * @goal: start search at this block's bit-pair (within @buffer) -* @old_state: GFS2_BLKST_XXX the state of the block we're looking for; -* bit 0 = alloc(1)/free(0), bit 1 = meta(1)/data(0) +* @old_state: GFS2_BLKST_XXX the state of the block we're looking for. * * Scope of @goal and returned block number is only within this bitmap buffer, * not entire rgrp or filesystem. @buffer will be offset from the actual
@@ -137,9 +137,13 @@ static u32 gfs2_bitfit(struct gfs2_rgrpd *rgd, unsigned char *buffer, byte = buffer + (goal /GFS2_NBBY ); bit = (goal %GFS2_NBBY ) *GFS2_BIT_SIZE ; end = buffer + buflen; - alloc = (old_state &1 ) ?0 :0x55 ; + alloc = (old_state ==GFS2_BLKST_FREE ) ?0x55 :0 ;while (byte < end) { +/* If we're looking for a free block we can eliminate all +bitmap settings with 0x55, which represents four data +blocks in a row. If we're looking for a data block, we can +eliminate 0x00 which corresponds to four free blocks. */ if ((*byte &0x55 ) == alloc) { blk += (8 - bit) >>1 ;
@@ -859,19 +863,21 @@ static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al)static struct inode *try_rgrp_unlink (struct gfs2_rgrpd *rgd,u64 *last_unlinked) {struct inode *inode; -u32 goal =0 ; +u32 goal =0 , block;u64 no_addr;for (;;) {if (goal >= rgd->rd_data)break ; - goal =rgblk_search (rgd, goal,GFS2_BLKST_UNLINKED , -GFS2_BLKST_UNLINKED ); -if (goal ==BFITNOENT ) + block =rgblk_search (rgd, goal,GFS2_BLKST_UNLINKED , +GFS2_BLKST_UNLINKED ); +if (block ==BFITNOENT )break ; - no_addr = goal + rgd->rd_data0; +/* rgblk_search can return a block < goal, so we need to +keep it marching forward. */ + no_addr = block + rgd->rd_data0; goal++; -if (no_addr < *last_unlinked) +if (*last_unlinked !=NO_BLOCK && no_addr <= *last_unlinked)continue ; *last_unlinked = no_addr; inode = gfs2_inode_lookup(rgd->rd_sbd->sd_vfs, DT_UNKNOWN,
@@ -1152,7 +1158,7 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line)struct gfs2_alloc *al = &ip->i_alloc;struct inode *inode;int error =0 ; -u64 last_unlinked =0 ; +u64 last_unlinked =NO_BLOCK ;if (gfs2_assert_warn (sdp, al->al_requested))return -EINVAL ;
@@ -1305,9 +1311,7 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, goal =0 ; } -if (old_state != new_state) { -gfs2_assert_withdraw (rgd->rd_sbd, blk !=BFITNOENT ); - +if (blk !=BFITNOENT && old_state != new_state) {gfs2_trans_add_bh (rgd->rd_gl, bi->bi_bh,1 );gfs2_setbit (rgd, bi->bi_bh->b_data + bi->bi_offset, bi->bi_len, blk, new_state);
Signature · 1 line
1.5.1.2
PATCH 9/51 use an temp variable to reduce a spin_unlock
From: Denis Cheng <[email protected]>
this is more clear.
fs/gfs2/locking/dlm/plock.c +6 -5
@@ -346,15 +346,16 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,static unsigned int dev_poll (struct file *file,poll_table *wait) { +unsigned int mask =0 ; +poll_wait (file, &send_wq, wait);spin_lock (&ops_lock); -if (!list_empty (&send_list)) { -spin_unlock (&ops_lock); -return POLLIN |POLLRDNORM ; - } +if (!list_empty (&send_list)) + mask =POLLIN |POLLRDNORM ;spin_unlock (&ops_lock); -return 0 ; + +return mask; }static const struct file_operations dev_fops = {
Signature · 1 line
1.5.1.2
PATCH 10/51 Detach buf data during in-place writeback
From: Bob Peterson <[email protected]>
This is patch 5 of 5 for bug #248176
Metadata corruption was occurring because page references weren't being removed in all cases. I previously added a function called detach_bufdata, but I discovered there already WAS a function out there to do the job. It's called gfs2_meta_cache_flush. So I added a call to that to remove the page references.
fs/gfs2/log.c +3 -0
@@ -219,6 +219,7 @@ static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) {struct list_head *head = &ai->ai_ail2_list;struct gfs2_bufdata *bd; +struct gfs2_inode *bh_ip;while (!list_empty (head)) { bd = list_entry(head->prev, struct gfs2_bufdata,
@@ -228,6 +229,8 @@ static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)list_del (&bd->bd_ail_st_list);list_del (&bd->bd_ail_gl_list);atomic_dec (&bd->bd_gl->gl_ail_count); + bh_ip =GFS2_I (bd->bd_bh->b_page->mapping->host); +gfs2_meta_cache_flush (bh_ip);brelse (bd->bd_bh); } }
Signature · 1 line
1.5.1.2
PATCH 11/51 mark struct *_operations const
From: Denis Cheng <[email protected]>
these struct *_operations are all method tables, thus should be const.
fs/gfs2/eaops.c +4 -4
@@ -200,28 +200,28 @@ static int security_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)return gfs2_ea_remove_i (ip, er); } -static struct gfs2_eattr_operations gfs2_user_eaops = { +static const struct gfs2_eattr_operations gfs2_user_eaops = { .eo_get = user_eo_get, .eo_set = user_eo_set, .eo_remove = user_eo_remove, .eo_name ="user" , }; -struct gfs2_eattr_operations gfs2_system_eaops = { +const struct gfs2_eattr_operations gfs2_system_eaops = { .eo_get = system_eo_get, .eo_set = system_eo_set, .eo_remove = system_eo_remove, .eo_name ="system" , }; -static struct gfs2_eattr_operations gfs2_security_eaops = { +static const struct gfs2_eattr_operations gfs2_security_eaops = { .eo_get = security_eo_get, .eo_set = security_eo_set, .eo_remove = security_eo_remove, .eo_name ="security" , }; -struct gfs2_eattr_operations *gfs2_ea_ops[] = { +const struct gfs2_eattr_operations *gfs2_ea_ops[] = {NULL , &gfs2_user_eaops, &gfs2_system_eaops,
fs/gfs2/eaops.h +2 -2
@@ -22,9 +22,9 @@ struct gfs2_eattr_operations {unsigned int gfs2_ea_name2type (const char *name,const char **truncated_name); -extern struct gfs2_eattr_operations gfs2_system_eaops; +extern const struct gfs2_eattr_operations gfs2_system_eaops; -extern struct gfs2_eattr_operations *gfs2_ea_ops[]; +extern const struct gfs2_eattr_operations *gfs2_ea_ops[];#endif /* __EAOPS_DOT_H__ */
fs/gfs2/glock.c +1 -1
@@ -2103,7 +2103,7 @@ static int gfs2_glock_seq_show(struct seq_file *file, void *iter_ptr)return 0 ; } -static struct seq_operations gfs2_glock_seq_ops = { +static const struct seq_operations gfs2_glock_seq_ops = { .start = gfs2_glock_seq_start, .next = gfs2_glock_seq_next, .stop = gfs2_glock_seq_stop,
Signature · 1 line
1.5.1.2
PATCH 12/51 use the declaration of gfs2_dops in the header file instead
From: Denis Cheng <[email protected]>
fs/gfs2/ops_fstype.c +1 -2
@@ -28,6 +28,7 @@#include "lm.h" #include "mount.h" #include "ops_fstype.h" +#include "ops_dentry.h" #include "ops_super.h" #include "recovery.h" #include "rgrp.h"
@@ -38,8 +39,6 @@#define DO 0#define UNDO 1 -extern struct dentry_operations gfs2_dops; -static struct gfs2_sbd *init_sbd (struct super_block *sb) {struct gfs2_sbd *sdp;
Signature · 1 line
1.5.1.2
PATCH 13/51 Reduce number of gfs2_scand processes to one
From: Steven Whitehouse <[email protected]>
We only need a single gfs2_scand process rather than the one per filesystem which we had previously. As a result the parameter determining the frequency of gfs2_scand runs becomes a module parameter rather than a mount parameter as it was before.
fs/gfs2/daemon.c +0 -24
@@ -35,30 +35,6 @@The kthread functions used to start these daemons block and flush signals. */ /** -* gfs2_scand - Look for cached glocks and inodes to toss from memory -* @sdp: Pointer to GFS2 superblock -* -* One of these daemons runs, finding candidates to add to sd_reclaim_list. -* See gfs2_glockd() -*/ - -int gfs2_scand (void *data) -{ -struct gfs2_sbd *sdp = data; -unsigned long t; - -while (!kthread_should_stop ()) { -gfs2_scand_internal (sdp); - t =gfs2_tune_get (sdp, gt_scand_secs) *HZ ; -if (freezing (current)) -refrigerator (); -schedule_timeout_interruptible (t); - } - -return 0 ; -} - -/** * gfs2_glockd - Reclaim unused glock structures * @sdp: Pointer to GFS2 superblock *
fs/gfs2/daemon.h +0 -1
@@ -10,7 +10,6 @@#ifndef __DAEMON_DOT_H__#define __DAEMON_DOT_H__ -int gfs2_scand (void *data);int gfs2_glockd (void *data);int gfs2_recoverd (void *data);int gfs2_logd (void *data);
fs/gfs2/glock.c +48 -15
108 lines not on this page · raw message
fs/gfs2/glock.h +2 -2
@@ -132,11 +132,11 @@ void gfs2_glock_cb(void *cb_data, unsigned int type, void *data);void gfs2_glock_schedule_for_reclaim (struct gfs2_glock *gl);void gfs2_reclaim_glock (struct gfs2_sbd *sdp); - -void gfs2_scand_internal (struct gfs2_sbd *sdp);void gfs2_gl_hash_clear (struct gfs2_sbd *sdp,int wait);int __init gfs2_glock_init (void ); +void gfs2_glock_exit (void ); +int gfs2_create_debugfs_file (struct gfs2_sbd *sdp);void gfs2_delete_debugfs_file (struct gfs2_sbd *sdp);int gfs2_register_debugfs (void );
fs/gfs2/incore.h +0 -2
@@ -429,7 +429,6 @@ struct gfs2_tune {unsigned int gt_log_flush_secs;unsigned int gt_jindex_refresh_secs;/* Check for new journal index */ -unsigned int gt_scand_secs;unsigned int gt_recoverd_secs;unsigned int gt_logd_secs;unsigned int gt_quotad_secs;
@@ -574,7 +573,6 @@ struct gfs2_sbd {/* Daemon stuff */ -struct task_struct *sd_scand_process;struct task_struct *sd_recoverd_process;struct task_struct *sd_logd_process;struct task_struct *sd_quotad_process;
fs/gfs2/main.c +3 -0
@@ -107,6 +107,8 @@ static int __init init_gfs2_fs(void) fail_unregister:unregister_filesystem (&gfs2_fs_type); fail: +gfs2_glock_exit (); +if (gfs2_bufdata_cachep)kmem_cache_destroy (gfs2_bufdata_cachep);
@@ -127,6 +129,7 @@ fail: static void __exit exit_gfs2_fs(void) { +gfs2_glock_exit ();gfs2_unregister_debugfs ();unregister_filesystem (&gfs2_fs_type);unregister_filesystem (&gfs2meta_fs_type);
fs/gfs2/ops_fstype.c +0 -9
@@ -160,14 +160,6 @@ static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh,if (undo) goto fail_trans; - p =kthread_run (gfs2_scand, sdp,"gfs2_scand" ); - error =IS_ERR (p); -if (error) { -fs_err (sdp,"can't start scand thread: %d\n" , error); -return error; - } - sdp->sd_scand_process = p; -for (sdp->sd_glockd_num =0 ; sdp->sd_glockd_num < sdp->sd_args.ar_num_glockd; sdp->sd_glockd_num++) {
@@ -228,7 +220,6 @@ fail:while (sdp->sd_glockd_num--)kthread_stop (sdp->sd_glockd_process[sdp->sd_glockd_num]); -kthread_stop (sdp->sd_scand_process);return error; }
fs/gfs2/ops_super.c +0 -1
@@ -92,7 +92,6 @@ static void gfs2_put_super(struct super_block *sb)kthread_stop (sdp->sd_recoverd_process);while (sdp->sd_glockd_num--)kthread_stop (sdp->sd_glockd_process[sdp->sd_glockd_num]); -kthread_stop (sdp->sd_scand_process);if (!(sb->s_flags &MS_RDONLY )) { error =gfs2_make_fs_ro (sdp);
fs/gfs2/super.c +0 -1
@@ -58,7 +58,6 @@ void gfs2_tune_init(struct gfs2_tune *gt) gt->gt_incore_log_blocks =1024 ; gt->gt_log_flush_secs =60 ; gt->gt_jindex_refresh_secs =60 ; - gt->gt_scand_secs =15 ; gt->gt_recoverd_secs =60 ; gt->gt_logd_secs =1 ; gt->gt_quotad_secs =5 ;
fs/gfs2/sys.c +0 -2
@@ -442,7 +442,6 @@ TUNE_ATTR(quota_simul_sync, 1);TUNE_ATTR (quota_cache_secs,1 );TUNE_ATTR (stall_secs,1 );TUNE_ATTR (statfs_quantum,1 ); -TUNE_ATTR_DAEMON (scand_secs, scand_process);TUNE_ATTR_DAEMON (recoverd_secs, recoverd_process);TUNE_ATTR_DAEMON (logd_secs, logd_process);TUNE_ATTR_DAEMON (quotad_secs, quotad_process);
@@ -464,7 +463,6 @@ static struct attribute *tune_attrs[] = { &tune_attr_quota_cache_secs.attr, &tune_attr_stall_secs.attr, &tune_attr_statfs_quantum.attr, - &tune_attr_scand_secs.attr, &tune_attr_recoverd_secs.attr, &tune_attr_logd_secs.attr, &tune_attr_quotad_secs.attr,
Signature · 1 line
1.5.1.2
PATCH 14/51 invalid metadata block - REVISED
From: Bob Peterson <[email protected]>
This is for bugzilla bug #248176: GFS2: invalid metadata block
Patches 1 thru 3 were accepted upstream, but there were problems with 4 and 5. Those issues have been resolved and now the recovery tests are passing without errors. This code has gone through 41 * 3 successful gfs2 recovery tests before it hit an unrelated (openais) problem.
This is a complete rewrite of patch 4 for bug #248176.
Part of the problem was that inodes were being recycled before their buffers were flushed to the journal logs. Another problem was that the clone bitmaps were being searched for deleted inodes to recycle, but only the "real" bitmaps should be searched for that purpose.
fs/gfs2/rgrp.c +6 -1
@@ -865,12 +865,15 @@ static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked)struct inode *inode;u32 goal =0 , block;u64 no_addr; +struct gfs2_sbd *sdp = rgd->rd_sbd;for (;;) {if (goal >= rgd->rd_data)break ; +down_write (&sdp->sd_log_flush_lock); block =rgblk_search (rgd, goal,GFS2_BLKST_UNLINKED ,GFS2_BLKST_UNLINKED ); +up_write (&sdp->sd_log_flush_lock);if (block ==BFITNOENT )break ;/* rgblk_search can return a block < goal, so we need to
@@ -1295,7 +1298,9 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,allocatable block anywhere else, we want to be able wrap around and search in the first part of our first-searched bit block. */ for (x =0 ; x <= length; x++) { -if (bi->bi_clone) +/* The GFS2_BLKST_UNLINKED state doesn't apply to the clone +bitmaps, so we must search the originals for that. */ +if (old_state !=GFS2_BLKST_UNLINKED && bi->bi_clone) blk =gfs2_bitfit (rgd, bi->bi_clone + bi->bi_offset, bi->bi_len, goal, old_state);else
Signature · 1 line
1.5.1.2
PATCH 15/51 Ensure journal file cache is flushed after recovery
From: Bob Peterson <[email protected]>
This is for bugzilla bug #248176: GFS2: invalid metadata block
Patches 1 thru 3 were accepted upstream, but there were problems with 4 and 5. Those issues have been resolved and now the recovery tests are passing without errors. This code has gone through 41 * 3 successful gfs2 recovery tests before it hit an unrelated (openais) problem. I'm continuing to test it.
This is a complete rewrite of patch 5 for bug #248176, written by Steve Whitehouse. This is referred to in the bugzilla record as "new 6" and "a different solution".
The problem was that the journal inodes, although protected by a glock, were not synched with the other nodes because they don't use the inode glock synch operations (i.e. no "glops" were defined). Therefore, journal recovery on a journal-recovering node were causing the blocks to get out of sync with the node that was actually trying to use that journal as it comes back up from a reboot.
There are two possible solutions: (1) To make the journals use the normal inode glock sync operations, or (2) To make the journal operations take effect immediately (i.e. no caching). Although option 1 works, it turns out to be a lot more code. Steve opted for option 2, which is much simpler and therefore less prone to regression errors.
--
fs/gfs2/ops_fstype.c +1 -1
@@ -358,7 +358,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) ip =GFS2_I (sdp->sd_jdesc->jd_inode); error =gfs2_glock_nq_init (ip->i_gl,LM_ST_SHARED , -LM_FLAG_NOEXP |GL_EXACT , +LM_FLAG_NOEXP |GL_EXACT |GL_NOCACHE , &sdp->sd_jinode_gh);if (error) { fs_err(sdp, "can't acquire journal inode glock: %d\n",
fs/gfs2/recovery.c +1 -1
@@ -469,7 +469,7 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd) }; error =gfs2_glock_nq_init (ip->i_gl,LM_ST_SHARED , -LM_FLAG_NOEXP , &ji_gh); +LM_FLAG_NOEXP |GL_NOCACHE , &ji_gh);if (error) goto fail_gunlock_j; }else {
Signature · 1 line
1.5.1.2
PATCH 16/51 use list_for_each_entry instead
From: Denis Cheng <[email protected]>
fs/gfs2/ops_fstype.c +1 -3
@@ -808,7 +808,6 @@ static struct super_block* get_gfs2_sb(const char *dev_name)struct nameidata nd;struct file_system_type *fstype;struct super_block *sb =NULL , *s; -struct list_head *l;int error; error =path_lookup (dev_name,LOOKUP_FOLLOW , &nd);
@@ -820,8 +819,7 @@ static struct super_block* get_gfs2_sb(const char *dev_name) error =vfs_getattr (nd.mnt, nd.dentry, &stat); fstype =get_fs_type ("gfs2" ); -list_for_each (l, &fstype->fs_supers) { - s = list_entry(l, struct super_block, s_instances); +list_for_each_entry (s, &fstype->fs_supers, s_instances) {if ((S_ISBLK (stat.mode) && s->s_dev == stat.rdev) || (S_ISDIR (stat.mode) && s == nd.dentry->d_inode->i_sb)) { sb = s;
Signature · 1 line
1.5.1.2
PATCH 17/51 unneeded typecast
From: Denis Cheng <[email protected]>
sb->s_fs_info is a void pointer, thus the type cast is not needed.
fs/gfs2/ops_fstype.c +1 -1
@@ -849,7 +849,7 @@ static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags, error = -ENOENT ; goto error; } - sdp = (struct gfs2_sbd *) sb->s_fs_info; + sdp = sb->s_fs_info;if (sdp->sd_vfs_meta) {printk (KERN_WARNING "GFS2: gfs2meta mount already exists\n" ); error = -EBUSY ;
Signature · 1 line
1.5.1.2
PATCH 18/51 better code for translating characters
From: Denis Cheng <[email protected]>
the original code could work, but I think this code could work better.
fs/gfs2/ops_fstype.c +2 -1
@@ -144,7 +144,8 @@ static int init_names(struct gfs2_sbd *sdp, int silent)snprintf (sdp->sd_proto_name,GFS2_FSNAME_LEN ,"%s" , proto);snprintf (sdp->sd_table_name,GFS2_FSNAME_LEN ,"%s" , table); -while ((table =strchr (sdp->sd_table_name,'/' ))) + table = sdp->sd_table_name; +while ((table =strchr (table,'/' ))) *table ='_' ; out:
Signature · 1 line
1.5.1.2
PATCH 19/51 Force unstuff of hidden quota inode
From: Abhijith Das <[email protected]>
This patch forcibly unstuffs (if stuffed) the hidden quota inode at the first availble opportunity. In any practical scenario the quota inode won't be stuffed, so this is ok to do. Unstuffing the quota inode allows us to ignore the case of a stuffed quota inode in gfs2_adjust_quota().
fs/gfs2/quota.c +10 -0
@@ -614,6 +614,16 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,s64 value;int err = -EIO ; +if (gfs2_is_stuffed (ip)) { +struct gfs2_alloc *al =NULL ; + al =gfs2_alloc_get (ip); +/* just request 1 blk */ + al->al_requested =1 ; +gfs2_inplace_reserve (ip); +gfs2_unstuff_dinode (ip,NULL ); +gfs2_inplace_release (ip); +gfs2_alloc_put (ip); + } page =grab_cache_page (mapping, index);if (!page)return -ENOMEM ;
Signature · 1 line
1.5.1.2
PATCH 20/51 fixed a NULL pointer assignment BUG
From: Denis Cheng <[email protected]>
fs/gfs2/ops_fstype.c +3 -2
@@ -292,8 +292,9 @@ static int init_sb(struct gfs2_sbd *sdp, int silent, int undo)fs_err (sdp,"can't get root dentry\n" ); error = -ENOMEM ;iput (inode); - } - sb->s_root->d_op = &gfs2_dops; + }else + sb->s_root->d_op = &gfs2_dops; + out:gfs2_glock_dq_uninit (&sb_gh);return error;
Signature · 1 line
1.5.1.2
PATCH 21/51 Fix quota do_list operation hang
From: Abhijith Das <[email protected]>
This is the filesystem part of the patches to fix this bz. There are additional userland patches (gfs2_quota, libgfs2) for the complete solution. This patch adds a new field qu_ll_next to the gfs2_quota structure. This field allows us to create linked lists of quotas in the ondisk quota inode. Instead of scanning through the entire sparse quota file for valid quotas, we can now simply walk through the user and group quota linked lists to perform the do_list operation.
fs/gfs2/quota.c +3 -0
@@ -70,6 +70,7 @@ struct gfs2_quota_host {u64 qu_limit;u64 qu_warn;s64 qu_value; +u32 qu_ll_next; };struct gfs2_quota_change_host {
@@ -580,6 +581,7 @@ static void gfs2_quota_in(struct gfs2_quota_host *qu, const void *buf) qu->qu_limit =be64_to_cpu (str->qu_limit); qu->qu_warn =be64_to_cpu (str->qu_warn); qu->qu_value =be64_to_cpu (str->qu_value); + qu->qu_ll_next =be32_to_cpu (str->qu_ll_next); }static void gfs2_quota_out (const struct gfs2_quota_host *qu,void *buf)
@@ -589,6 +591,7 @@ static void gfs2_quota_out(const struct gfs2_quota_host *qu, void *buf) str->qu_limit =cpu_to_be64 (qu->qu_limit); str->qu_warn =cpu_to_be64 (qu->qu_warn); str->qu_value =cpu_to_be64 (qu->qu_value); + str->qu_ll_next =cpu_to_be32 (qu->qu_ll_next);memset (&str->qu_reserved,0 ,sizeof (str->qu_reserved)); }
include/linux/gfs2_ondisk.h +29 -1
@@ -170,6 +170,33 @@ struct gfs2_rgrp { };/* +* quota linked list: user quotas and group quotas form two separate +* singly linked lists. ll_next stores uids or gids of next quotas in the +* linked list. + +Given the uid/gid, how to calculate the quota file offsets for the corresponding +gfs2_quota structures on disk: + +for user quotas, given uid, +offset = uid * sizeof(struct gfs2_quota); + +for group quotas, given gid, +offset = (gid * sizeof(struct gfs2_quota)) + sizeof(struct gfs2_quota); + + +uid:0 gid:0 uid:12 gid:12 uid:17 gid:17 uid:5142 gid:5142 ++-------+-------+ +-------+-------+ +-------+- - - -+ +- - - -+-------+ +| valid | valid | :: | valid | valid | :: | valid | inval | :: | inval | valid | ++-------+-------+ +-------+-------+ +-------+- - - -+ +- - - -+-------+ +next:12 next:12 next:17 next:5142 next:NULL next:NULL +| | | | |<-- user quota list | +\______|___________/ \______|___________/ group quota list -->| +| | | +\__________________/ \_______________________________________/ + +*/ + +/* * quota structure */
@@ -177,7 +204,8 @@ struct gfs2_quota {__be64 qu_limit;__be64 qu_warn;__be64 qu_value; -__u8 qu_reserved[64 ]; +__be32 qu_ll_next;/* location of next quota in list */ +__u8 qu_reserved[60 ]; };/*
Signature · 1 line
1.5.1.2
PATCH 22/51 Clean up invalidatepage/releasepage
From: Steven Whitehouse <[email protected]>
This patch fixes some bugs relating to journaled data files by cleaning up the gfs2_invalidatepage() and gfs2_releasepage() functions. We now never block during gfs2_releasepage(), instead we always either release or refuse to release depending on the status of the buffers.
This fixes Red Hat bugzillas #248969 and #252392.
fs/gfs2/glops.c +3 -1
@@ -156,9 +156,11 @@ static void inode_go_sync(struct gfs2_glock *gl) ip =NULL ;if (test_bit (GLF_DIRTY , &gl->gl_flags)) { -if (ip) +if (ip && !gfs2_is_jdata (ip))filemap_fdatawrite (ip->i_inode.i_mapping);gfs2_log_flush (gl->gl_sbd, gl); +if (ip &&gfs2_is_jdata (ip)) +filemap_fdatawrite (ip->i_inode.i_mapping);gfs2_meta_sync (gl);if (ip) {struct address_space *mapping = ip->i_inode.i_mapping;
fs/gfs2/log.c +4 -2
@@ -229,8 +229,10 @@ static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)list_del (&bd->bd_ail_st_list);list_del (&bd->bd_ail_gl_list);atomic_dec (&bd->bd_gl->gl_ail_count); - bh_ip =GFS2_I (bd->bd_bh->b_page->mapping->host); -gfs2_meta_cache_flush (bh_ip); +if (bd->bd_bh->b_page->mapping) { + bh_ip =GFS2_I (bd->bd_bh->b_page->mapping->host); +gfs2_meta_cache_flush (bh_ip); + }brelse (bd->bd_bh); } }
fs/gfs2/ops_address.c +15 -117
176 lines not on this page · raw message
fs/gfs2/ops_fstype.c +2 -0
@@ -35,6 +35,7 @@#include "super.h" #include "sys.h" #include "util.h" +#include "log.h" #define DO 0#define UNDO 1
@@ -887,6 +888,7 @@ error:static void gfs2_kill_sb (struct super_block *sb) {gfs2_delete_debugfs_file (sb->s_fs_info); +gfs2_meta_syncfs (sb->s_fs_info);kill_block_super (sb); }
Signature · 1 line
1.5.1.2
PATCH 23/51 Add a missing gfs2_trans_add_bh()
From: Steven Whitehouse <[email protected]>
This was missing from the dir_split_leaf() function although in most cases its not a problem due to other functions having already previously called gfs2_trans_add_bh. This makes certain that it is correct.
fs/gfs2/dir.c +1 -0
@@ -1043,6 +1043,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) error =gfs2_meta_inode_buffer (dip, &dibh);if (!gfs2_assert_withdraw (GFS2_SB (&dip->i_inode), !error)) { +gfs2_trans_add_bh (dip->i_gl, dibh,1 ); dip->i_di.di_blocks++;gfs2_set_inode_blocks (&dip->i_inode);gfs2_dinode_out (dip, dibh->b_data);
Signature · 1 line
1.5.1.2
PATCH 24/51 Add NULL entry to token table
From: Benjamin Marzinski <[email protected]>
match_token() was returning garbage data instead of a fail value. This data happened to match a valid option id for an option that required an argument (in this case, lockproto=%s) For match_token() to correctly fail if the option doesn't match any of the tokens, the token table must end with a NULL entry. This patch adds the NULL entry.
fs/gfs2/mount.c +4 -1
@@ -42,6 +42,7 @@ enum { Opt_nosuiddir, Opt_data_writeback, Opt_data_ordered, + Opt_err, }; static match_table_t tokens = {
@@ -64,7 +65,8 @@ static match_table_t tokens = { {Opt_suiddir, "suiddir"}, {Opt_nosuiddir, "nosuiddir"}, {Opt_data_writeback, "data=writeback"}, - {Opt_data_ordered, "data=ordered"} + {Opt_data_ordered, "data=ordered"}, + {Opt_err, NULL} };/**
@@ -237,6 +239,7 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount)case Opt_data_ordered: args->ar_data =GFS2_DATA_ORDERED ;break ; +case Opt_err:default :fs_info (sdp,"unknown option: %s\n" , o); error = -EINVAL ;
Signature · 1 line
1.5.1.2
PATCH 25/51 Reduce truncate IO traffic
From: Wendy Cheng <[email protected]>
Current GFS2 setattr call unconditionally invokes do_shrink even the requested size and actual file size are equal. This has generated large amount of extra IOs found during NFS benchmark runs. This patch moves the relevant logic out of shrink code path. Since setattr is a system call, the time stamps update is still required.
fs/gfs2/bmap.c +31 -1
@@ -1085,6 +1085,33 @@ static int do_shrink(struct gfs2_inode *ip, u64 size)return error; } +static int do_touch (struct gfs2_inode *ip,u64 size) +{ +struct gfs2_sbd *sdp =GFS2_SB (&ip->i_inode); +struct buffer_head *dibh; +int error; + + error =gfs2_trans_begin (sdp,RES_DINODE ,0 ); +if (error) +return error; + +down_write (&ip->i_rw_mutex); + + error =gfs2_meta_inode_buffer (ip, &dibh); +if (error) + goto do_touch_out; + + ip->i_inode.i_mtime = ip->i_inode.i_ctime =CURRENT_TIME ; +gfs2_trans_add_bh (ip->i_gl, dibh,1 ); +gfs2_dinode_out (ip, dibh->b_data); +brelse (dibh); + +do_touch_out: +up_write (&ip->i_rw_mutex); +gfs2_trans_end (sdp); +return error; +} +/** * gfs2_truncatei - make a file a given size * @ip: the inode
@@ -1105,8 +1132,11 @@ int gfs2_truncatei(struct gfs2_inode *ip, u64 size)if (size > ip->i_di.di_size) error =do_grow (ip, size); -else +else if (size < ip->i_di.di_size) error =do_shrink (ip, size); +else +/* update time stamps */ + error =do_touch (ip, size);return error; }
Signature · 1 line
1.5.1.2
PATCH 26/51 Fix lowcomms socket closing
From: Patrick Caulfield <[email protected]>
This patch fixes the slight mess made in lowcomms closing by previous patches and fixes all sorts of DLM hangs.
fs/dlm/lowcomms.c +4 -12
@@ -334,18 +334,8 @@ static void close_connection(struct connection *con, bool and_other) con->rx_page =NULL ; } -/* If we are an 'othercon' then NULL the pointer to us -from the parent and tidy ourself up */ -if (test_bit (CF_IS_OTHERCON , &con->flags)) { -struct connection *parent =__nodeid2con (con->nodeid,0 ); - parent->othercon =NULL ; -kmem_cache_free (con_cache, con); - } -else { -/* Parent connections get reused */ - con->retries =0 ; -mutex_unlock (&con->sock_mutex); - } + con->retries =0 ; +mutex_unlock (&con->sock_mutex); }/* We only send shutdown messages to nodes that are not part of the cluster */
@@ -731,6 +721,8 @@ static int tcp_accept_from_sock(struct connection *con)INIT_WORK (&othercon->swork, process_send_sockets);INIT_WORK (&othercon->rwork, process_recv_sockets);set_bit (CF_IS_OTHERCON , &othercon->flags); + } +if (!othercon->sock) { newcon->othercon = othercon; othercon->sock = newsock; newsock->sk->sk_user_data = othercon;
Signature · 1 line
1.5.1.2
PATCH 27/51 Wendy's dump lockname in hex & fix glock dump
From: Abhijith Das <[email protected]>
With this patch, gfs2 glockdump through the debugfs filesystem will only dump glocks for the specified filesystem instead of all glocks. Also, to aid debugging, the glock number is dumped in hex instead of decimal.
fs/gfs2/glock.c +13 -13
@@ -1844,7 +1844,7 @@ static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl)spin_lock (&gl->gl_spin); -print_dbg (gi,"Glock 0x%p (%u, %llu)\n" , gl, gl->gl_name.ln_type, +print_dbg (gi,"Glock 0x%p (%u, 0x%llx)\n" , gl, gl->gl_name.ln_type, (unsigned long long )gl->gl_name.ln_number);print_dbg (gi," gl_flags =" );for (x =0 ; x <32 ; x++) {
@@ -2024,20 +2024,21 @@ static int gfs2_glock_iter_next(struct glock_iter *gi) {struct gfs2_glock *gl; +restart:read_lock (gl_lock_addr (gi->hash)); gl = gi->gl;if (gl) { - gi->gl = hlist_entry(gl->gl_list.next, struct gfs2_glock, - gl_list); + gi->gl =hlist_entry (gl->gl_list.next, + struct gfs2_glock, gl_list);if (gi->gl)gfs2_glock_hold (gi->gl); }read_unlock (gl_lock_addr (gi->hash));if (gl)gfs2_glock_put (gl); - -while (gi->gl ==NULL ) { +if (gl && gi->gl ==NULL ) gi->hash++; +while (gi->gl ==NULL ) {if (gi->hash >=GFS2_GL_HASH_SIZE )return 1 ;read_lock (gl_lock_addr (gi->hash));
@@ -2046,7 +2047,12 @@ static int gfs2_glock_iter_next(struct glock_iter *gi)if (gi->gl)gfs2_glock_hold (gi->gl);read_unlock (gl_lock_addr (gi->hash)); + gi->hash++; } + +if (gi->sdp != gi->gl->gl_sbd) + goto restart; +return 0 ; }
@@ -2068,16 +2074,10 @@ static struct glock_iter *gfs2_glock_iter_init(struct gfs2_sbd *sdp) gi->sdp = sdp; gi->hash =0 ; gi->seq =NULL ; + gi->gl =NULL ;memset (gi->string,0 ,sizeof (gi->string)); -read_lock (gl_lock_addr (gi->hash)); - gi->gl =hlist_entry (gl_hash_table[gi->hash].hb_list.first, - struct gfs2_glock, gl_list); -if (gi->gl) -gfs2_glock_hold (gi->gl); -read_unlock (gl_lock_addr (gi->hash)); - -if (!gi->gl &&gfs2_glock_iter_next (gi)) { +if (gfs2_glock_iter_next (gi)) {gfs2_glock_iter_free (gi);return NULL ; }
Signature · 1 line
1.5.1.2
PATCH 28/51 Patch to protect sd_log_num_jdata
From: Bob Peterson <[email protected]>
This is a patch to GFS2 to protect sd_log_num_jdata with the gfs2_log_lock. Without this patch, there is a timing window where you can get hit the following assert from function gfs2_log_flush():
gfs2_assert_withdraw(sdp,
sdp->sd_log_num_buf + sdp->sd_log_num_jdata == sdp->sd_log_commited_buf + sdp->sd_log_commited_databuf);
I've tested it on my roth cluster and it fixes the problem.
fs/gfs2/lops.c +2 -1
@@ -492,11 +492,12 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)gfs2_trans_add_gl (bd->bd_gl);if (gfs2_is_jdata (ip)) { - sdp->sd_log_num_jdata++;gfs2_pin (sdp, bd->bd_bh); tr->tr_num_databuf_new++; }gfs2_log_lock (sdp); +if (gfs2_is_jdata (ip)) + sdp->sd_log_num_jdata++; sdp->sd_log_num_databuf++;list_add (&le->le_list, &sdp->sd_log_le_databuf);gfs2_log_unlock (sdp);
Signature · 1 line
1.5.1.2
PATCH 29/51 panic after can't parse mount arguments
From: Abhijith Das <[email protected]>
When you try to mount gfs2 with -o garbage, the mount fails and the gfs2 superblock is deallocated and becomes NULL. The vfs comes around later on and calls gfs2_kill_sb. At this point the hidden gfs2 superblock pointer (sb->s_fs_info) is NULL and dereferencing it through gfs2_meta_syncfs causes the panic. (the other function call to gfs2_delete_debugfs_file() succeeds because this function already checks for a NULL pointer)
fs/gfs2/ops_fstype.c +4 -2
@@ -887,8 +887,10 @@ error:static void gfs2_kill_sb (struct super_block *sb) { -gfs2_delete_debugfs_file (sb->s_fs_info); -gfs2_meta_syncfs (sb->s_fs_info); +if (sb->s_fs_info) { +gfs2_delete_debugfs_file (sb->s_fs_info); +gfs2_meta_syncfs (sb->s_fs_info); + }kill_block_super (sb); }
Signature · 1 line
1.5.1.2
PATCH 30/51 delay glock demote for a minimum hold time
From: Benjamin Marzinski <[email protected]>
When a lot of IO, with some distributed mmap IO, is run on a GFS2 filesystem in a cluster, it will deadlock. The reason is that do_no_page() will repeatedly call gfs2_sharewrite_nopage(), because each node keeps giving up the glock too early, and is forced to call unmap_mapping_range(). This bumps the mapping->truncate_count sequence count, forcing do_no_page() to retry. This patch institutes a minimum glock hold time a tenth a second. This insures that even in heavy contention cases, the node has enough time to get some useful work done before it gives up the glock.
A second issue is that when gfs2_glock_dq() is called from within a page fault to demote a lock, and the associated page needs to be written out, it will try to acqire a lock on it, but it has already been locked at a higher level. This patch puts makes gfs2_glock_dq() use the work queue as well, to avoid this issue. This is the same patch as Steve Whitehouse originally proposed to fix this issue, execpt that gfs2_glock_dq() now grabs a reference to the glock before it queues up the work on it.
fs/gfs2/glock.c +59 -16
@@ -27,6 +27,8 @@#include <linux/debugfs.h> #include <linux/kthread.h> #include <linux/freezer.h> +#include <linux/workqueue.h> +#include <linux/jiffies.h> #include "gfs2.h" #include "incore.h"
@@ -58,10 +60,13 @@ static int gfs2_dump_lockstate(struct gfs2_sbd *sdp);static int dump_glock (struct glock_iter *gi,struct gfs2_glock *gl);static void gfs2_glock_xmote_th (struct gfs2_glock *gl,struct gfs2_holder *gh);static void gfs2_glock_drop_th (struct gfs2_glock *gl); +static void run_queue (struct gfs2_glock *gl); +static DECLARE_RWSEM (gfs2_umount_flush_sem);static struct dentry *gfs2_root;static struct task_struct *scand_process;static unsigned int scand_secs =5 ; +static struct workqueue_struct *glock_workqueue;#define GFS2_GL_HASH_SHIFT 15#define GFS2_GL_HASH_SIZE (1 << GFS2_GL_HASH_SHIFT)
@@ -277,6 +282,18 @@ static struct gfs2_glock *gfs2_glock_find(const struct gfs2_sbd *sdp,return gl; } +static void glock_work_func (struct work_struct *work) +{ + struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_work.work); + +spin_lock (&gl->gl_spin); +if (test_and_clear_bit (GLF_PENDING_DEMOTE , &gl->gl_flags)) +set_bit (GLF_DEMOTE , &gl->gl_flags); +run_queue (gl); +spin_unlock (&gl->gl_spin); +gfs2_glock_put (gl); +} +/** * gfs2_glock_get() - Get a glock, or create one if one doesn't exist * @sdp: The GFS2 superblock
@@ -316,6 +333,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, gl->gl_name = name;atomic_set (&gl->gl_ref,1 ); gl->gl_state =LM_ST_UNLOCKED ; + gl->gl_demote_state =LM_ST_EXCLUSIVE ; gl->gl_hash = hash; gl->gl_owner_pid =0 ; gl->gl_ip =0 ;
@@ -324,10 +342,12 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, gl->gl_req_bh =NULL ; gl->gl_vn =0 ; gl->gl_stamp = jiffies; + gl->gl_tchange = jiffies; gl->gl_object =NULL ; gl->gl_sbd = sdp; gl->gl_aspace =NULL ;lops_init_le (&gl->gl_le, &gfs2_glock_lops); +INIT_DELAYED_WORK (&gl->gl_work, glock_work_func);/* If this glock protects actual on-disk data or metadata blocks, create a VFS inode to manage the pages/buffers holding them. */
@@ -441,6 +461,8 @@ static void wait_on_holder(struct gfs2_holder *gh)static void gfs2_demote_wake (struct gfs2_glock *gl) { +BUG_ON (!spin_is_locked (&gl->gl_spin)); + gl->gl_demote_state =LM_ST_EXCLUSIVE ;clear_bit (GLF_DEMOTE , &gl->gl_flags);smp_mb__after_clear_bit ();wake_up_bit (&gl->gl_flags,GLF_DEMOTE );
@@ -682,10 +704,14 @@ static void gfs2_glmutex_unlock(struct gfs2_glock *gl)* practise: LM_ST_SHARED and LM_ST_UNLOCKED */ -static void handle_callback (struct gfs2_glock *gl,unsigned int state,int remote) +static void handle_callback (struct gfs2_glock *gl,unsigned int state, +int remote,unsigned long delay) { +int bit = delay ?GLF_PENDING_DEMOTE :GLF_DEMOTE ; +spin_lock (&gl->gl_spin); -if (test_and_set_bit (GLF_DEMOTE , &gl->gl_flags) ==0 ) { +set_bit (bit, &gl->gl_flags); +if (gl->gl_demote_state ==LM_ST_EXCLUSIVE ) { gl->gl_demote_state = state; gl->gl_demote_time = jiffies; if (remote && gl->gl_ops->go_type == LM_TYPE_IOPEN &&
@@ -727,6 +753,7 @@ static void state_change(struct gfs2_glock *gl, unsigned int new_state) } gl->gl_state = new_state; + gl->gl_tchange = jiffies; }/**
@@ -813,7 +840,6 @@ out: gl->gl_req_gh =NULL ; gl->gl_req_bh =NULL ;clear_bit (GLF_LOCK , &gl->gl_flags); -run_queue (gl);spin_unlock (&gl->gl_spin); }
@@ -885,7 +911,6 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret)gfs2_assert_warn (sdp, !ret);state_change (gl,LM_ST_UNLOCKED ); -gfs2_demote_wake (gl);if (glops->go_inval) glops->go_inval (gl,DIO_METADATA );
@@ -898,10 +923,10 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret) }spin_lock (&gl->gl_spin); +gfs2_demote_wake (gl); gl->gl_req_gh =NULL ; gl->gl_req_bh =NULL ;clear_bit (GLF_LOCK , &gl->gl_flags); -run_queue (gl);spin_unlock (&gl->gl_spin);gfs2_glock_put (gl);
@@ -1209,9 +1234,10 @@ void gfs2_glock_dq(struct gfs2_holder *gh) {struct gfs2_glock *gl = gh->gh_gl;const struct gfs2_glock_operations *glops = gl->gl_ops; +unsigned delay =0 ;if (gh->gh_flags &GL_NOCACHE ) -handle_callback (gl,LM_ST_UNLOCKED ,0 ); +handle_callback (gl,LM_ST_UNLOCKED ,0 ,0 );gfs2_glmutex_lock (gl);
@@ -1229,8 +1255,14 @@ void gfs2_glock_dq(struct gfs2_holder *gh) }clear_bit (GLF_LOCK , &gl->gl_flags); -run_queue (gl);spin_unlock (&gl->gl_spin); + +gfs2_glock_hold (gl); +if (test_bit (GLF_PENDING_DEMOTE , &gl->gl_flags) && + !test_bit (GLF_DEMOTE , &gl->gl_flags)) + delay = gl->gl_ops->go_min_hold_time; +if (queue_delayed_work (glock_workqueue, &gl->gl_work, delay) ==0 ) +gfs2_glock_put (gl); }void gfs2_glock_dq_wait (struct gfs2_holder *gh)
@@ -1457,18 +1489,21 @@ static void blocking_cb(struct gfs2_sbd *sdp, struct lm_lockname *name, unsigned int state) {struct gfs2_glock *gl; +unsigned long delay =0 ; +unsigned long holdtime; +unsigned long now = jiffies; gl =gfs2_glock_find (sdp, name);if (!gl)return ; -handle_callback (gl, state,1 ); - -spin_lock (&gl->gl_spin); -run_queue (gl); -spin_unlock (&gl->gl_spin); + holdtime = gl->gl_tchange + gl->gl_ops->go_min_hold_time; +if (time_before (now, holdtime)) + delay = holdtime - now; -gfs2_glock_put (gl); +handle_callback (gl, state,1 , delay); +if (queue_delayed_work (glock_workqueue, &gl->gl_work, delay) ==0 ) +gfs2_glock_put (gl); }/**
@@ -1509,7 +1544,8 @@ void gfs2_glock_cb(void *cb_data, unsigned int type, void *data)return ;if (!gfs2_assert_warn (sdp, gl->gl_req_bh)) gl->gl_req_bh (gl, async->lc_ret); -gfs2_glock_put (gl); +if (queue_delayed_work (glock_workqueue, &gl->gl_work,0 ) ==0 ) +gfs2_glock_put (gl);up_read (&gfs2_umount_flush_sem);return ; }
@@ -1602,7 +1638,7 @@ void gfs2_reclaim_glock(struct gfs2_sbd *sdp)if (gfs2_glmutex_trylock (gl)) {if (list_empty (&gl->gl_holders) && gl->gl_state !=LM_ST_UNLOCKED &&demote_ok (gl)) -handle_callback (gl,LM_ST_UNLOCKED ,0 ); +handle_callback (gl,LM_ST_UNLOCKED ,0 ,0 );gfs2_glmutex_unlock (gl); }
@@ -1702,7 +1738,7 @@ static void clear_glock(struct gfs2_glock *gl)if (gfs2_glmutex_trylock (gl)) {if (list_empty (&gl->gl_holders) && gl->gl_state !=LM_ST_UNLOCKED ) -handle_callback (gl,LM_ST_UNLOCKED ,0 ); +handle_callback (gl,LM_ST_UNLOCKED ,0 ,0 );gfs2_glmutex_unlock (gl); } }
@@ -2009,11 +2045,18 @@ int __init gfs2_glock_init(void)if (IS_ERR (scand_process))return PTR_ERR (scand_process); + glock_workqueue =create_workqueue ("glock_workqueue" ); +if (IS_ERR (glock_workqueue)) { +kthread_stop (scand_process); +return PTR_ERR (glock_workqueue); + } +return 0 ; }void gfs2_glock_exit (void ) { +destroy_workqueue (glock_workqueue);kthread_stop (scand_process); }
fs/gfs2/glops.c +2 -0
@@ -454,6 +454,7 @@ const struct gfs2_glock_operations gfs2_inode_glops = { .go_lock = inode_go_lock, .go_unlock = inode_go_unlock, .go_type = LM_TYPE_INODE, + .go_min_hold_time = HZ / 10, };const struct gfs2_glock_operations gfs2_rgrp_glops = {
@@ -464,6 +465,7 @@ const struct gfs2_glock_operations gfs2_rgrp_glops = { .go_lock = rgrp_go_lock, .go_unlock = rgrp_go_unlock, .go_type = LM_TYPE_RGRP, + .go_min_hold_time = HZ / 10, };const struct gfs2_glock_operations gfs2_trans_glops = {
fs/gfs2/incore.h +5 -0
@@ -11,6 +11,7 @@#define __INCORE_DOT_H__#include <linux/fs.h> +#include <linux/workqueue.h> #define DIO_WAIT 0x00000010#define DIO_METADATA 0x00000020
@@ -130,6 +131,7 @@ struct gfs2_glock_operations {int (*go_lock) (struct gfs2_holder *gh);void (*go_unlock) (struct gfs2_holder *gh);const int go_type; +const unsigned long go_min_hold_time; };enum {
@@ -161,6 +163,7 @@ enum {GLF_LOCK =1 ,GLF_STICKY =2 ,GLF_DEMOTE =3 , +GLF_PENDING_DEMOTE =4 , GLF_DIRTY = 5, };
@@ -193,6 +196,7 @@ struct gfs2_glock {u64 gl_vn;unsigned long gl_stamp; +unsigned long gl_tchange;void *gl_object;struct list_head gl_reclaim;
@@ -203,6 +207,7 @@ struct gfs2_glock {struct gfs2_log_element gl_le;struct list_head gl_ail_list;atomic_t gl_ail_count; +struct delayed_work gl_work; };struct gfs2_alloc {
Signature · 1 line
1.5.1.2
PATCH 31/51 fix inode meta data corruption
From: Wendy Cheng <[email protected]>
Fix a nasty inode meta data corruption issue by keeping the buffer head in icache array. This buffer needs to stay in memory until journal flush occurs Otherwise, gfs2_meta_inode_buffer could do a disk read before the inode hits disk. It ends up with meta data corruptions. The buffer will be released as part of the existing journal flush logic.
fs/gfs2/inode.c +15 -5
@@ -244,6 +244,11 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)return 0 ; } +static void gfs2_inode_bh (struct gfs2_inode *ip,struct buffer_head *bh) +{ + ip->i_cache[0 ] = bh; +} +/** * gfs2_inode_refresh - Refresh the incore copy of the dinode * @ip: The GFS2 inode
@@ -688,7 +693,7 @@ out:static void init_dinode (struct gfs2_inode *dip,struct gfs2_glock *gl,const struct gfs2_inum_host *inum,unsigned int mode,unsigned int uid,unsigned int gid, -const u64 *generation,dev_t dev) +const u64 *generation,dev_t dev,struct buffer_head **bhp) {struct gfs2_sbd *sdp =GFS2_SB (&dip->i_inode);struct gfs2_dinode *di;
@@ -743,13 +748,15 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, di->di_mtime_nsec =cpu_to_be32 (tv.tv_nsec); di->di_ctime_nsec =cpu_to_be32 (tv.tv_nsec);memset (&di->di_reserved,0 ,sizeof (di->di_reserved)); + +set_buffer_uptodate (dibh); -brelse (dibh); + *bhp = dibh; }static int make_dinode (struct gfs2_inode *dip,struct gfs2_glock *gl,unsigned int mode,const struct gfs2_inum_host *inum, -const u64 *generation,dev_t dev) +const u64 *generation,dev_t dev,struct buffer_head **bhp) {struct gfs2_sbd *sdp =GFS2_SB (&dip->i_inode);unsigned int uid, gid;
@@ -770,7 +777,7 @@ static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,if (error) goto out_quota; -init_dinode (dip, gl, inum, mode, uid, gid, generation, dev); +init_dinode (dip, gl, inum, mode, uid, gid, generation, dev, bhp);gfs2_quota_change (dip,+1 , uid, gid);gfs2_trans_end (sdp);
@@ -909,6 +916,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,struct gfs2_inum_host inum = { .no_addr =0 , .no_formal_ino =0 };int error;u64 generation; +struct buffer_head *bh=NULL ;if (!name->len || name->len >GFS2_FNAMESIZE )return ERR_PTR (-ENAMETOOLONG );
@@ -935,7 +943,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,if (error) goto fail_gunlock; - error =make_dinode (dip, ghs[1 ].gh_gl, mode, &inum, &generation, dev); + error =make_dinode (dip, ghs[1 ].gh_gl, mode, &inum, &generation, dev, &bh);if (error) goto fail_gunlock2;
@@ -945,6 +953,8 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,if (IS_ERR (inode)) goto fail_gunlock2; +gfs2_inode_bh (GFS2_I (inode), bh); + error =gfs2_inode_refresh (GFS2_I (inode));if (error) goto fail_gunlock2;
Signature · 1 line
1.5.1.2
PATCH 32/51 Correct lock ordering in unlink
From: Steven Whitehouse <[email protected]>
This patch corrects the lock ordering in unlink to be the same as that in the rest of GFS2, i.e. parent -> child -> rgrp.
fs/gfs2/ops_inode.c +20 -9
@@ -278,17 +278,25 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)gfs2_holder_init (rgd->rd_gl,LM_ST_EXCLUSIVE ,0 , ghs +2 ); - error =gfs2_glock_nq_m (3 , ghs); + error =gfs2_glock_nq (ghs);/* parent */ if (error) - goto out; + goto out_parent; + + error =gfs2_glock_nq (ghs +1 );/* child */ +if (error) + goto out_child; + + error =gfs2_glock_nq (ghs +2 );/* rgrp */ +if (error) + goto out_rgrp; error =gfs2_unlink_ok (dip, &dentry->d_name, ip);if (error) - goto out_gunlock; + goto out_rgrp; error =gfs2_trans_begin (sdp,2 *RES_DINODE +RES_LEAF +RES_RG_BIT ,0 );if (error) - goto out_gunlock; + goto out_rgrp; error =gfs2_dir_del (dip, &dentry->d_name);if (error)
@@ -298,12 +306,15 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) out_end_trans:gfs2_trans_end (sdp); -out_gunlock: -gfs2_glock_dq_m (3 , ghs); -out: -gfs2_holder_uninit (ghs); -gfs2_holder_uninit (ghs +1 ); +gfs2_glock_dq (ghs +2 ); +out_rgrp:gfs2_holder_uninit (ghs +2 ); +gfs2_glock_dq (ghs +1 ); +out_child: +gfs2_holder_uninit (ghs +1 ); +gfs2_glock_dq (ghs); +out_parent: +gfs2_holder_uninit (ghs);gfs2_glock_dq_uninit (&ri_gh);return error; }
Signature · 1 line
1.5.1.2
PATCH 33/51 Introduce gfs2_remove_from_ail
From: Steven Whitehouse <[email protected]>
This collects together the operations required to remove a gfs2_bufdata from the ail lists. Its only called from two places to start with, but expect to see more of this function in future.
fs/gfs2/glops.c +1 -5
@@ -60,11 +60,7 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl) blkno = bh->b_blocknr;gfs2_assert_withdraw (sdp, !buffer_busy (bh)); - bd->bd_ail =NULL ; -list_del (&bd->bd_ail_st_list); -list_del (&bd->bd_ail_gl_list); -atomic_dec (&gl->gl_ail_count); -brelse (bh); +gfs2_remove_from_ail (NULL , bd);gfs2_log_unlock (sdp);gfs2_trans_add_revoke (sdp, blkno);
fs/gfs2/log.c +21 -10
@@ -60,6 +60,26 @@ unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, }/** +* gfs2_remove_from_ail - Remove an entry from the ail lists, updating counters +* @mapping: The associated mapping (maybe NULL) +* @bd: The gfs2_bufdata to remove +* +* The log lock _must_ be held when calling this function +* +*/ + +void gfs2_remove_from_ail (struct address_space *mapping,struct gfs2_bufdata *bd) +{ + bd->bd_ail =NULL ; +list_del (&bd->bd_ail_st_list); +list_del (&bd->bd_ail_gl_list); +atomic_dec (&bd->bd_gl->gl_ail_count); +if (mapping) +gfs2_meta_cache_flush (GFS2_I (mapping->host)); +brelse (bd->bd_bh); +} + +/** * gfs2_ail1_start_one - Start I/O on a part of the AIL * @sdp: the filesystem * @tr: the part of the AIL
@@ -219,21 +239,12 @@ static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) {struct list_head *head = &ai->ai_ail2_list;struct gfs2_bufdata *bd; -struct gfs2_inode *bh_ip;while (!list_empty (head)) { bd = list_entry(head->prev, struct gfs2_bufdata, bd_ail_st_list);gfs2_assert (sdp, bd->bd_ail == ai); - bd->bd_ail =NULL ; -list_del (&bd->bd_ail_st_list); -list_del (&bd->bd_ail_gl_list); -atomic_dec (&bd->bd_gl->gl_ail_count); -if (bd->bd_bh->b_page->mapping) { - bh_ip =GFS2_I (bd->bd_bh->b_page->mapping->host); -gfs2_meta_cache_flush (bh_ip); - } -brelse (bd->bd_bh); +gfs2_remove_from_ail (bd->bd_bh->b_page->mapping, bd); } }
fs/gfs2/log.h +1 -0
@@ -58,6 +58,7 @@ struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp, struct buffer_head *real);void gfs2_log_flush (struct gfs2_sbd *sdp,struct gfs2_glock *gl);void gfs2_log_commit (struct gfs2_sbd *sdp,struct gfs2_trans *trans); +void gfs2_remove_from_ail (struct address_space *mapping,struct gfs2_bufdata *bd);void gfs2_log_shutdown (struct gfs2_sbd *sdp);void gfs2_meta_syncfs (struct gfs2_sbd *sdp);
Signature · 1 line
1.5.1.2
PATCH 34/51 Don't mark jdata dirty in gfs2_unstuffer_page()
From: Steven Whitehouse <[email protected]>
Journaled data is marked dirty by gfs2_unpin and should not be marked dirty here.
fs/gfs2/bmap.c +2 -1
@@ -95,7 +95,8 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,set_buffer_uptodate (bh);if (sdp->sd_args.ar_data ==GFS2_DATA_ORDERED ||gfs2_is_jdata (ip))gfs2_trans_add_bh (ip->i_gl, bh,0 ); -mark_buffer_dirty (bh); +if (!gfs2_is_jdata (ip)) +mark_buffer_dirty (bh);if (release) {unlock_page (page);
Signature · 1 line
1.5.1.2
PATCH 35/51 Move pin/unpin into lops.c, clean up locking
From: Steven Whitehouse <[email protected]>
gfs2_pin and gfs2_unpin are only used in lops.c, despite being defined in meta_io.c, so this patch moves them into lops.c and makes them static. At the same time, its possible to clean up the locking in the buf and databuf _lo_add() functions so that we only need to grab the spinlock once. Also we have to move lock_buffer() around the _lo_add() functions since we can't do that in gfs2_pin() any more since we hold the spinlock for the duration of that function.
As a result, the code shrinks by 12 lines and we do far fewer operations when adding buffers to the log. It also makes the code somewhat easier to read & understand.
fs/gfs2/lops.c +89 -28
@@ -27,7 +27,71 @@#include "trans.h" #include "util.h" -static void glock_lo_add (struct gfs2_sbd *sdp,struct gfs2_log_element *le) +/** +* gfs2_pin - Pin a buffer in memory +* @sdp: The superblock +* @bh: The buffer to be pinned +* +* The log lock must be held when calling this function +*/ +static void gfs2_pin (struct gfs2_sbd *sdp,struct buffer_head *bh) +{ +struct gfs2_bufdata *bd; + +gfs2_assert_withdraw (sdp,test_bit (SDF_JOURNAL_LIVE , &sdp->sd_flags)); + +clear_buffer_dirty (bh); +if (test_set_buffer_pinned (bh)) +gfs2_assert_withdraw (sdp,0 ); +if (!buffer_uptodate (bh)) +gfs2_io_error_bh (sdp, bh); + bd = bh->b_private; +/* If this buffer is in the AIL and it has already been written +* to in-place disk block, remove it from the AIL. +*/ +if (bd->bd_ail) +list_move (&bd->bd_ail_st_list, &bd->bd_ail->ai_ail2_list); +get_bh (bh); +} + +/** +* gfs2_unpin - Unpin a buffer +* @sdp: the filesystem the buffer belongs to +* @bh: The buffer to unpin +* @ai: +* +*/ + +static void gfs2_unpin (struct gfs2_sbd *sdp,struct buffer_head *bh, +struct gfs2_ail *ai) +{ +struct gfs2_bufdata *bd = bh->b_private; + +gfs2_assert_withdraw (sdp,buffer_uptodate (bh)); + +if (!buffer_pinned (bh)) +gfs2_assert_withdraw (sdp,0 ); + +lock_buffer (bh); +mark_buffer_dirty (bh); +clear_buffer_pinned (bh); + +gfs2_log_lock (sdp); +if (bd->bd_ail) { +list_del (&bd->bd_ail_st_list); +brelse (bh); + }else { +struct gfs2_glock *gl = bd->bd_gl; +list_add (&bd->bd_ail_gl_list, &gl->gl_ail_list); +atomic_inc (&gl->gl_ail_count); + } + bd->bd_ail = ai; +list_add (&bd->bd_ail_st_list, &ai->ai_ail1_list); +gfs2_log_unlock (sdp); +unlock_buffer (bh); +} + +static void __glock_lo_add (struct gfs2_sbd *sdp,struct gfs2_log_element *le) {struct gfs2_glock *gl;struct gfs2_trans *tr = current->journal_info;
@@ -38,15 +102,19 @@ static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)if (gfs2_assert_withdraw (sdp,gfs2_glock_is_held_excl (gl)))return ; -gfs2_log_lock (sdp); -if (!list_empty (&le->le_list)){ -gfs2_log_unlock (sdp); +if (!list_empty (&le->le_list))return ; - } +gfs2_glock_hold (gl);set_bit (GLF_DIRTY , &gl->gl_flags); sdp->sd_log_num_gl++;list_add (&le->le_list, &sdp->sd_log_le_gl); +} + +static void glock_lo_add (struct gfs2_sbd *sdp,struct gfs2_log_element *le) +{ +gfs2_log_lock (sdp); +__glock_lo_add (sdp, le);gfs2_log_unlock (sdp); }
@@ -71,30 +139,25 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le);struct gfs2_trans *tr; +lock_buffer (bd->bd_bh);gfs2_log_lock (sdp); -if (!list_empty (&bd->bd_list_tr)) { -gfs2_log_unlock (sdp); -return ; - } +if (!list_empty (&bd->bd_list_tr)) + goto out; tr = current->journal_info; tr->tr_touched =1 ; tr->tr_num_buf++;list_add (&bd->bd_list_tr, &tr->tr_list_buf); -gfs2_log_unlock (sdp); -if (!list_empty (&le->le_list)) -return ; - -gfs2_trans_add_gl (bd->bd_gl); - + goto out; +__glock_lo_add (sdp, &bd->bd_gl->gl_le);gfs2_meta_check (sdp, bd->bd_bh);gfs2_pin (sdp, bd->bd_bh); -gfs2_log_lock (sdp); sdp->sd_log_num_buf++;list_add (&le->le_list, &sdp->sd_log_le_buf); -gfs2_log_unlock (sdp); - tr->tr_num_buf_new++; +out: +gfs2_log_unlock (sdp); +unlock_buffer (bd->bd_bh); }static void buf_lo_incore_commit (struct gfs2_sbd *sdp,struct gfs2_trans *tr)
@@ -476,31 +539,29 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)struct address_space *mapping = bd->bd_bh->b_page->mapping;struct gfs2_inode *ip =GFS2_I (mapping->host); +lock_buffer (bd->bd_bh);gfs2_log_lock (sdp); -if (!list_empty (&bd->bd_list_tr)) { -gfs2_log_unlock (sdp); -return ; - } +if (!list_empty (&bd->bd_list_tr)) + goto out; tr->tr_touched =1 ;if (gfs2_is_jdata (ip)) { tr->tr_num_buf++;list_add (&bd->bd_list_tr, &tr->tr_list_buf); } -gfs2_log_unlock (sdp);if (!list_empty (&le->le_list)) -return ; + goto out; -gfs2_trans_add_gl (bd->bd_gl); +__glock_lo_add (sdp, &bd->bd_gl->gl_le);if (gfs2_is_jdata (ip)) {gfs2_pin (sdp, bd->bd_bh); tr->tr_num_databuf_new++; - } -gfs2_log_lock (sdp); -if (gfs2_is_jdata (ip)) sdp->sd_log_num_jdata++; + } sdp->sd_log_num_databuf++;list_add (&le->le_list, &sdp->sd_log_le_databuf); +out:gfs2_log_unlock (sdp); +unlock_buffer (bd->bd_bh); }static int gfs2_check_magic (struct buffer_head *bh)
fs/gfs2/meta_io.c +0 -70
76 lines not on this page · raw message
fs/gfs2/meta_io.h +0 -3
@@ -50,9 +50,6 @@ int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh);void gfs2_attach_bufdata (struct gfs2_glock *gl,struct buffer_head *bh,int meta); -void gfs2_pin (struct gfs2_sbd *sdp,struct buffer_head *bh); -void gfs2_unpin (struct gfs2_sbd *sdp,struct buffer_head *bh, -struct gfs2_ail *ai);void gfs2_meta_wipe (struct gfs2_inode *ip,u64 bstart,u32 blen);
Signature · 1 line
1.5.1.2
PATCH 36/51 Clean up ordered write code
From: Steven Whitehouse <[email protected]>
The following patch removes the ordered write processing from databuf_lo_before_commit() and moves it to log.c. This has the effect of greatly simplyfying databuf_lo_before_commit() and well as potentially making the ordered write code more efficient.
As a side effect of this, its now possible to remove ordered buffers from the ordered buffer list at any time, so we now make use of this in invalidatepage and releasepage to ensure timely release of these buffers.
fs/gfs2/incore.h +1 -1
@@ -612,13 +612,13 @@ struct gfs2_sbd {unsigned int sd_log_num_revoke;unsigned int sd_log_num_rg;unsigned int sd_log_num_databuf; -unsigned int sd_log_num_jdata;struct list_head sd_log_le_gl;struct list_head sd_log_le_buf;struct list_head sd_log_le_revoke;struct list_head sd_log_le_rg;struct list_head sd_log_le_databuf; +struct list_head sd_log_le_ordered;unsigned int sd_log_blks_free;struct mutex sd_log_reserve_mutex;
fs/gfs2/log.c +55 -2
82 lines not on this page · raw message
fs/gfs2/lops.c +40 -120
209 lines not on this page · raw message
fs/gfs2/ops_address.c +46 -4
68 lines not on this page · raw message
fs/gfs2/ops_fstype.c +1 -0
@@ -82,6 +82,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)INIT_LIST_HEAD (&sdp->sd_log_le_revoke);INIT_LIST_HEAD (&sdp->sd_log_le_rg);INIT_LIST_HEAD (&sdp->sd_log_le_databuf); +INIT_LIST_HEAD (&sdp->sd_log_le_ordered);mutex_init (&sdp->sd_log_reserve_mutex);INIT_LIST_HEAD (&sdp->sd_ail1_list);
Signature · 1 line
1.5.1.2
PATCH 37/51 Fix ordering of dirty/journal for ordered buffer unstuffing
From: Bob Peterson <[email protected]>
fs/gfs2/bmap.c +2 -2
@@ -93,10 +93,10 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,map_bh (bh, inode->i_sb, block);set_buffer_uptodate (bh); -if (sdp->sd_args.ar_data ==GFS2_DATA_ORDERED ||gfs2_is_jdata (ip)) -gfs2_trans_add_bh (ip->i_gl, bh,0 );if (!gfs2_is_jdata (ip))mark_buffer_dirty (bh); +if (sdp->sd_args.ar_data ==GFS2_DATA_ORDERED ||gfs2_is_jdata (ip)) +gfs2_trans_add_bh (ip->i_gl, bh,0 );if (release) {unlock_page (page);
Signature · 1 line
1.5.1.2
PATCH 38/51 Replace revoke structure with bufdata structure
From: Steven Whitehouse <[email protected]>
Both the revoke structure and the bufdata structure are quite similar. They are basically small tags which are put on lists. In addition to which the revoke structure is always allocated when there is a bufdata structure which is (or can be) freed. As such it should be possible to reduce the number of frees and allocations by using the same structure for both purposes.
This patch is the first step along that path. It replaces existing uses of the revoke structure with the bufdata structure.
fs/gfs2/incore.h +7 -6
@@ -114,7 +114,13 @@ struct gfs2_bufdata {struct buffer_head *bd_bh;struct gfs2_glock *bd_gl; -struct list_head bd_list_tr; +union { +struct list_head list_tr; +u64 blkno; + } u; +#define bd_list_tr u.list_tr +#define bd_blkno u.blkno +struct gfs2_log_element bd_le;struct gfs2_ail *bd_ail;
@@ -298,11 +304,6 @@ struct gfs2_file {struct gfs2_holder f_fl_gh; }; -struct gfs2_revoke { -struct gfs2_log_element rv_le; -u64 rv_blkno; -}; -struct gfs2_revoke_replay {struct list_head rr_list;u64 rr_blkno;
fs/gfs2/lops.c +5 -5
@@ -357,7 +357,7 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp)struct buffer_head *bh;unsigned int offset;struct list_head *head = &sdp->sd_log_le_revoke; -struct gfs2_revoke *rv; +struct gfs2_bufdata *bd;if (!sdp->sd_log_num_revoke)return ;
@@ -376,8 +376,8 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) offset =sizeof (struct gfs2_log_descriptor );while (!list_empty (head)) { - rv = list_entry(head->next, struct gfs2_revoke, rv_le.le_list); -list_del_init (&rv->rv_le.le_list); + bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list); +list_del_init (&bd->bd_le.le_list); sdp->sd_log_num_revoke--;if (offset +sizeof (u64) > sdp->sd_sb.sb_bsize) {
@@ -392,8 +392,8 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) offset =sizeof (struct gfs2_meta_header ); } - *(__be64 *)(bh->b_data + offset) =cpu_to_be64 (rv->rv_blkno); -kfree (rv); + *(__be64 *)(bh->b_data + offset) =cpu_to_be64 (bd->bd_blkno); +kfree (bd); offset +=sizeof (u64); }
fs/gfs2/trans.c +10 -10
@@ -144,23 +144,23 @@ void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta)void gfs2_trans_add_revoke (struct gfs2_sbd *sdp,u64 blkno) { -struct gfs2_revoke *rv =kmalloc (sizeof (struct gfs2_revoke ), -GFP_NOFS | __GFP_NOFAIL); -lops_init_le (&rv->rv_le, &gfs2_revoke_lops); - rv->rv_blkno = blkno; -lops_add (sdp, &rv->rv_le); +struct gfs2_bufdata *bd =kmalloc (sizeof (struct gfs2_bufdata ), +GFP_NOFS | __GFP_NOFAIL); +lops_init_le (&bd->bd_le, &gfs2_revoke_lops); + bd->bd_blkno = blkno; +lops_add (sdp, &bd->bd_le); }void gfs2_trans_add_unrevoke (struct gfs2_sbd *sdp,u64 blkno) { -struct gfs2_revoke *rv; +struct gfs2_bufdata *bd;int found =0 ;gfs2_log_lock (sdp); -list_for_each_entry (rv, &sdp->sd_log_le_revoke, rv_le.le_list) { -if (rv->rv_blkno == blkno) { -list_del (&rv->rv_le.le_list); +list_for_each_entry (bd, &sdp->sd_log_le_revoke, bd_le.le_list) { +if (bd->bd_blkno == blkno) { +list_del (&bd->bd_le.le_list);gfs2_assert_withdraw (sdp, sdp->sd_log_num_revoke); sdp->sd_log_num_revoke--; found =1 ;
@@ -172,7 +172,7 @@ void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno)if (found) {struct gfs2_trans *tr = current->journal_info; -kfree (rv); +kfree (bd); tr->tr_num_revoke_rm++; } }
Signature · 1 line
1.5.1.2
PATCH 39/51 Use slab operations for all gfs2_bufdata allocations
From: Steven Whitehouse <[email protected]>
The old revoke structure was allocated using kalloc/kfree but there is a slab cache for gfs2_bufdata, so we should use that now that the structures have been converted.
This is part two of the patch series to merge the revoke and gfs2_bufdata structures.
fs/gfs2/lops.c +1 -1
@@ -393,7 +393,7 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) } *(__be64 *)(bh->b_data + offset) =cpu_to_be64 (bd->bd_blkno); -kfree (bd); +kmem_cache_free (gfs2_bufdata_cachep, bd); offset +=sizeof (u64); }
fs/gfs2/trans.c +2 -2
@@ -144,7 +144,7 @@ void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta)void gfs2_trans_add_revoke (struct gfs2_sbd *sdp,u64 blkno) { -struct gfs2_bufdata *bd =kmalloc (sizeof (struct gfs2_bufdata ), +struct gfs2_bufdata *bd =kmem_cache_alloc (gfs2_bufdata_cachep,GFP_NOFS | __GFP_NOFAIL);lops_init_le (&bd->bd_le, &gfs2_revoke_lops); bd->bd_blkno = blkno;
@@ -172,7 +172,7 @@ void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno)if (found) {struct gfs2_trans *tr = current->journal_info; -kfree (bd); +kmem_cache_free (gfs2_bufdata_cachep, bd); tr->tr_num_revoke_rm++; } }
Signature · 1 line
1.5.1.2
PATCH 40/51 Clean up gfs2_trans_add_revoke()
From: Steven Whitehouse <[email protected]>
The following alters gfs2_trans_add_revoke() to take a struct gfs2_bufdata as an argument. This eliminates the memory allocation which was previously required by making use of the already existing struct gfs2_bufdata. It makes some sanity checks to ensure that the gfs2_bufdata has been removed from all the lists before its recycled as a revoke structure. This saves one memory allocation and one free per revoke structure.
Also as a result, and to simplify the locking, since there is no longer any blocking code in gfs2_trans_add_revoke() we must hold the log lock whenever this function is called. This reduces the amount of times we take and unlock the log lock.
fs/gfs2/glops.c +5 -9
@@ -41,7 +41,6 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl)struct list_head *head = &gl->gl_ail_list;struct gfs2_bufdata *bd;struct buffer_head *bh; -u64 blkno;int error; blocks =atomic_read (&gl->gl_ail_count);
@@ -57,15 +56,12 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl) bd = list_entry(head->next, struct gfs2_bufdata, bd_ail_gl_list); bh = bd->bd_bh; - blkno = bh->b_blocknr; -gfs2_assert_withdraw (sdp, !buffer_busy (bh)); -gfs2_remove_from_ail (NULL , bd); -gfs2_log_unlock (sdp); - -gfs2_trans_add_revoke (sdp, blkno); - -gfs2_log_lock (sdp); + bd->bd_bh =NULL ; + bh->b_private =NULL ; + bd->bd_blkno = bh->b_blocknr; +gfs2_assert_withdraw (sdp, !buffer_busy (bh)); +gfs2_trans_add_revoke (sdp, bd); }gfs2_assert_withdraw (sdp, !atomic_read (&gl->gl_ail_count));gfs2_log_unlock (sdp);
fs/gfs2/log.c +2 -2
@@ -71,8 +71,8 @@ unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,void gfs2_remove_from_ail (struct address_space *mapping,struct gfs2_bufdata *bd) { bd->bd_ail =NULL ; -list_del (&bd->bd_ail_st_list); -list_del (&bd->bd_ail_gl_list); +list_del_init (&bd->bd_ail_st_list); +list_del_init (&bd->bd_ail_gl_list);atomic_dec (&bd->bd_gl->gl_ail_count);if (mapping)gfs2_meta_cache_flush (GFS2_I (mapping->host));
fs/gfs2/lops.c +0 -3
@@ -343,11 +343,8 @@ static void revoke_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) tr = current->journal_info; tr->tr_touched =1 ; tr->tr_num_revoke++; - -gfs2_log_lock (sdp); sdp->sd_log_num_revoke++;list_add (&le->le_list, &sdp->sd_log_le_revoke); -gfs2_log_unlock (sdp); }static void revoke_lo_before_commit (struct gfs2_sbd *sdp)
fs/gfs2/meta_io.c +12 -23
@@ -313,42 +313,31 @@ void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen)while (blen) { bh =getbuf (ip->i_gl, bstart,NO_CREATE );if (bh) { -struct gfs2_bufdata *bd = bh->b_private; +struct gfs2_bufdata *bd; +lock_buffer (bh); +gfs2_log_lock (sdp); + bd = bh->b_private;if (test_clear_buffer_pinned (bh)) {struct gfs2_trans *tr = current->journal_info; -struct gfs2_inode *bh_ip = -GFS2_I (bh->b_page->mapping->host); - -gfs2_log_lock (sdp);list_del_init (&bd->bd_le.le_list);gfs2_assert_warn (sdp, sdp->sd_log_num_buf); sdp->sd_log_num_buf--; -gfs2_log_unlock (sdp); -if (bh_ip->i_inode.i_private !=NULL ) - tr->tr_num_databuf_rm++; -else - tr->tr_num_buf_rm++; + tr->tr_num_buf_rm++;brelse (bh); }if (bd) { -gfs2_log_lock (sdp);if (bd->bd_ail) { -u64 blkno = bh->b_blocknr; - bd->bd_ail =NULL ; -list_del (&bd->bd_ail_st_list); -list_del (&bd->bd_ail_gl_list); -atomic_dec (&bd->bd_gl->gl_ail_count); -brelse (bh); -gfs2_log_unlock (sdp); -gfs2_trans_add_revoke (sdp, blkno); - }else -gfs2_log_unlock (sdp); +gfs2_remove_from_ail (NULL , bd); + bh->b_private =NULL ; + bd->bd_bh =NULL ; + bd->bd_blkno = bh->b_blocknr; +gfs2_trans_add_revoke (sdp, bd); + } } - -lock_buffer (bh);clear_buffer_dirty (bh);clear_buffer_uptodate (bh); +gfs2_log_unlock (sdp);unlock_buffer (bh);brelse (bh);
fs/gfs2/trans.c +5 -5
@@ -142,12 +142,12 @@ void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta)lops_add (sdp, &bd->bd_le); } -void gfs2_trans_add_revoke (struct gfs2_sbd *sdp,u64 blkno) +void gfs2_trans_add_revoke (struct gfs2_sbd *sdp,struct gfs2_bufdata *bd) { -struct gfs2_bufdata *bd =kmem_cache_alloc (gfs2_bufdata_cachep, -GFP_NOFS | __GFP_NOFAIL); +BUG_ON (!list_empty (&bd->bd_le.le_list)); +BUG_ON (!list_empty (&bd->bd_ail_st_list)); +BUG_ON (!list_empty (&bd->bd_ail_gl_list));lops_init_le (&bd->bd_le, &gfs2_revoke_lops); - bd->bd_blkno = blkno;lops_add (sdp, &bd->bd_le); }
@@ -160,7 +160,7 @@ void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno)list_for_each_entry (bd, &sdp->sd_log_le_revoke, bd_le.le_list) {if (bd->bd_blkno == blkno) { -list_del (&bd->bd_le.le_list); +list_del_init (&bd->bd_le.le_list);gfs2_assert_withdraw (sdp, sdp->sd_log_num_revoke); sdp->sd_log_num_revoke--; found =1 ;
fs/gfs2/trans.h +1 -1
@@ -32,7 +32,7 @@ void gfs2_trans_end(struct gfs2_sbd *sdp);void gfs2_trans_add_gl (struct gfs2_glock *gl);void gfs2_trans_add_bh (struct gfs2_glock *gl,struct buffer_head *bh,int meta); -void gfs2_trans_add_revoke (struct gfs2_sbd *sdp,u64 blkno); +void gfs2_trans_add_revoke (struct gfs2_sbd *sdp,struct gfs2_bufdata *bd);void gfs2_trans_add_unrevoke (struct gfs2_sbd *sdp,u64 blkno);void gfs2_trans_add_rg (struct gfs2_rgrpd *rgd);
Signature · 1 line
1.5.1.2
PATCH 41/51 flocks from same process trip kernel BUG at fs/gfs2/glock.c:1118!
From: Abhijith Das <[email protected]>
This patch adds a new flag to the gfs2_holder structure GL_FLOCK. It is set on holders of glocks representing flocks. This flag is checked in add_to_queue() and a process is permitted to queue more than one holder onto a glock if it is set. This solves the issue of a process not being able to do multiple flocks on the same file. Through a single descriptor, a process can now promote and demote flocks. Through multiple descriptors a process can now queue multiple flocks on the same file. There's still the problem of a process deadlocking itself (because gfs2 blocking locks are not interruptible) by queueing incompatible deadlock.
fs/gfs2/glock.c +25 -18
@@ -1106,24 +1106,31 @@ static void add_to_queue(struct gfs2_holder *gh)if (test_and_set_bit (HIF_WAIT , &gh->gh_iflags))BUG (); - existing =find_holder_by_owner (&gl->gl_holders, gh->gh_owner_pid); -if (existing) { -print_symbol (KERN_WARNING "original: %s\n" , existing->gh_ip); -printk (KERN_INFO "pid : %d\n" , existing->gh_owner_pid); -printk (KERN_INFO "lock type : %d lock state : %d\n" , - existing->gh_gl->gl_name.ln_type, existing->gh_gl->gl_state); -print_symbol (KERN_WARNING "new: %s\n" , gh->gh_ip); -printk (KERN_INFO "pid : %d\n" , gh->gh_owner_pid); -printk (KERN_INFO "lock type : %d lock state : %d\n" , - gl->gl_name.ln_type, gl->gl_state); -BUG (); - } - - existing =find_holder_by_owner (&gl->gl_waiters3, gh->gh_owner_pid); -if (existing) { -print_symbol (KERN_WARNING "original: %s\n" , existing->gh_ip); -print_symbol (KERN_WARNING "new: %s\n" , gh->gh_ip); -BUG (); +if (!(gh->gh_flags &GL_FLOCK )) { + existing =find_holder_by_owner (&gl->gl_holders, + gh->gh_owner_pid); +if (existing) { +print_symbol (KERN_WARNING "original: %s\n" , + existing->gh_ip); +printk (KERN_INFO "pid : %d\n" , existing->gh_owner_pid); +printk (KERN_INFO "lock type : %d lock state : %d\n" , + existing->gh_gl->gl_name.ln_type, + existing->gh_gl->gl_state); +print_symbol (KERN_WARNING "new: %s\n" , gh->gh_ip); +printk (KERN_INFO "pid : %d\n" , gh->gh_owner_pid); +printk (KERN_INFO "lock type : %d lock state : %d\n" , + gl->gl_name.ln_type, gl->gl_state); +BUG (); + } + + existing =find_holder_by_owner (&gl->gl_waiters3, + gh->gh_owner_pid); +if (existing) { +print_symbol (KERN_WARNING "original: %s\n" , + existing->gh_ip); +print_symbol (KERN_WARNING "new: %s\n" , gh->gh_ip); +BUG (); + } }if (gh->gh_flags &LM_FLAG_PRIORITY )
fs/gfs2/glock.h +1 -0
@@ -26,6 +26,7 @@#define GL_SKIP 0x00000100#define GL_ATIME 0x00000200#define GL_NOCACHE 0x00000400 +#define GL_FLOCK 0x00000800#define GL_NOCANCEL 0x00001000#define GLR_TRYFAILED 13
fs/gfs2/ops_file.c +6 -7
@@ -571,7 +571,8 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl)int error =0 ; state = (fl->fl_type ==F_WRLCK ) ?LM_ST_EXCLUSIVE :LM_ST_SHARED ; - flags = (IS_SETLKW (cmd) ?0 :LM_FLAG_TRY ) |GL_EXACT |GL_NOCACHE ; + flags = (IS_SETLKW (cmd) ?0 :LM_FLAG_TRY ) |GL_EXACT |GL_NOCACHE + |GL_FLOCK ;mutex_lock (&fp->f_fl_mutex);
@@ -579,21 +580,19 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl)if (gl) {if (fl_gh->gh_state == state) goto out; -gfs2_glock_hold (gl);flock_lock_file_wait (file, &(struct file_lock ){.fl_type =F_UNLCK }); -gfs2_glock_dq_uninit (fl_gh); +gfs2_glock_dq_wait (fl_gh); +gfs2_holder_reinit (state, flags, fl_gh); }else { error =gfs2_glock_get (GFS2_SB (&ip->i_inode), ip->i_no_addr, &gfs2_flock_glops,CREATE , &gl);if (error) goto out; +gfs2_holder_init (gl, state, flags, fl_gh); +gfs2_glock_put (gl); } - -gfs2_holder_init (gl, state, flags, fl_gh); -gfs2_glock_put (gl); - error =gfs2_glock_nq (fl_gh);if (error) {gfs2_holder_uninit (fl_gh);
Signature · 1 line
1.5.1.2
PATCH 42/51 Move inode deletion out of blocking_cb
From: Wendy Cheng <[email protected]>
Move inode deletion code out of blocking_cb handle_callback route to avoid racy conditions that end up blocking lock_dlm1 thread. Fix bugzilla 286821.
fs/gfs2/glock.c +1 -5
@@ -716,12 +716,8 @@ static void handle_callback(struct gfs2_glock *gl, unsigned int state, gl->gl_demote_time = jiffies;if (remote && gl->gl_ops->go_type ==LM_TYPE_IOPEN && gl->gl_object) { -struct inode *inode =igrab (gl->gl_object); +gfs2_glock_schedule_for_reclaim (gl);spin_unlock (&gl->gl_spin); -if (inode) { -d_prune_aliases (inode); -iput (inode); - }return ; } } else if (gl->gl_demote_state != LM_ST_UNLOCKED &&
Signature · 1 line
1.5.1.2
PATCH 43/51 Make dlm_sendd cond_resched more
From: Patrick Caulfield <[email protected]>
Under high recovery loads dlm_sendd can monopolise the CPU and cause soft lockups.
This one extra and one moved cond_resched() make it yield a little more during such times keeping work moving.
fs/dlm/lowcomms.c +4 -3
@@ -1264,14 +1264,15 @@ static void send_to_sock(struct connection *con)if (len) { ret =sendpage (con->sock, e->page, offset, len, msg_flags); -if (ret == -EAGAIN || ret ==0 ) +if (ret == -EAGAIN || ret ==0 ) { +cond_resched (); goto out; + }if (ret <=0 ) goto send_error; - }else { + }/* Don't starve people filling buffers */ cond_resched (); - }spin_lock (&con->writequeue_lock); e->offset += ret;
Signature · 1 line
1.5.1.2
PATCH 44/51 GFS2: chmod hung - fix race in thread creation
From: Bob Peterson <[email protected]>
The problem boiled down to a race between the gdlm_init_threads() function initializing thread1 and its setting of blist = 1. Essentially, "if (current == ls->thread1)" was checked by the thread before the thread creator set ls->thread1.
Since thread1 is the only thread who is allowed to work on the blocking queue, and since neither thread thought it was thread1, no one was working on the queue. So everything just sat.
This patch reuses the ls->async_lock spin_lock to fix the race, and it fixes the problem. I've done more than 2000 iterations of the loop that was recreating the failure and it seems to work.
--
fs/gfs2/locking/dlm/thread.c +13 -7
@@ -268,20 +268,16 @@ static inline int check_drop(struct gdlm_ls *ls)return 0 ; } -static int gdlm_thread (void *data) +static int gdlm_thread (void *data,int blist) {struct gdlm_ls *ls = (struct gdlm_ls *) data;struct gdlm_lock *lp =NULL ; -int blist =0 ;uint8_t complete, blocking, submit, drop;DECLARE_WAITQUEUE (wait, current);/* Only thread1 is allowed to do blocking callbacks since gfs may wait for a completion callback within a blocking cb. */ -if (current == ls->thread1) - blist =1 ; -while (!kthread_should_stop ()) {set_current_state (TASK_INTERRUPTIBLE );add_wait_queue (&ls->thread_wait, &wait);
@@ -333,12 +329,22 @@ static int gdlm_thread(void *data)return 0 ; } +static int gdlm_thread1 (void *data) +{ +return gdlm_thread (data,1 ); +} + +static int gdlm_thread2 (void *data) +{ +return gdlm_thread (data,0 ); +} +int gdlm_init_threads (struct gdlm_ls *ls) {struct task_struct *p;int error; - p =kthread_run (gdlm_thread, ls,"lock_dlm1" ); + p =kthread_run (gdlm_thread1, ls,"lock_dlm1" ); error =IS_ERR (p);if (error) {log_error ("can't start lock_dlm1 thread %d" , error);
@@ -346,7 +352,7 @@ int gdlm_init_threads(struct gdlm_ls *ls) } ls->thread1 = p; - p =kthread_run (gdlm_thread, ls,"lock_dlm2" ); + p =kthread_run (gdlm_thread2, ls,"lock_dlm2" ); error =IS_ERR (p);if (error) {log_error ("can't start lock_dlm2 thread %d" , error);
Signature · 1 line
1.5.1.2
PATCH 45/51 Clean up journaled data writing
From: Steven Whitehouse <[email protected]>
This patch cleans up the code for writing journaled data into the log. It also removes the need to allocate a small "tag" structure for each block written into the log. Instead we just keep count of the outstanding I/O so that we can be sure that its all been written at the correct time. Another result of this patch is that a number of ll_rw_block() calls have become submit_bh() calls, closing some races at the same time.
fs/gfs2/incore.h +2 -7
@@ -341,12 +341,6 @@ struct gfs2_quota_data {unsigned long qd_last_touched; }; -struct gfs2_log_buf { -struct list_head lb_list; -struct buffer_head *lb_bh; -struct buffer_head *lb_real; -}; -struct gfs2_trans {unsigned long tr_ip;
@@ -631,7 +625,8 @@ struct gfs2_sbd {unsigned long sd_log_flush_time;struct rw_semaphore sd_log_flush_lock; -struct list_head sd_log_flush_list; +atomic_t sd_log_in_flight; +wait_queue_head_t sd_log_flush_wait;unsigned int sd_log_flush_head;u64 sd_log_flush_wrapped;
fs/gfs2/log.c +83 -62
228 lines not on this page · raw message
fs/gfs2/log.h +1 -0
@@ -52,6 +52,7 @@ int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags);int gfs2_log_reserve (struct gfs2_sbd *sdp,unsigned int blks);void gfs2_log_release (struct gfs2_sbd *sdp,unsigned int blks); +void gfs2_log_incr_head (struct gfs2_sbd *sdp);struct buffer_head *gfs2_log_get_buf (struct gfs2_sbd *sdp); struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
fs/gfs2/lops.c +126 -116
335 lines not on this page · raw message
fs/gfs2/meta_io.c +32 -23
71 lines not on this page · raw message
fs/gfs2/meta_io.h +3 -0
@@ -51,6 +51,9 @@ int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh);void gfs2_attach_bufdata (struct gfs2_glock *gl,struct buffer_head *bh,int meta); +void gfs2_remove_from_journal (struct buffer_head *bh,struct gfs2_trans *tr, +int meta); +void gfs2_meta_wipe (struct gfs2_inode *ip,u64 bstart,u32 blen);void gfs2_meta_cache_flush (struct gfs2_inode *ip);
fs/gfs2/ops_address.c +6 -5
@@ -414,7 +414,8 @@ static int gfs2_prepare_write(struct file *file, struct page *page,if (ind_blocks || data_blocks) rblocks +=RES_STATFS +RES_QUOTA ; - error =gfs2_trans_begin (sdp, rblocks,0 ); + error =gfs2_trans_begin (sdp, rblocks, +PAGE_CACHE_SIZE /sdp->sd_sb.sb_bsize);if (error) goto out_trans_fail;
@@ -625,10 +626,10 @@ static void gfs2_discard(struct gfs2_sbd *sdp, struct buffer_head *bh)clear_buffer_dirty (bh); bd = bh->b_private;if (bd) { -if (!list_empty (&bd->bd_le.le_list)) { -if (!buffer_pinned (bh)) -list_del_init (&bd->bd_le.le_list); - } +if (!list_empty (&bd->bd_le.le_list) && !buffer_pinned (bh)) +list_del_init (&bd->bd_le.le_list); +else +gfs2_remove_from_journal (bh, current->journal_info,0 ); } bh->b_bdev =NULL ;clear_buffer_mapped (bh);
fs/gfs2/ops_fstype.c +2 -1
@@ -89,7 +89,8 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)INIT_LIST_HEAD (&sdp->sd_ail2_list);init_rwsem (&sdp->sd_log_flush_lock); -INIT_LIST_HEAD (&sdp->sd_log_flush_list); +atomic_set (&sdp->sd_log_in_flight,0 ); +init_waitqueue_head (&sdp->sd_log_flush_wait);INIT_LIST_HEAD (&sdp->sd_revoke_list);
fs/gfs2/ops_inode.c +6 -1
@@ -905,12 +905,17 @@ static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd)static int setattr_size (struct inode *inode,struct iattr *attr) {struct gfs2_inode *ip =GFS2_I (inode); +struct gfs2_sbd *sdp =GFS2_SB (inode);int error;if (attr->ia_size != ip->i_di.di_size) { - error =vmtruncate (inode, attr->ia_size); + error =gfs2_trans_begin (sdp,0 , sdp->sd_jdesc->jd_blocks);if (error)return error; + error =vmtruncate (inode, attr->ia_size); +gfs2_trans_end (sdp); +if (error) +return error; } error =gfs2_truncatei (ip, attr->ia_size);
fs/gfs2/ops_super.c +8 -5
@@ -455,12 +455,15 @@ static void gfs2_delete_inode(struct inode *inode) } error =gfs2_dinode_dealloc (ip); -/* -* Must do this before unlock to avoid trying to write back -* potentially dirty data now that inode no longer exists -* on disk. -*/ +if (error) + goto out_unlock; + + error =gfs2_trans_begin (sdp,0 , sdp->sd_jdesc->jd_blocks); +if (error) + goto out_unlock; +/* Needs to be done before glock release & also in a transaction */ truncate_inode_pages (&inode->i_data,0 ); +gfs2_trans_end (sdp); out_unlock:gfs2_glock_dq (&ip->i_iopen_gh);
Signature · 1 line
1.5.1.2
PATCH 46/51 Data corruption fix
From: Wendy Cheng <[email protected]>
* GFS2 has been using i_cache array to store its indirect meta blocks. Its flush routine doesn't correctly clean up all the entries. The problem would show while multiple nodes do simultaneous writes to the same file. Upon glock exclusive lock transfer, if the file is a sparse file with large file size where the indirect meta blocks span multiple array entries with "zero" entries in between. The flush routine prematurely stops the flushing that leaves old (stale) entries around. This leads to several nasty issues, including data corruption.
* Fix gfs2_get_block_noalloc checking to correctly return EIO upon unmapped buffer.
fs/gfs2/meta_io.c +4 -4
@@ -374,10 +374,10 @@ void gfs2_meta_cache_flush(struct gfs2_inode *ip)for (x =0 ; x <GFS2_MAX_META_HEIGHT ; x++) { bh_slot = &ip->i_cache[x]; -if (!*bh_slot) -break ; -brelse (*bh_slot); - *bh_slot =NULL ; +if (*bh_slot) { +brelse (*bh_slot); + *bh_slot =NULL ; + } }spin_unlock (&ip->i_spin);
fs/gfs2/ops_address.c +1 -1
@@ -90,7 +90,7 @@ static int gfs2_get_block_noalloc(struct inode *inode, sector_t lblock, error =gfs2_block_map (inode, lblock,0 , bh_result);if (error)return error; -if (bh_result->b_blocknr ==0 ) +if (!buffer_mapped (bh_result))return -EIO ;return 0 ; }
Signature · 1 line
1.5.1.2
PATCH 47/51 Alternate gfs2_iget to avoid looking up inodes being freed
From: Benjamin Marzinski <[email protected]>
There is a possible deadlock between two processes on the same node, where one process is deleting an inode, and another process is looking for allocated but unused inodes to delete in order to create more space.
process A does an iput() on inode X, and it's i_count drops to 0. This causes iput_final() to be called, which puts an inode into state I_FREEING at generic_delete_inode(). There no point between when iput_final() is called, and when I_FREEING is set where GFS2 could acquire any glocks. Once I_FREEING is set, no other process on that node can successfully look up that inode until the delete finishes.
process B locks the the resource group for the same inode in get_local_rgrp(), which is called by gfs2_inplace_reserve_i()
process A tries to lock the resource group for the inode in gfs2_dinode_dealloc(), but it's already locked by process B
process B waits in find_inode for the inode to have the I_FREEING state cleared.
Deadlock.
This patch solves the problem by adding an alternative to gfs2_iget(), gfs2_iget_skip(), that simply skips any inodes that are in the I_FREEING state.o The alternate test function is just like the original one, except that it fails if the inode is being freed, and sets a skipped flag. The alternate set function is just like the original, except that it fails if the skipped flag is set. Only try_rgrp_unlink() calls gfs2_iget_skip() instead of gfs2_iget().
fs/gfs2/dir.c +1 -1
@@ -1502,7 +1502,7 @@ struct inode *gfs2_dir_search(struct inode *dir, const struct qstr *name) inode =gfs2_inode_lookup (dir->i_sb,be16_to_cpu (dent->de_type),be64_to_cpu (dent->de_inum.no_addr), -be64_to_cpu (dent->de_inum.no_formal_ino)); +be64_to_cpu (dent->de_inum.no_formal_ino),0 );brelse (bh);return inode; }
fs/gfs2/inode.c +54 -4
86 lines not on this page · raw message
fs/gfs2/inode.h +2 -1
@@ -49,7 +49,8 @@ static inline void gfs2_inum_out(const struct gfs2_inode *ip,void gfs2_inode_attr_in (struct gfs2_inode *ip);void gfs2_set_iop (struct inode *inode);struct inode *gfs2_inode_lookup (struct super_block *sb,unsigned type, -u64 no_addr,u64 no_formal_ino); +u64 no_addr,u64 no_formal_ino, +int skip_freeing);struct inode *gfs2_ilookup (struct super_block *sb,u64 no_addr);int gfs2_inode_refresh (struct gfs2_inode *ip);
fs/gfs2/ops_export.c +1 -1
@@ -237,7 +237,7 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_obj) inode =gfs2_inode_lookup (sb,DT_UNKNOWN , inum->no_addr, -0 ); +0 ,0 );if (!inode) goto fail;if (IS_ERR (inode)) {
fs/gfs2/ops_fstype.c +1 -1
@@ -230,7 +230,7 @@ fail:static inline struct inode *gfs2_lookup_root (struct super_block *sb,u64 no_addr) { -return gfs2_inode_lookup (sb,DT_DIR , no_addr,0 ); +return gfs2_inode_lookup (sb,DT_DIR , no_addr,0 ,0 ); }static int init_sb (struct gfs2_sbd *sdp,int silent,int undo)
fs/gfs2/rgrp.c +1 -1
@@ -884,7 +884,7 @@ static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked)continue ; *last_unlinked = no_addr; inode =gfs2_inode_lookup (rgd->rd_sbd->sd_vfs,DT_UNKNOWN , - no_addr,-1 ); + no_addr,-1 ,1 );if (!IS_ERR (inode))return inode; }
Signature · 1 line
1.5.1.2
PATCH 48/51 Don't try to remove buffers that don't exist
From: Steven Whitehouse <[email protected]>
fs/gfs2/ops_address.c +1 -2
@@ -747,7 +747,7 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask)struct gfs2_bufdata *bd;if (!page_has_buffers (page)) - goto out; +return 0 ;gfs2_log_lock (sdp); head = bh =page_buffers (page);
@@ -787,7 +787,6 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) bh = bh->b_this_page; }while (bh != head); -out:return try_to_free_buffers (page); cannot_release:gfs2_log_unlock (sdp);
Signature · 1 line
1.5.1.2
PATCH 49/51 Get superblock a different way
From: Steven Whitehouse <[email protected]>
The mapping may be NULL by the time the I/O has completed, so we now get the superblock by a different route (via the bd and glock) to avoid this problem.
fs/gfs2/log.c +2 -1
@@ -513,7 +513,8 @@ struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp)static void gfs2_fake_write_endio (struct buffer_head *bh,int uptodate) {struct buffer_head *real_bh = bh->b_private; -struct gfs2_sbd *sdp =GFS2_SB (real_bh->b_page->mapping->host); +struct gfs2_bufdata *bd = real_bh->b_private; +struct gfs2_sbd *sdp = bd->bd_gl->gl_sbd;end_buffer_write_sync (bh, uptodate);free_buffer_head (bh);
Signature · 1 line
1.5.1.2
PATCH 50/51 don't overwrite castparam if it's NULL
From: Patrick Caulfield <[email protected]>
If the castaddr passed to the userland API is NULL then don't overwrite the existing castparam. This allows a different thread to cancel a lock request and the CANCEL AST gets delivered to the original thread.
bz#306391 (for RHEL4) refers.
fs/dlm/lock.c +4 -2
@@ -4429,7 +4429,8 @@ int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,if (lvb_in && ua->lksb.sb_lvbptr)memcpy (ua->lksb.sb_lvbptr, lvb_in,DLM_USER_LVB_LEN ); - ua->castparam = ua_tmp->castparam; +if (ua_tmp->castparam) + ua->castparam = ua_tmp->castparam; ua->user_lksb = ua_tmp->user_lksb; error =set_unlock_args (flags, ua, &args);
@@ -4474,7 +4475,8 @@ int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, goto out; ua = (struct dlm_user_args *)lkb->lkb_astparam; - ua->castparam = ua_tmp->castparam; +if (ua_tmp->castparam) + ua->castparam = ua_tmp->castparam; ua->user_lksb = ua_tmp->user_lksb; error =set_unlock_args (flags, ua, &args);
Signature · 1 line
1.5.1.2
PATCH 51/51 block dlm_recv in recovery transition
From: David Teigland <[email protected]>
Introduce a per-lockspace rwsem that's held in read mode by dlm_recv threads while working in the dlm. This allows dlm_recv activity to be suspended when the lockspace transitions to, from and between recovery cycles.
The specific bug prompting this change is one where an in-progress recovery cycle is aborted by a new recovery cycle. While dlm_recv was processing a recovery message, the recovery cycle was aborted and dlm_recoverd began cleaning up. dlm_recv decremented recover_locks_count on an rsb after dlm_recoverd had reset it to zero. This is fixed by suspending dlm_recv (taking write lock on the rwsem) before aborting the current recovery.
The transitions to/from normal and recovery modes are simplified by using this new ability to block dlm_recv. The switch from normal to recovery mode means dlm_recv goes from processing locking messages, to saving them for later, and vice versa. Races are avoided by blocking dlm_recv when setting the flag that switches between modes.
fs/dlm/dlm_internal.h +1 -0
@@ -491,6 +491,7 @@ struct dlm_ls {uint64_t ls_recover_seq;struct dlm_recover *ls_recover_args;struct rw_semaphore ls_in_recovery;/* block local requests */ +struct rw_semaphore ls_recv_active;/* block dlm_recv */ struct list_head ls_requestqueue;/* queue remote requests */ struct mutex ls_requestqueue_mutex;char *ls_recover_buf;
fs/dlm/lock.c +81 -55
153 lines not on this page · raw message
fs/dlm/lock.h +2 -1
@@ -16,7 +16,8 @@void dlm_print_rsb (struct dlm_rsb *r);void dlm_dump_rsb (struct dlm_rsb *r);void dlm_print_lkb (struct dlm_lkb *lkb); -int dlm_receive_message (struct dlm_header *hd,int nodeid,int recovery); +void dlm_receive_message_saved (struct dlm_ls *ls,struct dlm_message *ms); +void dlm_receive_buffer (struct dlm_header *hd,int nodeid);int dlm_modes_compat (int mode1,int mode2);int dlm_find_rsb (struct dlm_ls *ls,char *name,int namelen,unsigned int flags,struct dlm_rsb **r_ret);
fs/dlm/lockspace.c +1 -0
@@ -519,6 +519,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, ls->ls_recover_seq =0 ; ls->ls_recover_args =NULL ;init_rwsem (&ls->ls_in_recovery); +init_rwsem (&ls->ls_recv_active);INIT_LIST_HEAD (&ls->ls_requestqueue);mutex_init (&ls->ls_requestqueue_mutex);mutex_init (&ls->ls_clear_proc_locks);
fs/dlm/member.c +27 -14
72 lines not on this page · raw message
fs/dlm/midcomms.c +2 -15
@@ -2,7 +2,7 @@ ******************************************************************************* ** ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. -** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. ** ** This copyrighted material is made available to anyone wishing to use, ** modify, copy, or redistribute it subject to the terms and conditions
@@ -27,7 +27,6 @@#include "dlm_internal.h" #include "lowcomms.h" #include "config.h" -#include "rcom.h" #include "lock.h" #include "midcomms.h"
@@ -117,19 +116,7 @@ int dlm_process_incoming_buffer(int nodeid, const void *base, offset &= (limit -1 ); len -= msglen; -switch (msg->h_cmd) { -case DLM_MSG : -dlm_receive_message (msg, nodeid,0 ); -break ; - -case DLM_RCOM : -dlm_receive_rcom (msg, nodeid); -break ; - -default : -log_print ("unknown msg type %x from %u: %u %u %u %u" , - msg->h_cmd, nodeid, msglen, len, offset, ret); - } +dlm_receive_buffer (msg, nodeid); }if (msg != (struct dlm_header *) __tmp)
fs/dlm/rcom.c +8 -28
@@ -2,7 +2,7 @@ ******************************************************************************* ** ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. -** Copyright (C) 2005 Red Hat, Inc. All rights reserved. +** Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. ** ** This copyrighted material is made available to anyone wishing to use, ** modify, copy, or redistribute it subject to the terms and conditions
@@ -386,7 +386,10 @@ static void receive_rcom_lock_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in)dlm_recover_process_copy (ls, rc_in); } -static int send_ls_not_ready (int nodeid,struct dlm_rcom *rc_in) +/* If the lockspace doesn't exist then still send a status message +back; it's possible that it just doesn't have its global_id yet. */ + +int dlm_send_ls_not_ready (int nodeid,struct dlm_rcom *rc_in) {struct dlm_rcom *rc;struct rcom_config *rf;
@@ -446,28 +449,11 @@ static int is_old_reply(struct dlm_ls *ls, struct dlm_rcom *rc)return rv; } -/* Called by dlm_recvd; corresponds to dlm_receive_message() but special +/* Called by dlm_recv; corresponds to dlm_receive_message() but special recovery-only comms are sent through here. */ -void dlm_receive_rcom (struct dlm_header *hd,int nodeid) +void dlm_receive_rcom (struct dlm_ls *ls,struct dlm_rcom *rc,int nodeid) { -struct dlm_rcom *rc = (struct dlm_rcom *) hd; -struct dlm_ls *ls; - -dlm_rcom_in (rc); - -/* If the lockspace doesn't exist then still send a status message -back; it's possible that it just doesn't have its global_id yet. */ - - ls =dlm_find_lockspace_global (hd->h_lockspace); -if (!ls) { -log_print ("lockspace %x from %d type %x not found" , - hd->h_lockspace, nodeid, rc->rc_type); -if (rc->rc_type ==DLM_RCOM_STATUS ) -send_ls_not_ready (nodeid, rc); -return ; - } -if (dlm_recovery_stopped (ls) && (rc->rc_type !=DLM_RCOM_STATUS )) {log_debug (ls,"ignoring recovery message %x from %d" , rc->rc_type, nodeid);
@@ -477,12 +463,6 @@ void dlm_receive_rcom(struct dlm_header *hd, int nodeid)if (is_old_reply (ls, rc)) goto out; -if (nodeid != rc->rc_header.h_nodeid) { -log_error (ls,"bad rcom nodeid %d from %d" , - rc->rc_header.h_nodeid, nodeid); - goto out; - } -switch (rc->rc_type) {case DLM_RCOM_STATUS :receive_rcom_status (ls, rc);
@@ -520,6 +500,6 @@ void dlm_receive_rcom(struct dlm_header *hd, int nodeid) DLM_ASSERT(0, printk("rc_type=%x\n", rc->rc_type);); } out: -dlm_put_lockspace (ls); +return ; }
fs/dlm/rcom.h +3 -2
@@ -2,7 +2,7 @@ ******************************************************************************* ** ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. -** Copyright (C) 2005 Red Hat, Inc. All rights reserved. +** Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. ** ** This copyrighted material is made available to anyone wishing to use, ** modify, copy, or redistribute it subject to the terms and conditions
@@ -18,7 +18,8 @@ int dlm_rcom_status(struct dlm_ls *ls, int nodeid);int dlm_rcom_names (struct dlm_ls *ls,int nodeid,char *last_name,int last_len);int dlm_send_rcom_lookup (struct dlm_rsb *r,int dir_nodeid);int dlm_send_rcom_lock (struct dlm_rsb *r,struct dlm_lkb *lkb); -void dlm_receive_rcom (struct dlm_header *hd,int nodeid); +void dlm_receive_rcom (struct dlm_ls *ls,struct dlm_rcom *rc,int nodeid); +int dlm_send_ls_not_ready (int nodeid,struct dlm_rcom *rc_in);#endif
fs/dlm/recoverd.c +10 -1
@@ -24,19 +24,28 @@/* If the start for which we're re-enabling locking (seq) has been superseded -by a newer stop (ls_recover_seq), we need to leave locking disabled. */ +by a newer stop (ls_recover_seq), we need to leave locking disabled. + +We suspend dlm_recv threads here to avoid the race where dlm_recv a) sees +locking stopped and b) adds a message to the requestqueue, but dlm_recoverd +enables locking and clears the requestqueue between a and b. */ static int enable_locking (struct dlm_ls *ls,uint64_t seq) {int error = -EINTR ; +down_write (&ls->ls_recv_active); +spin_lock (&ls->ls_recover_lock);if (ls->ls_recover_seq == seq) {set_bit (LSFL_RUNNING , &ls->ls_flags); +/* unblocks processes waiting to enter the dlm */ up_write (&ls->ls_in_recovery); error =0 ; }spin_unlock (&ls->ls_recover_lock); + +up_write (&ls->ls_recv_active);return error; }
fs/dlm/requestqueue.c +24 -34
112 lines not on this page · raw message
fs/dlm/requestqueue.h +2 -2
@@ -1,7 +1,7 @@/****************************************************************************** ******************************************************************************* ** -** Copyright (C) 2005 Red Hat, Inc. All rights reserved. +** Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. ** ** This copyrighted material is made available to anyone wishing to use, ** modify, copy, or redistribute it subject to the terms and conditions
@@ -13,7 +13,7 @@#ifndef __REQUESTQUEUE_DOT_H__#define __REQUESTQUEUE_DOT_H__ -int dlm_add_requestqueue (struct dlm_ls *ls,int nodeid,struct dlm_header *hd); +void dlm_add_requestqueue (struct dlm_ls *ls,int nodeid,struct dlm_header *hd);int dlm_process_requestqueue (struct dlm_ls *ls);void dlm_wait_requestqueue (struct dlm_ls *ls);void dlm_purge_requestqueue (struct dlm_ls *ls);
Signature · 1 line
1.5.1.2
[GFS2/DLM] Pull request
In reply to [email protected]Hi,
There have been no changes since I posted the patches for review a few days ago. Please consider pulling the following changes from the GFS2/DLM -nmw git tree:
The following changes since commit bbf25010f1a6b761914430f5fca081ec8c7accd1:
Linus Torvalds (1):
Linux 2.6.23
are found in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw.git
Abhijith Das (5):
[GFS2] Force unstuff of hidden quota inode
[GFS2] Fix quota do_list operation hang
[GFS2] Wendy's dump lockname in hex & fix glock dump
[GFS2] panic after can't parse mount arguments
[GFS2] flocks from same process trip kernel BUG at fs/gfs2/glock.c:1118!
Benjamin Marzinski (3):
[GFS2] Add NULL entry to token table
[GFS2] delay glock demote for a minimum hold time [GFS2] Alternate gfs2_iget to avoid looking up inodes being freed
Bob Peterson (9):
[GFS2] Move some code inside the log lock
[GFS2] Revert part of earlier log.c changes
[GFS2] Prevent infinite loop in try_rgrp_unlink() [GFS2] Detach buf data during in-place writeback [GFS2] invalid metadata block - REVISED
[GFS2] Ensure journal file cache is flushed after recovery [GFS2] Patch to protect sd_log_num_jdata
[GFS2] Fix ordering of dirty/journal for ordered buffer unstuffing [GFS2] GFS2: chmod hung - fix race in thread creation
David Teigland (1):
[DLM] block dlm_recv in recovery transition
Denis Cheng (7):
[GFS2] use an temp variable to reduce a spin_unlock [GFS2] mark struct *_operations const
[GFS2] use the declaration of gfs2_dops in the header file instead [GFS2] use list_for_each_entry instead
[GFS2] unneeded typecast
[GFS2] better code for translating characters
[GFS2] fixed a NULL pointer assignment BUG
Jesper Juhl (1):
[GFS2] Clean up duplicate includes in fs/gfs2/
Josef Whiter (1):
[GFS2] Fix calculation of demote state
Patrick Caulfield (3):
[DLM] Fix lowcomms socket closing [DLM] Make dlm_sendd cond_resched more [DLM] don't overwrite castparam if it's NULL
Steve French (1):
[GFS2] GFS2 not checking pointer on create when running under nfsd
Steven Whitehouse (16):
[GFS2] Fix two races relating to glock callbacks [GFS2] Fix an oops in glock dumping
[GFS2] Reduce number of gfs2_scand processes to one [GFS2] Clean up invalidatepage/releasepage
[GFS2] Add a missing gfs2_trans_add_bh()
[GFS2] Correct lock ordering in unlink
[GFS2] Introduce gfs2_remove_from_ail
[GFS2] Don't mark jdata dirty in gfs2_unstuffer_page() [GFS2] Move pin/unpin into lops.c, clean up locking [GFS2] Clean up ordered write code
[GFS2] Replace revoke structure with bufdata structure [GFS2] Use slab operations for all gfs2_bufdata allocations [GFS2] Clean up gfs2_trans_add_revoke()
[GFS2] Clean up journaled data writing
[GFS2] Don't try to remove buffers that don't exist [GFS2] Get superblock a different way
Wendy Cheng (4):
[GFS2] Reduce truncate IO traffic [GFS2] fix inode meta data corruption [GFS2] Move inode deletion out of blocking_cb [GFS2] Data corruption fix
fs/dlm/dlm_internal.h | 1 + fs/dlm/lock.c | 142 +++++++----- fs/dlm/lock.h | 3 +- fs/dlm/lockspace.c | 1 + fs/dlm/lowcomms.c | 23 +-- fs/dlm/member.c | 41 +++-- fs/dlm/midcomms.c | 17 +-- fs/dlm/rcom.c | 36 +--- fs/dlm/rcom.h | 5 +- fs/dlm/recoverd.c | 11 +- fs/dlm/requestqueue.c | 58 ++--- fs/dlm/requestqueue.h | 4 +- fs/gfs2/bmap.c | 35 +++- fs/gfs2/daemon.c | 24 -- fs/gfs2/daemon.h | 1 - fs/gfs2/dir.c | 3 +- fs/gfs2/eaops.c | 8 +- fs/gfs2/eaops.h | 4 +- fs/gfs2/glock.c | 293 ++++++++++++++++--------- fs/gfs2/glock.h | 5 +- fs/gfs2/glops.c | 24 +-- fs/gfs2/incore.h | 31 ++-- fs/gfs2/inode.c | 78 ++++++- fs/gfs2/inode.h | 3 +- fs/gfs2/locking/dlm/lock_dlm.h | 1 - fs/gfs2/locking/dlm/plock.c | 11 +- fs/gfs2/locking/dlm/thread.c | 20 +- fs/gfs2/locking/nolock/main.c | 1 - fs/gfs2/log.c | 230 +++++++++++++------- fs/gfs2/log.h | 2 + fs/gfs2/lops.c | 470 ++++++++++++++++++++-------------------- fs/gfs2/main.c | 3 + fs/gfs2/meta_io.c | 136 +++--------- fs/gfs2/meta_io.h | 6 +- fs/gfs2/mount.c | 5 +- fs/gfs2/ops_address.c | 146 ++++--------- fs/gfs2/ops_export.c | 2 +- fs/gfs2/ops_file.c | 13 +- fs/gfs2/ops_fstype.c | 40 ++-- fs/gfs2/ops_inode.c | 38 +++- fs/gfs2/ops_super.c | 14 +- fs/gfs2/quota.c | 13 + fs/gfs2/recovery.c | 2 +- fs/gfs2/rgrp.c | 39 ++-- fs/gfs2/super.c | 1 - fs/gfs2/sys.c | 2 - fs/gfs2/trans.c | 22 +- fs/gfs2/trans.h | 2 +- include/linux/gfs2_ondisk.h | 30 +++- 49 files changed, 1139 insertions(+), 961 deletions(-)