Commit ba1bdefe authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'gfs2-merge-window' of...

Merge tag 'gfs2-merge-window' of git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-nmw into next

Pull gfs2 updates from Steven Whitehouse:
 "This must be about the smallest merge window patch set ever for GFS2.
  It is probably also the first one without a single patch from me.
  That is down to a combination of factors, and I have some things in
  the works that are not quite ready yet, that I hope to put in next
  time around.

  Returning to what is here this time...  we have 3 patches which fix
  various warnings.  Two are bug fixes (for quotas and also a rare
  recovery race condition).  The final patch, from Ben Marzinski, is an
  important change in the freeze code which has been in progress for
  some time.  This removes the need to take and drop the transaction
  lock for every single transaction, when the only time it was used, was
  at file system freeze time.  Ben's patch integrates the freeze
  operation into the journal flush code as an alternative with lower
  overheads and also lands up resolving some difficult to fix races at
  the same time"

* tag 'gfs2-merge-window' of git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-nmw:
  GFS2: Prevent recovery before the local journal is set
  GFS2: fs/gfs2/file.c: kernel-doc warning fixes
  GFS2: fs/gfs2/bmap.c: kernel-doc warning fixes
  GFS2: remove transaction glock
  GFS2: lops.c: replace 0 by NULL for pointers
  GFS2: quotas not being refreshed in gfs2_adjust_quota
parents 74efa045 0e48e055
...@@ -431,7 +431,7 @@ static int gfs2_jdata_writepages(struct address_space *mapping, ...@@ -431,7 +431,7 @@ static int gfs2_jdata_writepages(struct address_space *mapping,
ret = gfs2_write_cache_jdata(mapping, wbc); ret = gfs2_write_cache_jdata(mapping, wbc);
if (ret == 0 && wbc->sync_mode == WB_SYNC_ALL) { if (ret == 0 && wbc->sync_mode == WB_SYNC_ALL) {
gfs2_log_flush(sdp, ip->i_gl); gfs2_log_flush(sdp, ip->i_gl, NORMAL_FLUSH);
ret = gfs2_write_cache_jdata(mapping, wbc); ret = gfs2_write_cache_jdata(mapping, wbc);
} }
return ret; return ret;
......
...@@ -707,7 +707,7 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi ...@@ -707,7 +707,7 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi
* @top: The first pointer in the buffer * @top: The first pointer in the buffer
* @bottom: One more than the last pointer * @bottom: One more than the last pointer
* @height: the height this buffer is at * @height: the height this buffer is at
* @data: a pointer to a struct strip_mine * @sm: a pointer to a struct strip_mine
* *
* Returns: errno * Returns: errno
*/ */
...@@ -992,6 +992,8 @@ static int gfs2_block_truncate_page(struct address_space *mapping, loff_t from) ...@@ -992,6 +992,8 @@ static int gfs2_block_truncate_page(struct address_space *mapping, loff_t from)
return err; return err;
} }
#define GFS2_JTRUNC_REVOKES 8192
/** /**
* gfs2_journaled_truncate - Wrapper for truncate_pagecache for jdata files * gfs2_journaled_truncate - Wrapper for truncate_pagecache for jdata files
* @inode: The inode being truncated * @inode: The inode being truncated
...@@ -1003,8 +1005,6 @@ static int gfs2_block_truncate_page(struct address_space *mapping, loff_t from) ...@@ -1003,8 +1005,6 @@ static int gfs2_block_truncate_page(struct address_space *mapping, loff_t from)
* if the number of pages being truncated gets too large. * if the number of pages being truncated gets too large.
*/ */
#define GFS2_JTRUNC_REVOKES 8192
static int gfs2_journaled_truncate(struct inode *inode, u64 oldsize, u64 newsize) static int gfs2_journaled_truncate(struct inode *inode, u64 oldsize, u64 newsize)
{ {
struct gfs2_sbd *sdp = GFS2_SB(inode); struct gfs2_sbd *sdp = GFS2_SB(inode);
...@@ -1348,7 +1348,7 @@ void gfs2_free_journal_extents(struct gfs2_jdesc *jd) ...@@ -1348,7 +1348,7 @@ void gfs2_free_journal_extents(struct gfs2_jdesc *jd)
* gfs2_add_jextent - Add or merge a new extent to extent cache * gfs2_add_jextent - Add or merge a new extent to extent cache
* @jd: The journal descriptor * @jd: The journal descriptor
* @lblock: The logical block at start of new extent * @lblock: The logical block at start of new extent
* @pblock: The physical block at start of new extent * @dblock: The physical block at start of new extent
* @blocks: Size of extent in fs blocks * @blocks: Size of extent in fs blocks
* *
* Returns: 0 on success or -ENOMEM * Returns: 0 on success or -ENOMEM
......
...@@ -203,9 +203,9 @@ void gfs2_set_inode_flags(struct inode *inode) ...@@ -203,9 +203,9 @@ void gfs2_set_inode_flags(struct inode *inode)
GFS2_DIF_INHERIT_JDATA) GFS2_DIF_INHERIT_JDATA)
/** /**
* gfs2_set_flags - set flags on an inode * do_gfs2_set_flags - set flags on an inode
* @inode: The inode * @filp: file pointer
* @flags: The flags to set * @reqflags: The flags to set
* @mask: Indicates which flags are valid * @mask: Indicates which flags are valid
* *
*/ */
...@@ -256,7 +256,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) ...@@ -256,7 +256,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
} }
if ((flags ^ new_flags) & GFS2_DIF_JDATA) { if ((flags ^ new_flags) & GFS2_DIF_JDATA) {
if (flags & GFS2_DIF_JDATA) if (flags & GFS2_DIF_JDATA)
gfs2_log_flush(sdp, ip->i_gl); gfs2_log_flush(sdp, ip->i_gl, NORMAL_FLUSH);
error = filemap_fdatawrite(inode->i_mapping); error = filemap_fdatawrite(inode->i_mapping);
if (error) if (error)
goto out; goto out;
...@@ -318,7 +318,7 @@ static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -318,7 +318,7 @@ static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
/** /**
* gfs2_size_hint - Give a hint to the size of a write request * gfs2_size_hint - Give a hint to the size of a write request
* @file: The struct file * @filep: The struct file
* @offset: The file offset of the write * @offset: The file offset of the write
* @size: The length of the write * @size: The length of the write
* *
...@@ -371,7 +371,7 @@ static int gfs2_allocate_page_backing(struct page *page) ...@@ -371,7 +371,7 @@ static int gfs2_allocate_page_backing(struct page *page)
/** /**
* gfs2_page_mkwrite - Make a shared, mmap()ed, page writable * gfs2_page_mkwrite - Make a shared, mmap()ed, page writable
* @vma: The virtual memory area * @vma: The virtual memory area
* @page: The page which is about to become writable * @vmf: The virtual memory fault containing the page to become writable
* *
* When the page becomes writable, we need to ensure that we have * When the page becomes writable, we need to ensure that we have
* blocks allocated on disk to back that page. * blocks allocated on disk to back that page.
......
...@@ -89,18 +89,23 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl) ...@@ -89,18 +89,23 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
if (!tr.tr_revokes) if (!tr.tr_revokes)
return; return;
/* A shortened, inline version of gfs2_trans_begin() */ /* A shortened, inline version of gfs2_trans_begin()
* tr->alloced is not set since the transaction structure is
* on the stack */
tr.tr_reserved = 1 + gfs2_struct2blk(sdp, tr.tr_revokes, sizeof(u64)); tr.tr_reserved = 1 + gfs2_struct2blk(sdp, tr.tr_revokes, sizeof(u64));
tr.tr_ip = (unsigned long)__builtin_return_address(0); tr.tr_ip = (unsigned long)__builtin_return_address(0);
sb_start_intwrite(sdp->sd_vfs); sb_start_intwrite(sdp->sd_vfs);
gfs2_log_reserve(sdp, tr.tr_reserved); if (gfs2_log_reserve(sdp, tr.tr_reserved) < 0) {
sb_end_intwrite(sdp->sd_vfs);
return;
}
WARN_ON_ONCE(current->journal_info); WARN_ON_ONCE(current->journal_info);
current->journal_info = &tr; current->journal_info = &tr;
__gfs2_ail_flush(gl, 0, tr.tr_revokes); __gfs2_ail_flush(gl, 0, tr.tr_revokes);
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
gfs2_log_flush(sdp, NULL); gfs2_log_flush(sdp, NULL, NORMAL_FLUSH);
} }
void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync) void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync)
...@@ -121,7 +126,7 @@ void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync) ...@@ -121,7 +126,7 @@ void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync)
return; return;
__gfs2_ail_flush(gl, fsync, max_revokes); __gfs2_ail_flush(gl, fsync, max_revokes);
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
gfs2_log_flush(sdp, NULL); gfs2_log_flush(sdp, NULL, NORMAL_FLUSH);
} }
/** /**
...@@ -144,7 +149,7 @@ static void rgrp_go_sync(struct gfs2_glock *gl) ...@@ -144,7 +149,7 @@ static void rgrp_go_sync(struct gfs2_glock *gl)
return; return;
GLOCK_BUG_ON(gl, gl->gl_state != LM_ST_EXCLUSIVE); GLOCK_BUG_ON(gl, gl->gl_state != LM_ST_EXCLUSIVE);
gfs2_log_flush(sdp, gl); gfs2_log_flush(sdp, gl, NORMAL_FLUSH);
filemap_fdatawrite_range(mapping, gl->gl_vm.start, gl->gl_vm.end); filemap_fdatawrite_range(mapping, gl->gl_vm.start, gl->gl_vm.end);
error = filemap_fdatawait_range(mapping, gl->gl_vm.start, gl->gl_vm.end); error = filemap_fdatawait_range(mapping, gl->gl_vm.start, gl->gl_vm.end);
mapping_set_error(mapping, error); mapping_set_error(mapping, error);
...@@ -206,7 +211,7 @@ static void inode_go_sync(struct gfs2_glock *gl) ...@@ -206,7 +211,7 @@ static void inode_go_sync(struct gfs2_glock *gl)
GLOCK_BUG_ON(gl, gl->gl_state != LM_ST_EXCLUSIVE); GLOCK_BUG_ON(gl, gl->gl_state != LM_ST_EXCLUSIVE);
gfs2_log_flush(gl->gl_sbd, gl); gfs2_log_flush(gl->gl_sbd, gl, NORMAL_FLUSH);
filemap_fdatawrite(metamapping); filemap_fdatawrite(metamapping);
if (ip) { if (ip) {
struct address_space *mapping = ip->i_inode.i_mapping; struct address_space *mapping = ip->i_inode.i_mapping;
...@@ -253,7 +258,7 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags) ...@@ -253,7 +258,7 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags)
} }
if (ip == GFS2_I(gl->gl_sbd->sd_rindex)) { if (ip == GFS2_I(gl->gl_sbd->sd_rindex)) {
gfs2_log_flush(gl->gl_sbd, NULL); gfs2_log_flush(gl->gl_sbd, NULL, NORMAL_FLUSH);
gl->gl_sbd->sd_rindex_uptodate = 0; gl->gl_sbd->sd_rindex_uptodate = 0;
} }
if (ip && S_ISREG(ip->i_inode.i_mode)) if (ip && S_ISREG(ip->i_inode.i_mode))
...@@ -455,31 +460,39 @@ static void inode_go_dump(struct seq_file *seq, const struct gfs2_glock *gl) ...@@ -455,31 +460,39 @@ static void inode_go_dump(struct seq_file *seq, const struct gfs2_glock *gl)
} }
/** /**
* trans_go_sync - promote/demote the transaction glock * freeze_go_sync - promote/demote the freeze glock
* @gl: the glock * @gl: the glock
* @state: the requested state * @state: the requested state
* @flags: * @flags:
* *
*/ */
static void trans_go_sync(struct gfs2_glock *gl) static void freeze_go_sync(struct gfs2_glock *gl)
{ {
struct gfs2_sbd *sdp = gl->gl_sbd; struct gfs2_sbd *sdp = gl->gl_sbd;
DEFINE_WAIT(wait);
if (gl->gl_state != LM_ST_UNLOCKED && if (gl->gl_state == LM_ST_SHARED &&
test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) { test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
gfs2_meta_syncfs(sdp); atomic_set(&sdp->sd_log_freeze, 1);
gfs2_log_shutdown(sdp); wake_up(&sdp->sd_logd_waitq);
do {
prepare_to_wait(&sdp->sd_log_frozen_wait, &wait,
TASK_UNINTERRUPTIBLE);
if (atomic_read(&sdp->sd_log_freeze))
io_schedule();
} while(atomic_read(&sdp->sd_log_freeze));
finish_wait(&sdp->sd_log_frozen_wait, &wait);
} }
} }
/** /**
* trans_go_xmote_bh - After promoting/demoting the transaction glock * freeze_go_xmote_bh - After promoting/demoting the freeze glock
* @gl: the glock * @gl: the glock
* *
*/ */
static int trans_go_xmote_bh(struct gfs2_glock *gl, struct gfs2_holder *gh) static int freeze_go_xmote_bh(struct gfs2_glock *gl, struct gfs2_holder *gh)
{ {
struct gfs2_sbd *sdp = gl->gl_sbd; struct gfs2_sbd *sdp = gl->gl_sbd;
struct gfs2_inode *ip = GFS2_I(sdp->sd_jdesc->jd_inode); struct gfs2_inode *ip = GFS2_I(sdp->sd_jdesc->jd_inode);
...@@ -512,7 +525,7 @@ static int trans_go_xmote_bh(struct gfs2_glock *gl, struct gfs2_holder *gh) ...@@ -512,7 +525,7 @@ static int trans_go_xmote_bh(struct gfs2_glock *gl, struct gfs2_holder *gh)
* Always returns 0 * Always returns 0
*/ */
static int trans_go_demote_ok(const struct gfs2_glock *gl) static int freeze_go_demote_ok(const struct gfs2_glock *gl)
{ {
return 0; return 0;
} }
...@@ -563,10 +576,10 @@ const struct gfs2_glock_operations gfs2_rgrp_glops = { ...@@ -563,10 +576,10 @@ const struct gfs2_glock_operations gfs2_rgrp_glops = {
.go_flags = GLOF_LVB, .go_flags = GLOF_LVB,
}; };
const struct gfs2_glock_operations gfs2_trans_glops = { const struct gfs2_glock_operations gfs2_freeze_glops = {
.go_sync = trans_go_sync, .go_sync = freeze_go_sync,
.go_xmote_bh = trans_go_xmote_bh, .go_xmote_bh = freeze_go_xmote_bh,
.go_demote_ok = trans_go_demote_ok, .go_demote_ok = freeze_go_demote_ok,
.go_type = LM_TYPE_NONDISK, .go_type = LM_TYPE_NONDISK,
}; };
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
extern const struct gfs2_glock_operations gfs2_meta_glops; extern const struct gfs2_glock_operations gfs2_meta_glops;
extern const struct gfs2_glock_operations gfs2_inode_glops; extern const struct gfs2_glock_operations gfs2_inode_glops;
extern const struct gfs2_glock_operations gfs2_rgrp_glops; extern const struct gfs2_glock_operations gfs2_rgrp_glops;
extern const struct gfs2_glock_operations gfs2_trans_glops; extern const struct gfs2_glock_operations gfs2_freeze_glops;
extern const struct gfs2_glock_operations gfs2_iopen_glops; extern const struct gfs2_glock_operations gfs2_iopen_glops;
extern const struct gfs2_glock_operations gfs2_flock_glops; extern const struct gfs2_glock_operations gfs2_flock_glops;
extern const struct gfs2_glock_operations gfs2_nondisk_glops; extern const struct gfs2_glock_operations gfs2_nondisk_glops;
......
...@@ -465,9 +465,7 @@ struct gfs2_trans { ...@@ -465,9 +465,7 @@ struct gfs2_trans {
unsigned int tr_reserved; unsigned int tr_reserved;
unsigned int tr_touched:1; unsigned int tr_touched:1;
unsigned int tr_attached:1; unsigned int tr_attached:1;
unsigned int tr_alloced:1;
struct gfs2_holder tr_t_gh;
unsigned int tr_num_buf_new; unsigned int tr_num_buf_new;
unsigned int tr_num_databuf_new; unsigned int tr_num_databuf_new;
...@@ -682,7 +680,7 @@ struct gfs2_sbd { ...@@ -682,7 +680,7 @@ struct gfs2_sbd {
struct lm_lockstruct sd_lockstruct; struct lm_lockstruct sd_lockstruct;
struct gfs2_holder sd_live_gh; struct gfs2_holder sd_live_gh;
struct gfs2_glock *sd_rename_gl; struct gfs2_glock *sd_rename_gl;
struct gfs2_glock *sd_trans_gl; struct gfs2_glock *sd_freeze_gl;
wait_queue_head_t sd_glock_wait; wait_queue_head_t sd_glock_wait;
atomic_t sd_glock_disposal; atomic_t sd_glock_disposal;
struct completion sd_locking_init; struct completion sd_locking_init;
...@@ -730,6 +728,8 @@ struct gfs2_sbd { ...@@ -730,6 +728,8 @@ struct gfs2_sbd {
struct gfs2_holder sd_sc_gh; struct gfs2_holder sd_sc_gh;
struct gfs2_holder sd_qc_gh; struct gfs2_holder sd_qc_gh;
struct completion sd_journal_ready;
/* Daemon stuff */ /* Daemon stuff */
struct task_struct *sd_logd_process; struct task_struct *sd_logd_process;
...@@ -794,6 +794,12 @@ struct gfs2_sbd { ...@@ -794,6 +794,12 @@ struct gfs2_sbd {
/* For quiescing the filesystem */ /* For quiescing the filesystem */
struct gfs2_holder sd_freeze_gh; struct gfs2_holder sd_freeze_gh;
struct gfs2_holder sd_freeze_root_gh;
struct gfs2_holder sd_thaw_gh;
atomic_t sd_log_freeze;
atomic_t sd_frozen_root;
wait_queue_head_t sd_frozen_root_wait;
wait_queue_head_t sd_log_frozen_wait;
char sd_fsname[GFS2_FSNAME_LEN]; char sd_fsname[GFS2_FSNAME_LEN];
char sd_table_name[GFS2_FSNAME_LEN]; char sd_table_name[GFS2_FSNAME_LEN];
......
...@@ -1613,18 +1613,26 @@ int gfs2_permission(struct inode *inode, int mask) ...@@ -1613,18 +1613,26 @@ int gfs2_permission(struct inode *inode, int mask)
{ {
struct gfs2_inode *ip; struct gfs2_inode *ip;
struct gfs2_holder i_gh; struct gfs2_holder i_gh;
struct gfs2_sbd *sdp = GFS2_SB(inode);
int error; int error;
int unlock = 0; int unlock = 0;
int frozen_root = 0;
ip = GFS2_I(inode); ip = GFS2_I(inode);
if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) { if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) {
if (mask & MAY_NOT_BLOCK) if (unlikely(gfs2_glock_is_held_excl(sdp->sd_freeze_gl) &&
return -ECHILD; inode == sdp->sd_root_dir->d_inode &&
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); atomic_inc_not_zero(&sdp->sd_frozen_root)))
if (error) frozen_root = 1;
return error; else {
unlock = 1; if (mask & MAY_NOT_BLOCK)
return -ECHILD;
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
if (error)
return error;
unlock = 1;
}
} }
if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode)) if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode))
...@@ -1633,6 +1641,8 @@ int gfs2_permission(struct inode *inode, int mask) ...@@ -1633,6 +1641,8 @@ int gfs2_permission(struct inode *inode, int mask)
error = generic_permission(inode, mask); error = generic_permission(inode, mask);
if (unlock) if (unlock)
gfs2_glock_dq_uninit(&i_gh); gfs2_glock_dq_uninit(&i_gh);
else if (frozen_root && atomic_dec_and_test(&sdp->sd_frozen_root))
wake_up(&sdp->sd_frozen_root_wait);
return error; return error;
} }
...@@ -1805,19 +1815,29 @@ static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, ...@@ -1805,19 +1815,29 @@ static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_holder gh; struct gfs2_holder gh;
struct gfs2_sbd *sdp = GFS2_SB(inode);
int error; int error;
int unlock = 0; int unlock = 0;
int frozen_root = 0;
if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) { if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) {
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); if (unlikely(gfs2_glock_is_held_excl(sdp->sd_freeze_gl) &&
if (error) inode == sdp->sd_root_dir->d_inode &&
return error; atomic_inc_not_zero(&sdp->sd_frozen_root)))
unlock = 1; frozen_root = 1;
else {
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh);
if (error)
return error;
unlock = 1;
}
} }
generic_fillattr(inode, stat); generic_fillattr(inode, stat);
if (unlock) if (unlock)
gfs2_glock_dq_uninit(&gh); gfs2_glock_dq_uninit(&gh);
else if (frozen_root && atomic_dec_and_test(&sdp->sd_frozen_root))
wake_up(&sdp->sd_frozen_root_wait);
return 0; return 0;
} }
......
...@@ -300,6 +300,23 @@ static void ail2_empty(struct gfs2_sbd *sdp, unsigned int new_tail) ...@@ -300,6 +300,23 @@ static void ail2_empty(struct gfs2_sbd *sdp, unsigned int new_tail)
spin_unlock(&sdp->sd_ail_lock); spin_unlock(&sdp->sd_ail_lock);
} }
/**
* gfs2_log_release - Release a given number of log blocks
* @sdp: The GFS2 superblock
* @blks: The number of blocks
*
*/
void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks)
{
atomic_add(blks, &sdp->sd_log_blks_free);
trace_gfs2_log_blocks(sdp, blks);
gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <=
sdp->sd_jdesc->jd_blocks);
up_read(&sdp->sd_log_flush_lock);
}
/** /**
* gfs2_log_reserve - Make a log reservation * gfs2_log_reserve - Make a log reservation
* @sdp: The GFS2 superblock * @sdp: The GFS2 superblock
...@@ -358,7 +375,10 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks) ...@@ -358,7 +375,10 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks)
wake_up(&sdp->sd_log_waitq); wake_up(&sdp->sd_log_waitq);
down_read(&sdp->sd_log_flush_lock); down_read(&sdp->sd_log_flush_lock);
if (unlikely(!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))) {
gfs2_log_release(sdp, blks);
return -EROFS;
}
return 0; return 0;
} }
...@@ -671,7 +691,8 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags) ...@@ -671,7 +691,8 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags)
* *
*/ */
void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
enum gfs2_flush_type type)
{ {
struct gfs2_trans *tr; struct gfs2_trans *tr;
...@@ -723,6 +744,42 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) ...@@ -723,6 +744,42 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
} }
spin_unlock(&sdp->sd_ail_lock); spin_unlock(&sdp->sd_ail_lock);
gfs2_log_unlock(sdp); gfs2_log_unlock(sdp);
if (atomic_read(&sdp->sd_log_freeze))
type = FREEZE_FLUSH;
if (type != NORMAL_FLUSH) {
if (!sdp->sd_log_idle) {
for (;;) {
gfs2_ail1_start(sdp);
gfs2_ail1_wait(sdp);
if (gfs2_ail1_empty(sdp))
break;
}
atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */
trace_gfs2_log_blocks(sdp, -1);
sdp->sd_log_flush_wrapped = 0;
log_write_header(sdp, 0);
sdp->sd_log_head = sdp->sd_log_flush_head;
}
if (type == SHUTDOWN_FLUSH || type == FREEZE_FLUSH)
gfs2_log_shutdown(sdp);
if (type == FREEZE_FLUSH) {
int error;
atomic_set(&sdp->sd_log_freeze, 0);
wake_up(&sdp->sd_log_frozen_wait);
error = gfs2_glock_nq_init(sdp->sd_freeze_gl,
LM_ST_SHARED, 0,
&sdp->sd_thaw_gh);
if (error) {
printk(KERN_INFO "GFS2: couln't get freeze lock : %d\n", error);
gfs2_assert_withdraw(sdp, 0);
}
else
gfs2_glock_dq_uninit(&sdp->sd_thaw_gh);
}
}
trace_gfs2_log_flush(sdp, 0); trace_gfs2_log_flush(sdp, 0);
up_write(&sdp->sd_log_flush_lock); up_write(&sdp->sd_log_flush_lock);
...@@ -761,7 +818,7 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) ...@@ -761,7 +818,7 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
if (sdp->sd_log_tr) { if (sdp->sd_log_tr) {
gfs2_merge_trans(sdp->sd_log_tr, tr); gfs2_merge_trans(sdp->sd_log_tr, tr);
} else if (tr->tr_num_buf_new || tr->tr_num_databuf_new) { } else if (tr->tr_num_buf_new || tr->tr_num_databuf_new) {
gfs2_assert_withdraw(sdp, tr->tr_t_gh.gh_gl); gfs2_assert_withdraw(sdp, tr->tr_alloced);
sdp->sd_log_tr = tr; sdp->sd_log_tr = tr;
tr->tr_attached = 1; tr->tr_attached = 1;
} }
...@@ -813,8 +870,6 @@ void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) ...@@ -813,8 +870,6 @@ void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
void gfs2_log_shutdown(struct gfs2_sbd *sdp) void gfs2_log_shutdown(struct gfs2_sbd *sdp)
{ {
down_write(&sdp->sd_log_flush_lock);
gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved); gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved);
gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke); gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
gfs2_assert_withdraw(sdp, list_empty(&sdp->sd_ail1_list)); gfs2_assert_withdraw(sdp, list_empty(&sdp->sd_ail1_list));
...@@ -824,38 +879,16 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp) ...@@ -824,38 +879,16 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp)
log_write_header(sdp, GFS2_LOG_HEAD_UNMOUNT); log_write_header(sdp, GFS2_LOG_HEAD_UNMOUNT);
gfs2_assert_warn(sdp, atomic_read(&sdp->sd_log_blks_free) == sdp->sd_jdesc->jd_blocks);
gfs2_assert_warn(sdp, sdp->sd_log_head == sdp->sd_log_tail); gfs2_assert_warn(sdp, sdp->sd_log_head == sdp->sd_log_tail);
gfs2_assert_warn(sdp, list_empty(&sdp->sd_ail2_list)); gfs2_assert_warn(sdp, list_empty(&sdp->sd_ail2_list));
sdp->sd_log_head = sdp->sd_log_flush_head; sdp->sd_log_head = sdp->sd_log_flush_head;
sdp->sd_log_tail = sdp->sd_log_head; sdp->sd_log_tail = sdp->sd_log_head;
up_write(&sdp->sd_log_flush_lock);
}
/**
* gfs2_meta_syncfs - sync all the buffers in a filesystem
* @sdp: the filesystem
*
*/
void gfs2_meta_syncfs(struct gfs2_sbd *sdp)
{
gfs2_log_flush(sdp, NULL);
for (;;) {
gfs2_ail1_start(sdp);
gfs2_ail1_wait(sdp);
if (gfs2_ail1_empty(sdp))
break;
}
gfs2_log_flush(sdp, NULL);
} }
static inline int gfs2_jrnl_flush_reqd(struct gfs2_sbd *sdp) static inline int gfs2_jrnl_flush_reqd(struct gfs2_sbd *sdp)
{ {
return (atomic_read(&sdp->sd_log_pinned) >= atomic_read(&sdp->sd_log_thresh1)); return (atomic_read(&sdp->sd_log_pinned) >= atomic_read(&sdp->sd_log_thresh1) || atomic_read(&sdp->sd_log_freeze));
} }
static inline int gfs2_ail_flush_reqd(struct gfs2_sbd *sdp) static inline int gfs2_ail_flush_reqd(struct gfs2_sbd *sdp)
...@@ -882,14 +915,14 @@ int gfs2_logd(void *data) ...@@ -882,14 +915,14 @@ int gfs2_logd(void *data)
if (gfs2_jrnl_flush_reqd(sdp) || t == 0) { if (gfs2_jrnl_flush_reqd(sdp) || t == 0) {
gfs2_ail1_empty(sdp); gfs2_ail1_empty(sdp);
gfs2_log_flush(sdp, NULL); gfs2_log_flush(sdp, NULL, NORMAL_FLUSH);
} }
if (gfs2_ail_flush_reqd(sdp)) { if (gfs2_ail_flush_reqd(sdp)) {
gfs2_ail1_start(sdp); gfs2_ail1_start(sdp);
gfs2_ail1_wait(sdp); gfs2_ail1_wait(sdp);
gfs2_ail1_empty(sdp); gfs2_ail1_empty(sdp);
gfs2_log_flush(sdp, NULL); gfs2_log_flush(sdp, NULL, NORMAL_FLUSH);
} }
if (!gfs2_ail_flush_reqd(sdp)) if (!gfs2_ail_flush_reqd(sdp))
......
...@@ -63,14 +63,21 @@ extern void gfs2_ordered_del_inode(struct gfs2_inode *ip); ...@@ -63,14 +63,21 @@ extern void gfs2_ordered_del_inode(struct gfs2_inode *ip);
extern unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, extern unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
unsigned int ssize); unsigned int ssize);
extern void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks);
extern int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks); extern int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks);
extern void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl); enum gfs2_flush_type {
NORMAL_FLUSH = 0,
SYNC_FLUSH,
SHUTDOWN_FLUSH,
FREEZE_FLUSH
};
extern void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
enum gfs2_flush_type type);
extern void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans); extern void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
extern void gfs2_remove_from_ail(struct gfs2_bufdata *bd); extern void gfs2_remove_from_ail(struct gfs2_bufdata *bd);
extern void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc); extern void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc);
extern void gfs2_log_shutdown(struct gfs2_sbd *sdp); extern void gfs2_log_shutdown(struct gfs2_sbd *sdp);
extern void gfs2_meta_syncfs(struct gfs2_sbd *sdp);
extern int gfs2_logd(void *data); extern int gfs2_logd(void *data);
extern void gfs2_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd); extern void gfs2_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd);
extern void gfs2_write_revokes(struct gfs2_sbd *sdp); extern void gfs2_write_revokes(struct gfs2_sbd *sdp);
......
...@@ -75,7 +75,7 @@ static void maybe_release_space(struct gfs2_bufdata *bd) ...@@ -75,7 +75,7 @@ static void maybe_release_space(struct gfs2_bufdata *bd)
unsigned int index = bd->bd_bh->b_blocknr - gl->gl_name.ln_number; unsigned int index = bd->bd_bh->b_blocknr - gl->gl_name.ln_number;
struct gfs2_bitmap *bi = rgd->rd_bits + index; struct gfs2_bitmap *bi = rgd->rd_bits + index;
if (bi->bi_clone == 0) if (bi->bi_clone == NULL)
return; return;
if (sdp->sd_args.ar_discard) if (sdp->sd_args.ar_discard)
gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bd->bd_bh, bi, 1, NULL); gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bd->bd_bh, bi, 1, NULL);
......
...@@ -94,6 +94,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) ...@@ -94,6 +94,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
INIT_LIST_HEAD(&sdp->sd_jindex_list); INIT_LIST_HEAD(&sdp->sd_jindex_list);
spin_lock_init(&sdp->sd_jindex_spin); spin_lock_init(&sdp->sd_jindex_spin);
mutex_init(&sdp->sd_jindex_mutex); mutex_init(&sdp->sd_jindex_mutex);
init_completion(&sdp->sd_journal_ready);
INIT_LIST_HEAD(&sdp->sd_quota_list); INIT_LIST_HEAD(&sdp->sd_quota_list);
mutex_init(&sdp->sd_quota_mutex); mutex_init(&sdp->sd_quota_mutex);
...@@ -129,6 +130,10 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) ...@@ -129,6 +130,10 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
init_rwsem(&sdp->sd_log_flush_lock); init_rwsem(&sdp->sd_log_flush_lock);
atomic_set(&sdp->sd_log_in_flight, 0); atomic_set(&sdp->sd_log_in_flight, 0);
init_waitqueue_head(&sdp->sd_log_flush_wait); init_waitqueue_head(&sdp->sd_log_flush_wait);
init_waitqueue_head(&sdp->sd_log_frozen_wait);
atomic_set(&sdp->sd_log_freeze, 0);
atomic_set(&sdp->sd_frozen_root, 0);
init_waitqueue_head(&sdp->sd_frozen_root_wait);
return sdp; return sdp;
} }
...@@ -419,8 +424,8 @@ static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh, ...@@ -419,8 +424,8 @@ static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh,
goto fail_live; goto fail_live;
} }
error = gfs2_glock_get(sdp, GFS2_TRANS_LOCK, &gfs2_trans_glops, error = gfs2_glock_get(sdp, GFS2_FREEZE_LOCK, &gfs2_freeze_glops,
CREATE, &sdp->sd_trans_gl); CREATE, &sdp->sd_freeze_gl);
if (error) { if (error) {
fs_err(sdp, "can't create transaction glock: %d\n", error); fs_err(sdp, "can't create transaction glock: %d\n", error);
goto fail_rename; goto fail_rename;
...@@ -429,7 +434,7 @@ static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh, ...@@ -429,7 +434,7 @@ static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh,
return 0; return 0;
fail_trans: fail_trans:
gfs2_glock_put(sdp->sd_trans_gl); gfs2_glock_put(sdp->sd_freeze_gl);
fail_rename: fail_rename:
gfs2_glock_put(sdp->sd_rename_gl); gfs2_glock_put(sdp->sd_rename_gl);
fail_live: fail_live:
...@@ -755,7 +760,15 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) ...@@ -755,7 +760,15 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
set_bit(SDF_JOURNAL_CHECKED, &sdp->sd_flags); set_bit(SDF_JOURNAL_CHECKED, &sdp->sd_flags);
gfs2_glock_dq_uninit(&ji_gh); gfs2_glock_dq_uninit(&ji_gh);
jindex = 0; jindex = 0;
if (!sdp->sd_args.ar_spectator) {
error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, 0,
&sdp->sd_thaw_gh);
if (error) {
fs_err(sdp, "can't acquire freeze glock: %d\n", error);
goto fail_jinode_gh;
}
}
gfs2_glock_dq_uninit(&sdp->sd_thaw_gh);
return 0; return 0;
fail_jinode_gh: fail_jinode_gh:
...@@ -784,6 +797,7 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo) ...@@ -784,6 +797,7 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo)
goto fail_qinode; goto fail_qinode;
error = init_journal(sdp, undo); error = init_journal(sdp, undo);
complete_all(&sdp->sd_journal_ready);
if (error) if (error)
goto fail; goto fail;
...@@ -1200,6 +1214,7 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent ...@@ -1200,6 +1214,7 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent
fail_locking: fail_locking:
init_locking(sdp, &mount_gh, UNDO); init_locking(sdp, &mount_gh, UNDO);
fail_lm: fail_lm:
complete_all(&sdp->sd_journal_ready);
gfs2_gl_hash_clear(sdp); gfs2_gl_hash_clear(sdp);
gfs2_lm_unmount(sdp); gfs2_lm_unmount(sdp);
fail_debug: fail_debug:
...@@ -1380,7 +1395,7 @@ static void gfs2_kill_sb(struct super_block *sb) ...@@ -1380,7 +1395,7 @@ static void gfs2_kill_sb(struct super_block *sb)
return; return;
} }
gfs2_meta_syncfs(sdp); gfs2_log_flush(sdp, NULL, SYNC_FLUSH);
dput(sdp->sd_root_dir); dput(sdp->sd_root_dir);
dput(sdp->sd_master_dir); dput(sdp->sd_master_dir);
sdp->sd_root_dir = NULL; sdp->sd_root_dir = NULL;
......
...@@ -778,6 +778,7 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, ...@@ -778,6 +778,7 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
i_size_write(inode, size); i_size_write(inode, size);
inode->i_mtime = inode->i_atime = CURRENT_TIME; inode->i_mtime = inode->i_atime = CURRENT_TIME;
mark_inode_dirty(inode); mark_inode_dirty(inode);
set_bit(QDF_REFRESH, &qd->qd_flags);
return 0; return 0;
unlock_out: unlock_out:
...@@ -879,7 +880,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) ...@@ -879,7 +880,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
gfs2_glock_dq_uninit(&ghs[qx]); gfs2_glock_dq_uninit(&ghs[qx]);
mutex_unlock(&ip->i_inode.i_mutex); mutex_unlock(&ip->i_inode.i_mutex);
kfree(ghs); kfree(ghs);
gfs2_log_flush(ip->i_gl->gl_sbd, ip->i_gl); gfs2_log_flush(ip->i_gl->gl_sbd, ip->i_gl, NORMAL_FLUSH);
return error; return error;
} }
......
...@@ -454,7 +454,7 @@ void gfs2_recover_func(struct work_struct *work) ...@@ -454,7 +454,7 @@ void gfs2_recover_func(struct work_struct *work)
struct gfs2_inode *ip = GFS2_I(jd->jd_inode); struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
struct gfs2_log_header_host head; struct gfs2_log_header_host head;
struct gfs2_holder j_gh, ji_gh, t_gh; struct gfs2_holder j_gh, ji_gh, thaw_gh;
unsigned long t; unsigned long t;
int ro = 0; int ro = 0;
unsigned int pass; unsigned int pass;
...@@ -508,11 +508,11 @@ void gfs2_recover_func(struct work_struct *work) ...@@ -508,11 +508,11 @@ void gfs2_recover_func(struct work_struct *work)
t = jiffies; t = jiffies;
/* Acquire a shared hold on the transaction lock */ /* Acquire a shared hold on the freeze lock */
error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED,
LM_FLAG_NOEXP | LM_FLAG_PRIORITY | LM_FLAG_NOEXP | LM_FLAG_PRIORITY,
GL_NOCACHE, &t_gh); &thaw_gh);
if (error) if (error)
goto fail_gunlock_ji; goto fail_gunlock_ji;
...@@ -538,7 +538,7 @@ void gfs2_recover_func(struct work_struct *work) ...@@ -538,7 +538,7 @@ void gfs2_recover_func(struct work_struct *work)
fs_warn(sdp, "jid=%u: Can't replay: read-only block " fs_warn(sdp, "jid=%u: Can't replay: read-only block "
"device\n", jd->jd_jid); "device\n", jd->jd_jid);
error = -EROFS; error = -EROFS;
goto fail_gunlock_tr; goto fail_gunlock_thaw;
} }
fs_info(sdp, "jid=%u: Replaying journal...\n", jd->jd_jid); fs_info(sdp, "jid=%u: Replaying journal...\n", jd->jd_jid);
...@@ -549,14 +549,14 @@ void gfs2_recover_func(struct work_struct *work) ...@@ -549,14 +549,14 @@ void gfs2_recover_func(struct work_struct *work)
head.lh_blkno, pass); head.lh_blkno, pass);
lops_after_scan(jd, error, pass); lops_after_scan(jd, error, pass);
if (error) if (error)
goto fail_gunlock_tr; goto fail_gunlock_thaw;
} }
error = clean_journal(jd, &head); error = clean_journal(jd, &head);
if (error) if (error)
goto fail_gunlock_tr; goto fail_gunlock_thaw;
gfs2_glock_dq_uninit(&t_gh); gfs2_glock_dq_uninit(&thaw_gh);
t = DIV_ROUND_UP(jiffies - t, HZ); t = DIV_ROUND_UP(jiffies - t, HZ);
fs_info(sdp, "jid=%u: Journal replayed in %lus\n", fs_info(sdp, "jid=%u: Journal replayed in %lus\n",
jd->jd_jid, t); jd->jd_jid, t);
...@@ -572,8 +572,8 @@ void gfs2_recover_func(struct work_struct *work) ...@@ -572,8 +572,8 @@ void gfs2_recover_func(struct work_struct *work)
fs_info(sdp, "jid=%u: Done\n", jd->jd_jid); fs_info(sdp, "jid=%u: Done\n", jd->jd_jid);
goto done; goto done;
fail_gunlock_tr: fail_gunlock_thaw:
gfs2_glock_dq_uninit(&t_gh); gfs2_glock_dq_uninit(&thaw_gh);
fail_gunlock_ji: fail_gunlock_ji:
if (jlocked) { if (jlocked) {
gfs2_glock_dq_uninit(&ji_gh); gfs2_glock_dq_uninit(&ji_gh);
......
...@@ -2001,7 +2001,7 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, const struct gfs2_alloc_parms *a ...@@ -2001,7 +2001,7 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, const struct gfs2_alloc_parms *a
} }
/* Flushing the log may release space */ /* Flushing the log may release space */
if (loops == 2) if (loops == 2)
gfs2_log_flush(sdp, NULL); gfs2_log_flush(sdp, NULL, NORMAL_FLUSH);
} }
return -ENOSPC; return -ENOSPC;
......
...@@ -399,7 +399,7 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp) ...@@ -399,7 +399,7 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
{ {
struct gfs2_inode *ip = GFS2_I(sdp->sd_jdesc->jd_inode); struct gfs2_inode *ip = GFS2_I(sdp->sd_jdesc->jd_inode);
struct gfs2_glock *j_gl = ip->i_gl; struct gfs2_glock *j_gl = ip->i_gl;
struct gfs2_holder t_gh; struct gfs2_holder thaw_gh;
struct gfs2_log_header_host head; struct gfs2_log_header_host head;
int error; int error;
...@@ -407,7 +407,8 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp) ...@@ -407,7 +407,8 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
if (error) if (error)
return error; return error;
error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, 0, &t_gh); error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, 0,
&thaw_gh);
if (error) if (error)
goto fail_threads; goto fail_threads;
...@@ -433,13 +434,13 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp) ...@@ -433,13 +434,13 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
set_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags); set_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
gfs2_glock_dq_uninit(&t_gh); gfs2_glock_dq_uninit(&thaw_gh);
return 0; return 0;
fail: fail:
t_gh.gh_flags |= GL_NOCACHE; thaw_gh.gh_flags |= GL_NOCACHE;
gfs2_glock_dq_uninit(&t_gh); gfs2_glock_dq_uninit(&thaw_gh);
fail_threads: fail_threads:
kthread_stop(sdp->sd_quotad_process); kthread_stop(sdp->sd_quotad_process);
kthread_stop(sdp->sd_logd_process); kthread_stop(sdp->sd_logd_process);
...@@ -635,15 +636,21 @@ struct lfcc { ...@@ -635,15 +636,21 @@ struct lfcc {
*/ */
static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp, static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp,
struct gfs2_holder *t_gh) struct gfs2_holder *freeze_gh)
{ {
struct gfs2_inode *ip; struct gfs2_inode *ip;
struct gfs2_jdesc *jd; struct gfs2_jdesc *jd;
struct lfcc *lfcc; struct lfcc *lfcc;
LIST_HEAD(list); LIST_HEAD(list);
struct gfs2_log_header_host lh; struct gfs2_log_header_host lh;
struct gfs2_inode *dip = GFS2_I(sdp->sd_root_dir->d_inode);
int error; int error;
error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0,
&sdp->sd_freeze_root_gh);
if (error)
return error;
atomic_set(&sdp->sd_frozen_root, 1);
list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) { list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
lfcc = kmalloc(sizeof(struct lfcc), GFP_KERNEL); lfcc = kmalloc(sizeof(struct lfcc), GFP_KERNEL);
if (!lfcc) { if (!lfcc) {
...@@ -659,8 +666,8 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp, ...@@ -659,8 +666,8 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp,
list_add(&lfcc->list, &list); list_add(&lfcc->list, &list);
} }
error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_DEFERRED, error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_EXCLUSIVE,
GL_NOCACHE, t_gh); GL_NOCACHE, freeze_gh);
list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) { list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
error = gfs2_jdesc_check(jd); error = gfs2_jdesc_check(jd);
...@@ -676,7 +683,7 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp, ...@@ -676,7 +683,7 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp,
} }
if (error) if (error)
gfs2_glock_dq_uninit(t_gh); gfs2_glock_dq_uninit(freeze_gh);
out: out:
while (!list_empty(&list)) { while (!list_empty(&list)) {
...@@ -685,6 +692,11 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp, ...@@ -685,6 +692,11 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp,
gfs2_glock_dq_uninit(&lfcc->gh); gfs2_glock_dq_uninit(&lfcc->gh);
kfree(lfcc); kfree(lfcc);
} }
if (error) {
atomic_dec(&sdp->sd_frozen_root);
wait_event(sdp->sd_frozen_root_wait, atomic_read(&sdp->sd_frozen_root) == 0);
gfs2_glock_dq_uninit(&sdp->sd_freeze_root_gh);
}
return error; return error;
} }
...@@ -742,7 +754,7 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc) ...@@ -742,7 +754,7 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc)
int ret = 0; int ret = 0;
if (wbc->sync_mode == WB_SYNC_ALL) if (wbc->sync_mode == WB_SYNC_ALL)
gfs2_log_flush(GFS2_SB(inode), ip->i_gl); gfs2_log_flush(GFS2_SB(inode), ip->i_gl, NORMAL_FLUSH);
if (bdi->dirty_exceeded) if (bdi->dirty_exceeded)
gfs2_ail1_flush(sdp, wbc); gfs2_ail1_flush(sdp, wbc);
else else
...@@ -822,9 +834,18 @@ static void gfs2_dirty_inode(struct inode *inode, int flags) ...@@ -822,9 +834,18 @@ static void gfs2_dirty_inode(struct inode *inode, int flags)
static int gfs2_make_fs_ro(struct gfs2_sbd *sdp) static int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
{ {
struct gfs2_holder t_gh; struct gfs2_holder thaw_gh;
int error; int error;
error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, GL_NOCACHE,
&thaw_gh);
if (error && !test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
return error;
down_write(&sdp->sd_log_flush_lock);
clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
up_write(&sdp->sd_log_flush_lock);
kthread_stop(sdp->sd_quotad_process); kthread_stop(sdp->sd_quotad_process);
kthread_stop(sdp->sd_logd_process); kthread_stop(sdp->sd_logd_process);
...@@ -832,18 +853,11 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp) ...@@ -832,18 +853,11 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
gfs2_quota_sync(sdp->sd_vfs, 0); gfs2_quota_sync(sdp->sd_vfs, 0);
gfs2_statfs_sync(sdp->sd_vfs, 0); gfs2_statfs_sync(sdp->sd_vfs, 0);
error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, GL_NOCACHE, gfs2_log_flush(sdp, NULL, SHUTDOWN_FLUSH);
&t_gh); gfs2_assert_warn(sdp, atomic_read(&sdp->sd_log_blks_free) == sdp->sd_jdesc->jd_blocks);
if (error && !test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
return error;
gfs2_meta_syncfs(sdp);
gfs2_log_shutdown(sdp);
clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
if (t_gh.gh_gl) if (thaw_gh.gh_gl)
gfs2_glock_dq_uninit(&t_gh); gfs2_glock_dq_uninit(&thaw_gh);
gfs2_quota_cleanup(sdp); gfs2_quota_cleanup(sdp);
...@@ -900,7 +914,7 @@ static void gfs2_put_super(struct super_block *sb) ...@@ -900,7 +914,7 @@ static void gfs2_put_super(struct super_block *sb)
iput(sdp->sd_quota_inode); iput(sdp->sd_quota_inode);
gfs2_glock_put(sdp->sd_rename_gl); gfs2_glock_put(sdp->sd_rename_gl);
gfs2_glock_put(sdp->sd_trans_gl); gfs2_glock_put(sdp->sd_freeze_gl);
if (!sdp->sd_args.ar_spectator) { if (!sdp->sd_args.ar_spectator) {
gfs2_glock_dq_uninit(&sdp->sd_journal_gh); gfs2_glock_dq_uninit(&sdp->sd_journal_gh);
...@@ -935,8 +949,8 @@ static int gfs2_sync_fs(struct super_block *sb, int wait) ...@@ -935,8 +949,8 @@ static int gfs2_sync_fs(struct super_block *sb, int wait)
struct gfs2_sbd *sdp = sb->s_fs_info; struct gfs2_sbd *sdp = sb->s_fs_info;
gfs2_quota_sync(sb, -1); gfs2_quota_sync(sb, -1);
if (wait && sdp) if (wait && sdp && !atomic_read(&sdp->sd_log_freeze))
gfs2_log_flush(sdp, NULL); gfs2_log_flush(sdp, NULL, NORMAL_FLUSH);
return 0; return 0;
} }
...@@ -986,6 +1000,9 @@ static int gfs2_unfreeze(struct super_block *sb) ...@@ -986,6 +1000,9 @@ static int gfs2_unfreeze(struct super_block *sb)
struct gfs2_sbd *sdp = sb->s_fs_info; struct gfs2_sbd *sdp = sb->s_fs_info;
gfs2_glock_dq_uninit(&sdp->sd_freeze_gh); gfs2_glock_dq_uninit(&sdp->sd_freeze_gh);
atomic_dec(&sdp->sd_frozen_root);
wait_event(sdp->sd_frozen_root_wait, atomic_read(&sdp->sd_frozen_root) == 0);
gfs2_glock_dq_uninit(&sdp->sd_freeze_root_gh);
return 0; return 0;
} }
...@@ -1525,7 +1542,7 @@ static void gfs2_evict_inode(struct inode *inode) ...@@ -1525,7 +1542,7 @@ static void gfs2_evict_inode(struct inode *inode)
goto out_unlock; goto out_unlock;
out_truncate: out_truncate:
gfs2_log_flush(sdp, ip->i_gl); gfs2_log_flush(sdp, ip->i_gl, NORMAL_FLUSH);
if (test_bit(GLF_DIRTY, &ip->i_gl->gl_flags)) { if (test_bit(GLF_DIRTY, &ip->i_gl->gl_flags)) {
struct address_space *metamapping = gfs2_glock2aspace(ip->i_gl); struct address_space *metamapping = gfs2_glock2aspace(ip->i_gl);
filemap_fdatawrite(metamapping); filemap_fdatawrite(metamapping);
......
...@@ -240,8 +240,8 @@ static ssize_t demote_rq_store(struct gfs2_sbd *sdp, const char *buf, size_t len ...@@ -240,8 +240,8 @@ static ssize_t demote_rq_store(struct gfs2_sbd *sdp, const char *buf, size_t len
if (gltype > LM_TYPE_JOURNAL) if (gltype > LM_TYPE_JOURNAL)
return -EINVAL; return -EINVAL;
if (gltype == LM_TYPE_NONDISK && glnum == GFS2_TRANS_LOCK) if (gltype == LM_TYPE_NONDISK && glnum == GFS2_FREEZE_LOCK)
glops = &gfs2_trans_glops; glops = &gfs2_freeze_glops;
else else
glops = gfs2_glops_list[gltype]; glops = gfs2_glops_list[gltype];
if (glops == NULL) if (glops == NULL)
...@@ -407,6 +407,9 @@ int gfs2_recover_set(struct gfs2_sbd *sdp, unsigned jid) ...@@ -407,6 +407,9 @@ int gfs2_recover_set(struct gfs2_sbd *sdp, unsigned jid)
struct gfs2_jdesc *jd; struct gfs2_jdesc *jd;
int rv; int rv;
/* Wait for our primary journal to be initialized */
wait_for_completion(&sdp->sd_journal_ready);
spin_lock(&sdp->sd_jindex_spin); spin_lock(&sdp->sd_jindex_spin);
rv = -EBUSY; rv = -EBUSY;
if (sdp->sd_jdesc->jd_jid == jid) if (sdp->sd_jdesc->jd_jid == jid)
......
...@@ -48,6 +48,7 @@ int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks, ...@@ -48,6 +48,7 @@ int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
tr->tr_blocks = blocks; tr->tr_blocks = blocks;
tr->tr_revokes = revokes; tr->tr_revokes = revokes;
tr->tr_reserved = 1; tr->tr_reserved = 1;
tr->tr_alloced = 1;
if (blocks) if (blocks)
tr->tr_reserved += 6 + blocks; tr->tr_reserved += 6 + blocks;
if (revokes) if (revokes)
...@@ -57,48 +58,22 @@ int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks, ...@@ -57,48 +58,22 @@ int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
INIT_LIST_HEAD(&tr->tr_buf); INIT_LIST_HEAD(&tr->tr_buf);
sb_start_intwrite(sdp->sd_vfs); sb_start_intwrite(sdp->sd_vfs);
gfs2_holder_init(sdp->sd_trans_gl, LM_ST_SHARED, 0, &tr->tr_t_gh);
error = gfs2_glock_nq(&tr->tr_t_gh);
if (error)
goto fail_holder_uninit;
error = gfs2_log_reserve(sdp, tr->tr_reserved); error = gfs2_log_reserve(sdp, tr->tr_reserved);
if (error) if (error)
goto fail_gunlock; goto fail;
current->journal_info = tr; current->journal_info = tr;
return 0; return 0;
fail_gunlock: fail:
gfs2_glock_dq(&tr->tr_t_gh);
fail_holder_uninit:
sb_end_intwrite(sdp->sd_vfs); sb_end_intwrite(sdp->sd_vfs);
gfs2_holder_uninit(&tr->tr_t_gh);
kfree(tr); kfree(tr);
return error; return error;
} }
/**
* gfs2_log_release - Release a given number of log blocks
* @sdp: The GFS2 superblock
* @blks: The number of blocks
*
*/
static void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks)
{
atomic_add(blks, &sdp->sd_log_blks_free);
trace_gfs2_log_blocks(sdp, blks);
gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <=
sdp->sd_jdesc->jd_blocks);
up_read(&sdp->sd_log_flush_lock);
}
static void gfs2_print_trans(const struct gfs2_trans *tr) static void gfs2_print_trans(const struct gfs2_trans *tr)
{ {
pr_warn("Transaction created at: %pSR\n", (void *)tr->tr_ip); pr_warn("Transaction created at: %pSR\n", (void *)tr->tr_ip);
...@@ -119,11 +94,8 @@ void gfs2_trans_end(struct gfs2_sbd *sdp) ...@@ -119,11 +94,8 @@ void gfs2_trans_end(struct gfs2_sbd *sdp)
if (!tr->tr_touched) { if (!tr->tr_touched) {
gfs2_log_release(sdp, tr->tr_reserved); gfs2_log_release(sdp, tr->tr_reserved);
if (tr->tr_t_gh.gh_gl) { if (tr->tr_alloced)
gfs2_glock_dq(&tr->tr_t_gh);
gfs2_holder_uninit(&tr->tr_t_gh);
kfree(tr); kfree(tr);
}
sb_end_intwrite(sdp->sd_vfs); sb_end_intwrite(sdp->sd_vfs);
return; return;
} }
...@@ -137,16 +109,12 @@ void gfs2_trans_end(struct gfs2_sbd *sdp) ...@@ -137,16 +109,12 @@ void gfs2_trans_end(struct gfs2_sbd *sdp)
gfs2_print_trans(tr); gfs2_print_trans(tr);
gfs2_log_commit(sdp, tr); gfs2_log_commit(sdp, tr);
if (tr->tr_t_gh.gh_gl) { if (tr->tr_alloced && !tr->tr_attached)
gfs2_glock_dq(&tr->tr_t_gh);
gfs2_holder_uninit(&tr->tr_t_gh);
if (!tr->tr_attached)
kfree(tr); kfree(tr);
}
up_read(&sdp->sd_log_flush_lock); up_read(&sdp->sd_log_flush_lock);
if (sdp->sd_vfs->s_flags & MS_SYNCHRONOUS) if (sdp->sd_vfs->s_flags & MS_SYNCHRONOUS)
gfs2_log_flush(sdp, NULL); gfs2_log_flush(sdp, NULL, NORMAL_FLUSH);
sb_end_intwrite(sdp->sd_vfs); sb_end_intwrite(sdp->sd_vfs);
} }
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#define GFS2_MOUNT_LOCK 0 #define GFS2_MOUNT_LOCK 0
#define GFS2_LIVE_LOCK 1 #define GFS2_LIVE_LOCK 1
#define GFS2_TRANS_LOCK 2 #define GFS2_FREEZE_LOCK 2
#define GFS2_RENAME_LOCK 3 #define GFS2_RENAME_LOCK 3
#define GFS2_CONTROL_LOCK 4 #define GFS2_CONTROL_LOCK 4
#define GFS2_MOUNTED_LOCK 5 #define GFS2_MOUNTED_LOCK 5
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment