forked from Minki/linux
GFS2 changes for this merge window:
Bob's extensive filesystem withdrawal and recovery testing: - Don't write log headers after file system withdraw - clean up iopen glock mess in gfs2_create_inode - Close timing window with GLF_INVALIDATE_IN_PROGRESS - Abort gfs2_freeze if io error is seen - Don't loop forever in gfs2_freeze if withdrawn - fix infinite loop in gfs2_ail1_flush on io error - Introduce function gfs2_withdrawn - fix glock reference problem in gfs2_trans_remove_revoke Filesystems with a block size smaller than the page size: - Fix end-of-file handling in gfs2_page_mkwrite - Improve mmap write vs. punch_hole consistency Other: - Remove active journal side effect from gfs2_write_log_header - Multi-block allocations in gfs2_page_mkwrite Minor cleanups and coding style fixes: - Remove duplicate call from gfs2_create_inode - make gfs2_log_shutdown static - make gfs2_fs_parameters static - Some whitespace cleanups - removed unnecessary semicolon -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJd6VQ1AAoJENW/n+sDE2U6tUsP/2Zd64dVA+2KzpfvklAUNpx/ TENbvRqGVvhofxuScY0oAvcg0KZN03K/L6ZCa71e7RI7T3VM/FG3rKNCkm084a9d r+Rxcz+eSkce5qKVNva6CtQiczGAj27iNiho0Y9IgtzEZ5KEVJuY3cV8Z2qzHrQM Rel2aVpUtaLhbFOj3jLGMt/HHSw8RTTzNqtJJCwRys/tVF1WPVqyNg4PD9a7zMT7 z96tqrlQQxFT4SGiZVJwQHFGuQZEnbr2ahNRmivmGtnNnawLxpEdFuFrSAsC73UB wHO0Dq+7vYVTyQ7HugrqdkXxqyQr5ta06Pep7uj8ZvhoLWZvPuBf2SccpIn9Ufvo 9iLFY5Z9cHg6wpsW+YMG75Mz0A6WbPRIScVog0fxaKW+z0vMZOmsT6hT6llAlCzn oj1igqVEOIBTS+4uMDIOJKvMixo4NTdgsLFQyftUxNHiCw5iGbqkV7ux31YjqX22 A830zv8lba44BsixGtuPEy/0Dnka7rMfRp0cflCzKESSLIdXtSjUSEtS6g0fJISS qKNmnnkHpvjBGMG4lOqJihJdQ+2IiIMLWdNgxkvWgt6F7xjl3gcdREjJF0dmFsd+ GfDUkUZ/70T9UPsaTR2V0GBvEleq4PglALcet9Eela7tKOEziNf3L+prRjMr3909 y4uJIMH9/no1knKBxtkJ =b1m/ -----END PGP SIGNATURE----- Merge tag 'gfs2-for-5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2 Pull GFS2 updates from Andreas Gruenbacher: "Bob's extensive filesystem withdrawal and recovery testing: - don't write log headers after file system withdraw - clean up iopen glock mess in gfs2_create_inode - close timing window with GLF_INVALIDATE_IN_PROGRESS - abort gfs2_freeze if io error is seen - don't loop forever in gfs2_freeze if withdrawn - fix infinite loop in gfs2_ail1_flush on io error - introduce function gfs2_withdrawn - fix glock reference problem in gfs2_trans_remove_revoke Filesystems with a block size smaller than the page size: - fix end-of-file handling in gfs2_page_mkwrite - improve mmap write vs. punch_hole consistency Other: - remove active journal side effect from gfs2_write_log_header - multi-block allocations in gfs2_page_mkwrite Minor cleanups and coding style fixes: - remove duplicate call from gfs2_create_inode - make gfs2_log_shutdown static - make gfs2_fs_parameters static - some whitespace cleanups - removed unnecessary semicolon" * tag 'gfs2-for-5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2: gfs2: Don't write log headers after file system withdraw gfs2: Remove duplicate call from gfs2_create_inode gfs2: clean up iopen glock mess in gfs2_create_inode gfs2: Close timing window with GLF_INVALIDATE_IN_PROGRESS gfs2: Abort gfs2_freeze if io error is seen gfs2: Don't loop forever in gfs2_freeze if withdrawn gfs2: fix infinite loop in gfs2_ail1_flush on io error gfs2: Introduce function gfs2_withdrawn gfs2: fix glock reference problem in gfs2_trans_remove_revoke gfs2: make gfs2_log_shutdown static gfs2: Remove active journal side effect from gfs2_write_log_header gfs2: Fix end-of-file handling in gfs2_page_mkwrite gfs2: Multi-block allocations in gfs2_page_mkwrite gfs2: Improve mmap write vs. punch_hole consistency gfs2: make gfs2_fs_parameters static gfs2: Some whitespace cleanups gfs2: removed unnecessary semicolon
This commit is contained in:
commit
3f1266ec70
@ -497,7 +497,7 @@ static int __gfs2_readpage(void *file, struct page *page)
|
||||
error = mpage_readpage(page, gfs2_block_map);
|
||||
}
|
||||
|
||||
if (unlikely(test_bit(SDF_WITHDRAWN, &sdp->sd_flags)))
|
||||
if (unlikely(gfs2_withdrawn(sdp)))
|
||||
return -EIO;
|
||||
|
||||
return error;
|
||||
@ -614,7 +614,7 @@ static int gfs2_readpages(struct file *file, struct address_space *mapping,
|
||||
gfs2_glock_dq(&gh);
|
||||
out_uninit:
|
||||
gfs2_holder_uninit(&gh);
|
||||
if (unlikely(test_bit(SDF_WITHDRAWN, &sdp->sd_flags)))
|
||||
if (unlikely(gfs2_withdrawn(sdp)))
|
||||
ret = -EIO;
|
||||
return ret;
|
||||
}
|
||||
|
@ -2441,8 +2441,16 @@ int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length)
|
||||
struct inode *inode = file_inode(file);
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
||||
unsigned int blocksize = i_blocksize(inode);
|
||||
loff_t start, end;
|
||||
int error;
|
||||
|
||||
start = round_down(offset, blocksize);
|
||||
end = round_up(offset + length, blocksize) - 1;
|
||||
error = filemap_write_and_wait_range(inode->i_mapping, start, end);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (gfs2_is_jdata(ip))
|
||||
error = gfs2_trans_begin(sdp, RES_DINODE + 2 * RES_JDATA,
|
||||
GFS2_JTRUNC_REVOKES);
|
||||
@ -2456,9 +2464,8 @@ int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length)
|
||||
if (error)
|
||||
goto out;
|
||||
} else {
|
||||
unsigned int start_off, end_len, blocksize;
|
||||
unsigned int start_off, end_len;
|
||||
|
||||
blocksize = i_blocksize(inode);
|
||||
start_off = offset & (blocksize - 1);
|
||||
end_len = (offset + length) & (blocksize - 1);
|
||||
if (start_off) {
|
||||
|
@ -407,27 +407,28 @@ static void gfs2_size_hint(struct file *filep, loff_t offset, size_t size)
|
||||
/**
|
||||
* gfs2_allocate_page_backing - Allocate blocks for a write fault
|
||||
* @page: The (locked) page to allocate backing for
|
||||
* @length: Size of the allocation
|
||||
*
|
||||
* We try to allocate all the blocks required for the page in one go. This
|
||||
* might fail for various reasons, so we keep trying until all the blocks to
|
||||
* back this page are allocated. If some of the blocks are already allocated,
|
||||
* that is ok too.
|
||||
*/
|
||||
static int gfs2_allocate_page_backing(struct page *page)
|
||||
static int gfs2_allocate_page_backing(struct page *page, unsigned int length)
|
||||
{
|
||||
u64 pos = page_offset(page);
|
||||
u64 size = PAGE_SIZE;
|
||||
|
||||
do {
|
||||
struct iomap iomap = { };
|
||||
|
||||
if (gfs2_iomap_get_alloc(page->mapping->host, pos, 1, &iomap))
|
||||
if (gfs2_iomap_get_alloc(page->mapping->host, pos, length, &iomap))
|
||||
return -EIO;
|
||||
|
||||
iomap.length = min(iomap.length, size);
|
||||
size -= iomap.length;
|
||||
if (length < iomap.length)
|
||||
iomap.length = length;
|
||||
length -= iomap.length;
|
||||
pos += iomap.length;
|
||||
} while (size > 0);
|
||||
} while (length > 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -448,10 +449,10 @@ static vm_fault_t gfs2_page_mkwrite(struct vm_fault *vmf)
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
||||
struct gfs2_alloc_parms ap = { .aflags = 0, };
|
||||
unsigned long last_index;
|
||||
u64 pos = page_offset(page);
|
||||
u64 offset = page_offset(page);
|
||||
unsigned int data_blocks, ind_blocks, rblocks;
|
||||
struct gfs2_holder gh;
|
||||
unsigned int length;
|
||||
loff_t size;
|
||||
int ret;
|
||||
|
||||
@ -461,20 +462,39 @@ static vm_fault_t gfs2_page_mkwrite(struct vm_fault *vmf)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
gfs2_size_hint(vmf->vma->vm_file, pos, PAGE_SIZE);
|
||||
|
||||
gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
|
||||
ret = gfs2_glock_nq(&gh);
|
||||
if (ret)
|
||||
goto out_uninit;
|
||||
|
||||
/* Check page index against inode size */
|
||||
size = i_size_read(inode);
|
||||
if (offset >= size) {
|
||||
ret = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* Update file times before taking page lock */
|
||||
file_update_time(vmf->vma->vm_file);
|
||||
|
||||
/* page is wholly or partially inside EOF */
|
||||
if (offset > size - PAGE_SIZE)
|
||||
length = offset_in_page(size);
|
||||
else
|
||||
length = PAGE_SIZE;
|
||||
|
||||
gfs2_size_hint(vmf->vma->vm_file, offset, length);
|
||||
|
||||
set_bit(GLF_DIRTY, &ip->i_gl->gl_flags);
|
||||
set_bit(GIF_SW_PAGED, &ip->i_flags);
|
||||
|
||||
if (!gfs2_write_alloc_required(ip, pos, PAGE_SIZE)) {
|
||||
/*
|
||||
* iomap_writepage / iomap_writepages currently don't support inline
|
||||
* files, so always unstuff here.
|
||||
*/
|
||||
|
||||
if (!gfs2_is_stuffed(ip) &&
|
||||
!gfs2_write_alloc_required(ip, offset, length)) {
|
||||
lock_page(page);
|
||||
if (!PageUptodate(page) || page->mapping != inode->i_mapping) {
|
||||
ret = -EAGAIN;
|
||||
@ -487,7 +507,7 @@ static vm_fault_t gfs2_page_mkwrite(struct vm_fault *vmf)
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
|
||||
gfs2_write_calc_reserv(ip, PAGE_SIZE, &data_blocks, &ind_blocks);
|
||||
gfs2_write_calc_reserv(ip, length, &data_blocks, &ind_blocks);
|
||||
ap.target = data_blocks + ind_blocks;
|
||||
ret = gfs2_quota_lock_check(ip, &ap);
|
||||
if (ret)
|
||||
@ -508,13 +528,6 @@ static vm_fault_t gfs2_page_mkwrite(struct vm_fault *vmf)
|
||||
goto out_trans_fail;
|
||||
|
||||
lock_page(page);
|
||||
ret = -EINVAL;
|
||||
size = i_size_read(inode);
|
||||
last_index = (size - 1) >> PAGE_SHIFT;
|
||||
/* Check page index against inode size */
|
||||
if (size == 0 || (page->index > last_index))
|
||||
goto out_trans_end;
|
||||
|
||||
ret = -EAGAIN;
|
||||
/* If truncated, we must retry the operation, we may have raced
|
||||
* with the glock demotion code.
|
||||
@ -527,7 +540,7 @@ static vm_fault_t gfs2_page_mkwrite(struct vm_fault *vmf)
|
||||
if (gfs2_is_stuffed(ip))
|
||||
ret = gfs2_unstuff_dinode(ip, page);
|
||||
if (ret == 0)
|
||||
ret = gfs2_allocate_page_backing(page);
|
||||
ret = gfs2_allocate_page_backing(page, length);
|
||||
|
||||
out_trans_end:
|
||||
if (ret)
|
||||
@ -961,6 +974,7 @@ out:
|
||||
brelse(dibh);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* calc_max_reserv() - Reverse of write_calc_reserv. Given a number of
|
||||
* blocks, determine how many bytes can be written.
|
||||
@ -1208,7 +1222,7 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
|
||||
cmd = F_SETLK;
|
||||
fl->fl_type = F_UNLCK;
|
||||
}
|
||||
if (unlikely(test_bit(SDF_WITHDRAWN, &sdp->sd_flags))) {
|
||||
if (unlikely(gfs2_withdrawn(sdp))) {
|
||||
if (fl->fl_type == F_UNLCK)
|
||||
locks_lock_file_wait(file, fl);
|
||||
return -EIO;
|
||||
|
@ -549,7 +549,7 @@ __acquires(&gl->gl_lockref.lock)
|
||||
unsigned int lck_flags = (unsigned int)(gh ? gh->gh_flags : 0);
|
||||
int ret;
|
||||
|
||||
if (unlikely(test_bit(SDF_WITHDRAWN, &sdp->sd_flags)) &&
|
||||
if (unlikely(gfs2_withdrawn(sdp)) &&
|
||||
target != LM_ST_UNLOCKED)
|
||||
return;
|
||||
lck_flags &= (LM_FLAG_TRY | LM_FLAG_TRY_1CB | LM_FLAG_NOEXP |
|
||||
@ -558,7 +558,14 @@ __acquires(&gl->gl_lockref.lock)
|
||||
GLOCK_BUG_ON(gl, gl->gl_state == gl->gl_target);
|
||||
if ((target == LM_ST_UNLOCKED || target == LM_ST_DEFERRED) &&
|
||||
glops->go_inval) {
|
||||
set_bit(GLF_INVALIDATE_IN_PROGRESS, &gl->gl_flags);
|
||||
/*
|
||||
* If another process is already doing the invalidate, let that
|
||||
* finish first. The glock state machine will get back to this
|
||||
* holder again later.
|
||||
*/
|
||||
if (test_and_set_bit(GLF_INVALIDATE_IN_PROGRESS,
|
||||
&gl->gl_flags))
|
||||
return;
|
||||
do_error(gl, 0); /* Fail queued try locks */
|
||||
}
|
||||
gl->gl_req = target;
|
||||
@ -586,8 +593,7 @@ __acquires(&gl->gl_lockref.lock)
|
||||
}
|
||||
else if (ret) {
|
||||
fs_err(sdp, "lm_lock ret %d\n", ret);
|
||||
GLOCK_BUG_ON(gl, !test_bit(SDF_WITHDRAWN,
|
||||
&sdp->sd_flags));
|
||||
GLOCK_BUG_ON(gl, !gfs2_withdrawn(sdp));
|
||||
}
|
||||
} else { /* lock_nolock */
|
||||
finish_xmote(gl, target);
|
||||
@ -1191,7 +1197,7 @@ int gfs2_glock_nq(struct gfs2_holder *gh)
|
||||
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
|
||||
int error = 0;
|
||||
|
||||
if (unlikely(test_bit(SDF_WITHDRAWN, &sdp->sd_flags)))
|
||||
if (unlikely(gfs2_withdrawn(sdp)))
|
||||
return -EIO;
|
||||
|
||||
if (test_bit(GLF_LRU, &gl->gl_flags))
|
||||
|
@ -350,7 +350,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
|
||||
ip->i_inode.i_rdev = MKDEV(be32_to_cpu(str->di_major),
|
||||
be32_to_cpu(str->di_minor));
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
i_uid_write(&ip->i_inode, be32_to_cpu(str->di_uid));
|
||||
i_gid_write(&ip->i_inode, be32_to_cpu(str->di_gid));
|
||||
@ -540,7 +540,7 @@ static int freeze_go_xmote_bh(struct gfs2_glock *gl, struct gfs2_holder *gh)
|
||||
gfs2_consist(sdp);
|
||||
|
||||
/* Initialize some head of the log stuff */
|
||||
if (!test_bit(SDF_WITHDRAWN, &sdp->sd_flags)) {
|
||||
if (!gfs2_withdrawn(sdp)) {
|
||||
sdp->sd_log_sequence = head.lh_sequence + 1;
|
||||
gfs2_log_pointers_init(sdp, head.lh_blkno);
|
||||
}
|
||||
|
@ -656,7 +656,6 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
|
||||
inode->i_rdev = dev;
|
||||
inode->i_size = size;
|
||||
inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
|
||||
gfs2_set_inode_blocks(inode, 1);
|
||||
munge_mode_uid_gid(dip, inode);
|
||||
check_and_update_goal(dip);
|
||||
ip->i_goal = dip->i_goal;
|
||||
@ -712,7 +711,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
|
||||
|
||||
error = gfs2_trans_begin(sdp, blocks, 0);
|
||||
if (error)
|
||||
goto fail_gunlock2;
|
||||
goto fail_free_inode;
|
||||
|
||||
if (blocks > 1) {
|
||||
ip->i_eattr = ip->i_no_addr + 1;
|
||||
@ -723,7 +722,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
|
||||
|
||||
error = gfs2_glock_get(sdp, ip->i_no_addr, &gfs2_iopen_glops, CREATE, &io_gl);
|
||||
if (error)
|
||||
goto fail_gunlock2;
|
||||
goto fail_free_inode;
|
||||
|
||||
BUG_ON(test_and_set_bit(GLF_INODE_CREATING, &io_gl->gl_flags));
|
||||
|
||||
@ -732,7 +731,6 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
|
||||
goto fail_gunlock2;
|
||||
|
||||
glock_set_object(ip->i_iopen_gh.gh_gl, ip);
|
||||
gfs2_glock_put(io_gl);
|
||||
gfs2_set_iop(inode);
|
||||
insert_inode_hash(inode);
|
||||
|
||||
@ -765,6 +763,8 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
|
||||
|
||||
mark_inode_dirty(inode);
|
||||
d_instantiate(dentry, inode);
|
||||
/* After instantiate, errors should result in evict which will destroy
|
||||
* both inode and iopen glocks properly. */
|
||||
if (file) {
|
||||
file->f_mode |= FMODE_CREATED;
|
||||
error = finish_open(file, dentry, gfs2_open_common);
|
||||
@ -772,15 +772,15 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
|
||||
gfs2_glock_dq_uninit(ghs);
|
||||
gfs2_glock_dq_uninit(ghs + 1);
|
||||
clear_bit(GLF_INODE_CREATING, &io_gl->gl_flags);
|
||||
gfs2_glock_put(io_gl);
|
||||
return error;
|
||||
|
||||
fail_gunlock3:
|
||||
glock_clear_object(io_gl, ip);
|
||||
gfs2_glock_dq_uninit(&ip->i_iopen_gh);
|
||||
gfs2_glock_put(io_gl);
|
||||
fail_gunlock2:
|
||||
if (io_gl)
|
||||
clear_bit(GLF_INODE_CREATING, &io_gl->gl_flags);
|
||||
gfs2_glock_put(io_gl);
|
||||
fail_free_inode:
|
||||
if (ip->i_gl) {
|
||||
glock_clear_object(ip->i_gl, ip);
|
||||
@ -1475,7 +1475,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
|
||||
error = -EEXIST;
|
||||
default:
|
||||
goto out_gunlock;
|
||||
};
|
||||
}
|
||||
|
||||
if (odip != ndip) {
|
||||
if (!ndip->i_inode.i_nlink) {
|
||||
|
@ -31,6 +31,8 @@
|
||||
#include "dir.h"
|
||||
#include "trace_gfs2.h"
|
||||
|
||||
static void gfs2_log_shutdown(struct gfs2_sbd *sdp);
|
||||
|
||||
/**
|
||||
* gfs2_struct2blk - compute stuff
|
||||
* @sdp: the filesystem
|
||||
@ -159,7 +161,8 @@ restart:
|
||||
list_for_each_entry_reverse(tr, head, tr_list) {
|
||||
if (wbc->nr_to_write <= 0)
|
||||
break;
|
||||
if (gfs2_ail1_start_one(sdp, wbc, tr, &withdraw))
|
||||
if (gfs2_ail1_start_one(sdp, wbc, tr, &withdraw) &&
|
||||
!gfs2_withdrawn(sdp))
|
||||
goto restart;
|
||||
}
|
||||
spin_unlock(&sdp->sd_ail_lock);
|
||||
@ -609,6 +612,14 @@ void gfs2_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd)
|
||||
list_add(&bd->bd_list, &sdp->sd_log_revokes);
|
||||
}
|
||||
|
||||
void gfs2_glock_remove_revoke(struct gfs2_glock *gl)
|
||||
{
|
||||
if (atomic_dec_return(&gl->gl_revokes) == 0) {
|
||||
clear_bit(GLF_LFLUSH, &gl->gl_flags);
|
||||
gfs2_glock_queue_put(gl);
|
||||
}
|
||||
}
|
||||
|
||||
void gfs2_write_revokes(struct gfs2_sbd *sdp)
|
||||
{
|
||||
struct gfs2_trans *tr;
|
||||
@ -682,12 +693,16 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
|
||||
{
|
||||
struct gfs2_log_header *lh;
|
||||
u32 hash, crc;
|
||||
struct page *page = mempool_alloc(gfs2_page_pool, GFP_NOIO);
|
||||
struct page *page;
|
||||
struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local;
|
||||
struct timespec64 tv;
|
||||
struct super_block *sb = sdp->sd_vfs;
|
||||
u64 dblock;
|
||||
|
||||
if (gfs2_withdrawn(sdp))
|
||||
goto out;
|
||||
|
||||
page = mempool_alloc(gfs2_page_pool, GFP_NOIO);
|
||||
lh = page_address(page);
|
||||
clear_page(lh);
|
||||
|
||||
@ -707,7 +722,7 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
|
||||
lh->lh_nsec = cpu_to_be32(tv.tv_nsec);
|
||||
lh->lh_sec = cpu_to_be64(tv.tv_sec);
|
||||
if (!list_empty(&jd->extent_list))
|
||||
dblock = gfs2_log_bmap(sdp);
|
||||
dblock = gfs2_log_bmap(jd, lblock);
|
||||
else {
|
||||
int ret = gfs2_lblk_to_dblk(jd->jd_inode, lblock, &dblock);
|
||||
if (gfs2_assert_withdraw(sdp, ret == 0))
|
||||
@ -740,6 +755,7 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
|
||||
|
||||
gfs2_log_write(sdp, page, sb->s_blocksize, 0, dblock);
|
||||
gfs2_log_submit_bio(&sdp->sd_log_bio, REQ_OP_WRITE | op_flags);
|
||||
out:
|
||||
log_flush_wait(sdp);
|
||||
}
|
||||
|
||||
@ -768,6 +784,7 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags)
|
||||
sdp->sd_log_idle = (tail == sdp->sd_log_flush_head);
|
||||
gfs2_write_log_header(sdp, sdp->sd_jdesc, sdp->sd_log_sequence++, tail,
|
||||
sdp->sd_log_flush_head, flags, op_flags);
|
||||
gfs2_log_incr_head(sdp);
|
||||
|
||||
if (sdp->sd_log_tail != tail)
|
||||
log_pull_tail(sdp, tail);
|
||||
@ -948,7 +965,7 @@ void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
|
||||
*
|
||||
*/
|
||||
|
||||
void gfs2_log_shutdown(struct gfs2_sbd *sdp)
|
||||
static void gfs2_log_shutdown(struct gfs2_sbd *sdp)
|
||||
{
|
||||
gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved);
|
||||
gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
|
||||
|
@ -74,9 +74,9 @@ extern void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
|
||||
extern void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
|
||||
extern void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc);
|
||||
|
||||
extern void gfs2_log_shutdown(struct gfs2_sbd *sdp);
|
||||
extern int gfs2_logd(void *data);
|
||||
extern void gfs2_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd);
|
||||
extern void gfs2_glock_remove_revoke(struct gfs2_glock *gl);
|
||||
extern void gfs2_write_revokes(struct gfs2_sbd *sdp);
|
||||
|
||||
#endif /* __LOG_DOT_H__ */
|
||||
|
@ -129,7 +129,7 @@ static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
|
||||
atomic_dec(&sdp->sd_log_pinned);
|
||||
}
|
||||
|
||||
static void gfs2_log_incr_head(struct gfs2_sbd *sdp)
|
||||
void gfs2_log_incr_head(struct gfs2_sbd *sdp)
|
||||
{
|
||||
BUG_ON((sdp->sd_log_flush_head == sdp->sd_log_tail) &&
|
||||
(sdp->sd_log_flush_head != sdp->sd_log_head));
|
||||
@ -138,18 +138,13 @@ static void gfs2_log_incr_head(struct gfs2_sbd *sdp)
|
||||
sdp->sd_log_flush_head = 0;
|
||||
}
|
||||
|
||||
u64 gfs2_log_bmap(struct gfs2_sbd *sdp)
|
||||
u64 gfs2_log_bmap(struct gfs2_jdesc *jd, unsigned int lblock)
|
||||
{
|
||||
unsigned int lbn = sdp->sd_log_flush_head;
|
||||
struct gfs2_journal_extent *je;
|
||||
u64 block;
|
||||
|
||||
list_for_each_entry(je, &sdp->sd_jdesc->extent_list, list) {
|
||||
if ((lbn >= je->lblock) && (lbn < (je->lblock + je->blocks))) {
|
||||
block = je->dblock + lbn - je->lblock;
|
||||
gfs2_log_incr_head(sdp);
|
||||
return block;
|
||||
}
|
||||
list_for_each_entry(je, &jd->extent_list, list) {
|
||||
if (lblock >= je->lblock && lblock < je->lblock + je->blocks)
|
||||
return je->dblock + lblock - je->lblock;
|
||||
}
|
||||
|
||||
return -1;
|
||||
@ -351,8 +346,11 @@ void gfs2_log_write(struct gfs2_sbd *sdp, struct page *page,
|
||||
|
||||
static void gfs2_log_write_bh(struct gfs2_sbd *sdp, struct buffer_head *bh)
|
||||
{
|
||||
gfs2_log_write(sdp, bh->b_page, bh->b_size, bh_offset(bh),
|
||||
gfs2_log_bmap(sdp));
|
||||
u64 dblock;
|
||||
|
||||
dblock = gfs2_log_bmap(sdp->sd_jdesc, sdp->sd_log_flush_head);
|
||||
gfs2_log_incr_head(sdp);
|
||||
gfs2_log_write(sdp, bh->b_page, bh->b_size, bh_offset(bh), dblock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -369,8 +367,11 @@ static void gfs2_log_write_bh(struct gfs2_sbd *sdp, struct buffer_head *bh)
|
||||
void gfs2_log_write_page(struct gfs2_sbd *sdp, struct page *page)
|
||||
{
|
||||
struct super_block *sb = sdp->sd_vfs;
|
||||
gfs2_log_write(sdp, page, sb->s_blocksize, 0,
|
||||
gfs2_log_bmap(sdp));
|
||||
u64 dblock;
|
||||
|
||||
dblock = gfs2_log_bmap(sdp->sd_jdesc, sdp->sd_log_flush_head);
|
||||
gfs2_log_incr_head(sdp);
|
||||
gfs2_log_write(sdp, page, sb->s_blocksize, 0, dblock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -882,10 +883,7 @@ static void revoke_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
|
||||
bd = list_entry(head->next, struct gfs2_bufdata, bd_list);
|
||||
list_del_init(&bd->bd_list);
|
||||
gl = bd->bd_gl;
|
||||
if (atomic_dec_return(&gl->gl_revokes) == 0) {
|
||||
clear_bit(GLF_LFLUSH, &gl->gl_flags);
|
||||
gfs2_glock_queue_put(gl);
|
||||
}
|
||||
gfs2_glock_remove_revoke(gl);
|
||||
kmem_cache_free(gfs2_bufdata_cachep, bd);
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,8 @@
|
||||
~(2 * sizeof(__be64) - 1))
|
||||
|
||||
extern const struct gfs2_log_operations *gfs2_log_ops[];
|
||||
extern u64 gfs2_log_bmap(struct gfs2_sbd *sdp);
|
||||
extern void gfs2_log_incr_head(struct gfs2_sbd *sdp);
|
||||
extern u64 gfs2_log_bmap(struct gfs2_jdesc *jd, unsigned int lbn);
|
||||
extern void gfs2_log_write(struct gfs2_sbd *sdp, struct page *page,
|
||||
unsigned size, unsigned offset, u64 blkno);
|
||||
extern void gfs2_log_write_page(struct gfs2_sbd *sdp, struct page *page);
|
||||
|
@ -251,7 +251,7 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
|
||||
struct buffer_head *bh, *bhs[2];
|
||||
int num = 0;
|
||||
|
||||
if (unlikely(test_bit(SDF_WITHDRAWN, &sdp->sd_flags))) {
|
||||
if (unlikely(gfs2_withdrawn(sdp))) {
|
||||
*bhp = NULL;
|
||||
return -EIO;
|
||||
}
|
||||
@ -309,7 +309,7 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
|
||||
|
||||
int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh)
|
||||
{
|
||||
if (unlikely(test_bit(SDF_WITHDRAWN, &sdp->sd_flags)))
|
||||
if (unlikely(gfs2_withdrawn(sdp)))
|
||||
return -EIO;
|
||||
|
||||
wait_on_buffer(bh);
|
||||
@ -320,7 +320,7 @@ int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh)
|
||||
gfs2_io_error_bh_wd(sdp, bh);
|
||||
return -EIO;
|
||||
}
|
||||
if (unlikely(test_bit(SDF_WITHDRAWN, &sdp->sd_flags)))
|
||||
if (unlikely(gfs2_withdrawn(sdp)))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
|
@ -1006,8 +1006,7 @@ hostdata_error:
|
||||
void gfs2_lm_unmount(struct gfs2_sbd *sdp)
|
||||
{
|
||||
const struct lm_lockops *lm = sdp->sd_lockstruct.ls_ops;
|
||||
if (likely(!test_bit(SDF_WITHDRAWN, &sdp->sd_flags)) &&
|
||||
lm->lm_unmount)
|
||||
if (likely(!gfs2_withdrawn(sdp)) && lm->lm_unmount)
|
||||
lm->lm_unmount(sdp);
|
||||
}
|
||||
|
||||
@ -1328,7 +1327,7 @@ static const struct fs_parameter_enum gfs2_param_enums[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
const struct fs_parameter_description gfs2_fs_parameters = {
|
||||
static const struct fs_parameter_description gfs2_fs_parameters = {
|
||||
.name = "gfs2",
|
||||
.specs = gfs2_param_specs,
|
||||
.enums = gfs2_param_enums,
|
||||
|
@ -1475,7 +1475,7 @@ static void quotad_error(struct gfs2_sbd *sdp, const char *msg, int error)
|
||||
{
|
||||
if (error == 0 || error == -EROFS)
|
||||
return;
|
||||
if (!test_bit(SDF_WITHDRAWN, &sdp->sd_flags)) {
|
||||
if (!gfs2_withdrawn(sdp)) {
|
||||
fs_err(sdp, "gfs2_quotad: %s error %d\n", msg, error);
|
||||
sdp->sd_log_error = error;
|
||||
wake_up(&sdp->sd_logd_waitq);
|
||||
|
@ -263,11 +263,13 @@ static void clean_journal(struct gfs2_jdesc *jd,
|
||||
u32 lblock = head->lh_blkno;
|
||||
|
||||
gfs2_replay_incr_blk(jd, &lblock);
|
||||
if (jd->jd_jid == sdp->sd_lockstruct.ls_jid)
|
||||
sdp->sd_log_flush_head = lblock;
|
||||
gfs2_write_log_header(sdp, jd, head->lh_sequence + 1, 0, lblock,
|
||||
GFS2_LOG_HEAD_UNMOUNT | GFS2_LOG_HEAD_RECOVERY,
|
||||
REQ_PREFLUSH | REQ_FUA | REQ_META | REQ_SYNC);
|
||||
if (jd->jd_jid == sdp->sd_lockstruct.ls_jid) {
|
||||
sdp->sd_log_flush_head = lblock;
|
||||
gfs2_log_incr_head(sdp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -326,7 +328,7 @@ void gfs2_recover_func(struct work_struct *work)
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
};
|
||||
}
|
||||
|
||||
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED,
|
||||
LM_FLAG_NOEXP | GL_NOCACHE, &ji_gh);
|
||||
|
@ -399,8 +399,7 @@ struct lfcc {
|
||||
* Returns: errno
|
||||
*/
|
||||
|
||||
static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp,
|
||||
struct gfs2_holder *freeze_gh)
|
||||
static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp)
|
||||
{
|
||||
struct gfs2_inode *ip;
|
||||
struct gfs2_jdesc *jd;
|
||||
@ -425,7 +424,9 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp,
|
||||
}
|
||||
|
||||
error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_EXCLUSIVE,
|
||||
GL_NOCACHE, freeze_gh);
|
||||
GL_NOCACHE, &sdp->sd_freeze_gh);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
|
||||
error = gfs2_jdesc_check(jd);
|
||||
@ -441,7 +442,7 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp,
|
||||
}
|
||||
|
||||
if (error)
|
||||
gfs2_glock_dq_uninit(freeze_gh);
|
||||
gfs2_glock_dq_uninit(&sdp->sd_freeze_gh);
|
||||
|
||||
out:
|
||||
while (!list_empty(&list)) {
|
||||
@ -553,7 +554,7 @@ static void gfs2_dirty_inode(struct inode *inode, int flags)
|
||||
|
||||
if (!(flags & I_DIRTY_INODE))
|
||||
return;
|
||||
if (unlikely(test_bit(SDF_WITHDRAWN, &sdp->sd_flags)))
|
||||
if (unlikely(gfs2_withdrawn(sdp)))
|
||||
return;
|
||||
if (!gfs2_glock_is_locked_by_me(ip->i_gl)) {
|
||||
ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
|
||||
@ -602,7 +603,7 @@ int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
|
||||
|
||||
error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, GL_NOCACHE,
|
||||
&freeze_gh);
|
||||
if (error && !test_bit(SDF_WITHDRAWN, &sdp->sd_flags))
|
||||
if (error && !gfs2_withdrawn(sdp))
|
||||
return error;
|
||||
|
||||
flush_workqueue(gfs2_delete_workqueue);
|
||||
@ -761,21 +762,25 @@ static int gfs2_freeze(struct super_block *sb)
|
||||
if (atomic_read(&sdp->sd_freeze_state) != SFS_UNFROZEN)
|
||||
goto out;
|
||||
|
||||
if (test_bit(SDF_WITHDRAWN, &sdp->sd_flags)) {
|
||||
for (;;) {
|
||||
if (gfs2_withdrawn(sdp)) {
|
||||
error = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
error = gfs2_lock_fs_check_clean(sdp, &sdp->sd_freeze_gh);
|
||||
error = gfs2_lock_fs_check_clean(sdp);
|
||||
if (!error)
|
||||
break;
|
||||
|
||||
if (error == -EBUSY)
|
||||
fs_err(sdp, "waiting for recovery before freeze\n");
|
||||
else
|
||||
else if (error == -EIO) {
|
||||
fs_err(sdp, "Fatal IO error: cannot freeze gfs2 due "
|
||||
"to recovery error.\n");
|
||||
goto out;
|
||||
} else {
|
||||
fs_err(sdp, "error freezing FS: %d\n", error);
|
||||
|
||||
}
|
||||
fs_err(sdp, "retrying...\n");
|
||||
msleep(1000);
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ static ssize_t freeze_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
|
||||
|
||||
static ssize_t withdraw_show(struct gfs2_sbd *sdp, char *buf)
|
||||
{
|
||||
unsigned int b = test_bit(SDF_WITHDRAWN, &sdp->sd_flags);
|
||||
unsigned int b = gfs2_withdrawn(sdp);
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", b);
|
||||
}
|
||||
|
||||
|
@ -262,6 +262,8 @@ void gfs2_trans_remove_revoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len)
|
||||
list_del_init(&bd->bd_list);
|
||||
gfs2_assert_withdraw(sdp, sdp->sd_log_num_revoke);
|
||||
sdp->sd_log_num_revoke--;
|
||||
if (bd->bd_gl)
|
||||
gfs2_glock_remove_revoke(bd->bd_gl);
|
||||
kmem_cache_free(gfs2_bufdata_cachep, bd);
|
||||
tr->tr_num_revoke--;
|
||||
if (--n == 0)
|
||||
|
@ -258,7 +258,7 @@ void gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh,
|
||||
const char *function, char *file, unsigned int line,
|
||||
bool withdraw)
|
||||
{
|
||||
if (!test_bit(SDF_WITHDRAWN, &sdp->sd_flags))
|
||||
if (!gfs2_withdrawn(sdp))
|
||||
fs_err(sdp,
|
||||
"fatal: I/O error\n"
|
||||
" block = %llu\n"
|
||||
|
@ -164,6 +164,15 @@ static inline unsigned int gfs2_tune_get_i(struct gfs2_tune *gt,
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_withdrawn - test whether the file system is withdrawing or withdrawn
|
||||
* @sdp: the superblock
|
||||
*/
|
||||
static inline bool gfs2_withdrawn(struct gfs2_sbd *sdp)
|
||||
{
|
||||
return test_bit(SDF_WITHDRAWN, &sdp->sd_flags);
|
||||
}
|
||||
|
||||
#define gfs2_tune_get(sdp, field) \
|
||||
gfs2_tune_get_i(&(sdp)->sd_tune, &(sdp)->sd_tune.field)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user