Changes in gfs2:
- Make sure transactions won't be started recursively in gfs2_block_zero_range. (Bug introduced in 5.4 when switching to iomap_zero_range.) - Fix a glock holder refcount leak introduced in the iopen glock locking scheme rework merged in 5.8. - A few other small improvements (debugging, stack usage, comment fixes). -----BEGIN PGP SIGNATURE----- iQJIBAABCAAyFiEEJZs3krPW0xkhLMTc1b+f6wMTZToFAl8xkmAUHGFncnVlbmJh QHJlZGhhdC5jb20ACgkQ1b+f6wMTZToB0w/9FANsxraTsNxxZUQuP2uyPiB/TRxY Vutp63Pe+eE0GNxgpfLWT+QgO99BQlGZ8WmDJ49ex0dZXZY4lv4L7JoGTV5VwAyh CFqRcWQkAb7zVvOxAeKfyXT0CwhS7O0avvlubSpEHfQgPkGQa3q3vu18vg1jHfB3 OsFjZGCoyiJKmNFX005euhebnStabaGeP0+8uSz/5xHS+NQUbB3jPlgycUMvTVBe Lhl052rVQzlULNUCkehKnaBxzN0/8K55iFOaOSd2kzZ5BMfRabvskZEyJFf4T75p VJyElekk5mGV0k/FpGL03Me1oqMddDLpAFCGh9Hw51o02i8wZ3RderfQHfUmojku 5/lLEcEJV+oC7gJR7IsGRme71De9y+uLnKvod+ayBw+9us1ZbEm4zJY7hLLGyq03 piuFEAo0UGUmxGn8/s1RBT0lMYKjEDGIGjockaz/XzEQMSip27JZq4ATnA5CHaSy 8q4PFflxEaXWJtPEjiY7DW1xQhYW/3cEDfd7kjSBw/GUxk1ILXRMnzCOsjrYuWfH ykH0gzVq7/uJln/otYa39RBdt/GQXJCzhvODeizF6B36seVX9oBBEc6TtohxREwt aIpupz6iGQ6GXddg1Sq6p2w3xyW8e8bG4YislEyiCyxpdOjvcYdM6cVxF7UBgtgu fwEbjgGO34pAO1E= =+Nig -----END PGP SIGNATURE----- Merge tag 'gfs2-for-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2 Pull gfs2 updates from Andreas Gruenbacher: - Make sure transactions won't be started recursively in gfs2_block_zero_range (bug introduced in 5.4 when switching to iomap_zero_range) - Fix a glock holder refcount leak introduced in the iopen glock locking scheme rework merged in 5.8. - A few other small improvements (debugging, stack usage, comment fixes). * tag 'gfs2-for-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2: gfs2: When gfs2_dirty_inode gets a glock error, dump the glock gfs2: Never call gfs2_block_zero_range with an open transaction gfs2: print details on transactions that aren't properly ended gfs2: Fix inaccurate comment fs: Fix typo in comment gfs2: Fix refcount leak in gfs2_glock_poke gfs2: Pass glock holder to gfs2_file_direct_{read,write} gfs2: Add some flags missing from glock output
This commit is contained in:
commit
8c2618a6d0
|
@ -1351,9 +1351,15 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: Never call gfs2_block_zero_range with an open transaction because it
|
||||
* uses iomap write to perform its actions, which begin their own transactions
|
||||
* (iomap_begin, page_prepare, etc.)
|
||||
*/
|
||||
static int gfs2_block_zero_range(struct inode *inode, loff_t from,
|
||||
unsigned int length)
|
||||
{
|
||||
BUG_ON(current->journal_info);
|
||||
return iomap_zero_range(inode, from, length, NULL, &gfs2_iomap_ops);
|
||||
}
|
||||
|
||||
|
@ -1414,6 +1420,16 @@ static int trunc_start(struct inode *inode, u64 newsize)
|
|||
u64 oldsize = inode->i_size;
|
||||
int error;
|
||||
|
||||
if (!gfs2_is_stuffed(ip)) {
|
||||
unsigned int blocksize = i_blocksize(inode);
|
||||
unsigned int offs = newsize & (blocksize - 1);
|
||||
if (offs) {
|
||||
error = gfs2_block_zero_range(inode, newsize,
|
||||
blocksize - offs);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
}
|
||||
if (journaled)
|
||||
error = gfs2_trans_begin(sdp, RES_DINODE + RES_JDATA, GFS2_JTRUNC_REVOKES);
|
||||
else
|
||||
|
@ -1427,19 +1443,10 @@ static int trunc_start(struct inode *inode, u64 newsize)
|
|||
|
||||
gfs2_trans_add_meta(ip->i_gl, dibh);
|
||||
|
||||
if (gfs2_is_stuffed(ip)) {
|
||||
if (gfs2_is_stuffed(ip))
|
||||
gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + newsize);
|
||||
} else {
|
||||
unsigned int blocksize = i_blocksize(inode);
|
||||
unsigned int offs = newsize & (blocksize - 1);
|
||||
if (offs) {
|
||||
error = gfs2_block_zero_range(inode, newsize,
|
||||
blocksize - offs);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
ip->i_diskflags |= GFS2_DIF_TRUNC_IN_PROG;
|
||||
}
|
||||
|
||||
i_size_write(inode, newsize);
|
||||
ip->i_inode.i_mtime = ip->i_inode.i_ctime = current_time(&ip->i_inode);
|
||||
|
@ -2448,25 +2455,7 @@ int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length)
|
|||
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);
|
||||
else
|
||||
error = gfs2_trans_begin(sdp, RES_DINODE, 0);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (gfs2_is_stuffed(ip)) {
|
||||
error = stuffed_zero_range(inode, offset, length);
|
||||
if (error)
|
||||
goto out;
|
||||
} else {
|
||||
if (!gfs2_is_stuffed(ip)) {
|
||||
unsigned int start_off, end_len;
|
||||
|
||||
start_off = offset & (blocksize - 1);
|
||||
|
@ -2489,6 +2478,26 @@ int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length)
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
else
|
||||
error = gfs2_trans_begin(sdp, RES_DINODE, 0);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (gfs2_is_stuffed(ip)) {
|
||||
error = stuffed_zero_range(inode, offset, length);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (gfs2_is_jdata(ip)) {
|
||||
BUG_ON(!current->journal_info);
|
||||
gfs2_journaled_truncate_range(inode, offset, length);
|
||||
|
|
|
@ -781,39 +781,39 @@ static int gfs2_fsync(struct file *file, loff_t start, loff_t end,
|
|||
return ret ? ret : ret1;
|
||||
}
|
||||
|
||||
static ssize_t gfs2_file_direct_read(struct kiocb *iocb, struct iov_iter *to)
|
||||
static ssize_t gfs2_file_direct_read(struct kiocb *iocb, struct iov_iter *to,
|
||||
struct gfs2_holder *gh)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
|
||||
size_t count = iov_iter_count(to);
|
||||
struct gfs2_holder gh;
|
||||
ssize_t ret;
|
||||
|
||||
if (!count)
|
||||
return 0; /* skip atime */
|
||||
|
||||
gfs2_holder_init(ip->i_gl, LM_ST_DEFERRED, 0, &gh);
|
||||
ret = gfs2_glock_nq(&gh);
|
||||
gfs2_holder_init(ip->i_gl, LM_ST_DEFERRED, 0, gh);
|
||||
ret = gfs2_glock_nq(gh);
|
||||
if (ret)
|
||||
goto out_uninit;
|
||||
|
||||
ret = iomap_dio_rw(iocb, to, &gfs2_iomap_ops, NULL,
|
||||
is_sync_kiocb(iocb));
|
||||
|
||||
gfs2_glock_dq(&gh);
|
||||
gfs2_glock_dq(gh);
|
||||
out_uninit:
|
||||
gfs2_holder_uninit(&gh);
|
||||
gfs2_holder_uninit(gh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from)
|
||||
static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from,
|
||||
struct gfs2_holder *gh)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
size_t len = iov_iter_count(from);
|
||||
loff_t offset = iocb->ki_pos;
|
||||
struct gfs2_holder gh;
|
||||
ssize_t ret;
|
||||
|
||||
/*
|
||||
|
@ -824,8 +824,8 @@ static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from)
|
|||
* unfortunately, have the option of only flushing a range like the
|
||||
* VFS does.
|
||||
*/
|
||||
gfs2_holder_init(ip->i_gl, LM_ST_DEFERRED, 0, &gh);
|
||||
ret = gfs2_glock_nq(&gh);
|
||||
gfs2_holder_init(ip->i_gl, LM_ST_DEFERRED, 0, gh);
|
||||
ret = gfs2_glock_nq(gh);
|
||||
if (ret)
|
||||
goto out_uninit;
|
||||
|
||||
|
@ -838,9 +838,9 @@ static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from)
|
|||
if (ret == -ENOTBLK)
|
||||
ret = 0;
|
||||
out:
|
||||
gfs2_glock_dq(&gh);
|
||||
gfs2_glock_dq(gh);
|
||||
out_uninit:
|
||||
gfs2_holder_uninit(&gh);
|
||||
gfs2_holder_uninit(gh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -852,7 +852,7 @@ static ssize_t gfs2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
|||
ssize_t ret;
|
||||
|
||||
if (iocb->ki_flags & IOCB_DIRECT) {
|
||||
ret = gfs2_file_direct_read(iocb, to);
|
||||
ret = gfs2_file_direct_read(iocb, to, &gh);
|
||||
if (likely(ret != -ENOTBLK))
|
||||
return ret;
|
||||
iocb->ki_flags &= ~IOCB_DIRECT;
|
||||
|
@ -901,13 +901,12 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
|||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file_inode(file);
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
struct gfs2_holder gh;
|
||||
ssize_t ret;
|
||||
|
||||
gfs2_size_hint(file, iocb->ki_pos, iov_iter_count(from));
|
||||
|
||||
if (iocb->ki_flags & IOCB_APPEND) {
|
||||
struct gfs2_holder gh;
|
||||
|
||||
ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -931,7 +930,7 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
|||
struct address_space *mapping = file->f_mapping;
|
||||
ssize_t buffered, ret2;
|
||||
|
||||
ret = gfs2_file_direct_write(iocb, from);
|
||||
ret = gfs2_file_direct_write(iocb, from, &gh);
|
||||
if (ret < 0 || !iov_iter_count(from))
|
||||
goto out_unlock;
|
||||
|
||||
|
|
|
@ -790,9 +790,11 @@ static void gfs2_glock_poke(struct gfs2_glock *gl)
|
|||
struct gfs2_holder gh;
|
||||
int error;
|
||||
|
||||
error = gfs2_glock_nq_init(gl, LM_ST_SHARED, flags, &gh);
|
||||
gfs2_holder_init(gl, LM_ST_SHARED, flags, &gh);
|
||||
error = gfs2_glock_nq(&gh);
|
||||
if (!error)
|
||||
gfs2_glock_dq(&gh);
|
||||
gfs2_holder_uninit(&gh);
|
||||
}
|
||||
|
||||
static bool gfs2_try_evict(struct gfs2_glock *gl)
|
||||
|
@ -2106,6 +2108,12 @@ static const char *gflags2str(char *buf, const struct gfs2_glock *gl)
|
|||
*p++ = 'o';
|
||||
if (test_bit(GLF_BLOCKING, gflags))
|
||||
*p++ = 'b';
|
||||
if (test_bit(GLF_INODE_CREATING, gflags))
|
||||
*p++ = 'c';
|
||||
if (test_bit(GLF_PENDING_DELETE, gflags))
|
||||
*p++ = 'P';
|
||||
if (test_bit(GLF_FREEING, gflags))
|
||||
*p++ = 'x';
|
||||
*p = 0;
|
||||
return buf;
|
||||
}
|
||||
|
|
|
@ -1092,7 +1092,7 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
|
|||
* or the total number of used blocks (pinned blocks plus AIL blocks)
|
||||
* is greater than thresh2.
|
||||
*
|
||||
* At mount time thresh1 is 1/3rd of journal size, thresh2 is 2/3rd of
|
||||
* At mount time thresh1 is 2/5ths of journal size, thresh2 is 4/5ths of
|
||||
* journal size.
|
||||
*
|
||||
* Returns: errno
|
||||
|
|
|
@ -566,6 +566,7 @@ static void gfs2_dirty_inode(struct inode *inode, int flags)
|
|||
ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
|
||||
if (ret) {
|
||||
fs_err(sdp, "dirty_inode: glock %d\n", ret);
|
||||
gfs2_dump_glock(NULL, ip->i_gl, true);
|
||||
return;
|
||||
}
|
||||
need_unlock = 1;
|
||||
|
|
|
@ -25,13 +25,28 @@
|
|||
#include "util.h"
|
||||
#include "trace_gfs2.h"
|
||||
|
||||
static void gfs2_print_trans(struct gfs2_sbd *sdp, const struct gfs2_trans *tr)
|
||||
{
|
||||
fs_warn(sdp, "Transaction created at: %pSR\n", (void *)tr->tr_ip);
|
||||
fs_warn(sdp, "blocks=%u revokes=%u reserved=%u touched=%u\n",
|
||||
tr->tr_blocks, tr->tr_revokes, tr->tr_reserved,
|
||||
test_bit(TR_TOUCHED, &tr->tr_flags));
|
||||
fs_warn(sdp, "Buf %u/%u Databuf %u/%u Revoke %u/%u\n",
|
||||
tr->tr_num_buf_new, tr->tr_num_buf_rm,
|
||||
tr->tr_num_databuf_new, tr->tr_num_databuf_rm,
|
||||
tr->tr_num_revoke, tr->tr_num_revoke_rm);
|
||||
}
|
||||
|
||||
int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
|
||||
unsigned int revokes)
|
||||
{
|
||||
struct gfs2_trans *tr;
|
||||
int error;
|
||||
|
||||
BUG_ON(current->journal_info);
|
||||
if (current->journal_info) {
|
||||
gfs2_print_trans(sdp, current->journal_info);
|
||||
BUG();
|
||||
}
|
||||
BUG_ON(blocks == 0 && revokes == 0);
|
||||
|
||||
if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))
|
||||
|
@ -72,18 +87,6 @@ fail:
|
|||
return error;
|
||||
}
|
||||
|
||||
static void gfs2_print_trans(struct gfs2_sbd *sdp, const struct gfs2_trans *tr)
|
||||
{
|
||||
fs_warn(sdp, "Transaction created at: %pSR\n", (void *)tr->tr_ip);
|
||||
fs_warn(sdp, "blocks=%u revokes=%u reserved=%u touched=%u\n",
|
||||
tr->tr_blocks, tr->tr_revokes, tr->tr_reserved,
|
||||
test_bit(TR_TOUCHED, &tr->tr_flags));
|
||||
fs_warn(sdp, "Buf %u/%u Databuf %u/%u Revoke %u/%u\n",
|
||||
tr->tr_num_buf_new, tr->tr_num_buf_rm,
|
||||
tr->tr_num_databuf_new, tr->tr_num_databuf_rm,
|
||||
tr->tr_num_revoke, tr->tr_num_revoke_rm);
|
||||
}
|
||||
|
||||
void gfs2_trans_end(struct gfs2_sbd *sdp)
|
||||
{
|
||||
struct gfs2_trans *tr = current->journal_info;
|
||||
|
|
|
@ -2650,7 +2650,7 @@ static inline void filemap_set_wb_err(struct address_space *mapping, int err)
|
|||
}
|
||||
|
||||
/**
|
||||
* filemap_check_wb_error - has an error occurred since the mark was sampled?
|
||||
* filemap_check_wb_err - has an error occurred since the mark was sampled?
|
||||
* @mapping: mapping to check for writeback errors
|
||||
* @since: previously-sampled errseq_t
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue