Commit 8c2618a6 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 163c3e3d e28c02b9
......@@ -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 @@ int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
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
*
......
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