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 ...@@ -1351,9 +1351,15 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi
return ret; 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, static int gfs2_block_zero_range(struct inode *inode, loff_t from,
unsigned int length) unsigned int length)
{ {
BUG_ON(current->journal_info);
return iomap_zero_range(inode, from, length, NULL, &gfs2_iomap_ops); return iomap_zero_range(inode, from, length, NULL, &gfs2_iomap_ops);
} }
...@@ -1414,6 +1420,16 @@ static int trunc_start(struct inode *inode, u64 newsize) ...@@ -1414,6 +1420,16 @@ static int trunc_start(struct inode *inode, u64 newsize)
u64 oldsize = inode->i_size; u64 oldsize = inode->i_size;
int error; 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) if (journaled)
error = gfs2_trans_begin(sdp, RES_DINODE + RES_JDATA, GFS2_JTRUNC_REVOKES); error = gfs2_trans_begin(sdp, RES_DINODE + RES_JDATA, GFS2_JTRUNC_REVOKES);
else else
...@@ -1427,19 +1443,10 @@ static int trunc_start(struct inode *inode, u64 newsize) ...@@ -1427,19 +1443,10 @@ static int trunc_start(struct inode *inode, u64 newsize)
gfs2_trans_add_meta(ip->i_gl, dibh); 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); gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + newsize);
} else { 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;
}
ip->i_diskflags |= GFS2_DIF_TRUNC_IN_PROG; ip->i_diskflags |= GFS2_DIF_TRUNC_IN_PROG;
}
i_size_write(inode, newsize); i_size_write(inode, newsize);
ip->i_inode.i_mtime = ip->i_inode.i_ctime = current_time(&ip->i_inode); 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) ...@@ -2448,25 +2455,7 @@ int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length)
loff_t start, end; loff_t start, end;
int error; int error;
start = round_down(offset, blocksize); if (!gfs2_is_stuffed(ip)) {
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 {
unsigned int start_off, end_len; unsigned int start_off, end_len;
start_off = offset & (blocksize - 1); start_off = offset & (blocksize - 1);
...@@ -2489,6 +2478,26 @@ int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length) ...@@ -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)) { if (gfs2_is_jdata(ip)) {
BUG_ON(!current->journal_info); BUG_ON(!current->journal_info);
gfs2_journaled_truncate_range(inode, offset, length); gfs2_journaled_truncate_range(inode, offset, length);
......
...@@ -781,39 +781,39 @@ static int gfs2_fsync(struct file *file, loff_t start, loff_t end, ...@@ -781,39 +781,39 @@ static int gfs2_fsync(struct file *file, loff_t start, loff_t end,
return ret ? ret : ret1; 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 file *file = iocb->ki_filp;
struct gfs2_inode *ip = GFS2_I(file->f_mapping->host); struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
size_t count = iov_iter_count(to); size_t count = iov_iter_count(to);
struct gfs2_holder gh;
ssize_t ret; ssize_t ret;
if (!count) if (!count)
return 0; /* skip atime */ return 0; /* skip atime */
gfs2_holder_init(ip->i_gl, LM_ST_DEFERRED, 0, &gh); gfs2_holder_init(ip->i_gl, LM_ST_DEFERRED, 0, gh);
ret = gfs2_glock_nq(&gh); ret = gfs2_glock_nq(gh);
if (ret) if (ret)
goto out_uninit; goto out_uninit;
ret = iomap_dio_rw(iocb, to, &gfs2_iomap_ops, NULL, ret = iomap_dio_rw(iocb, to, &gfs2_iomap_ops, NULL,
is_sync_kiocb(iocb)); is_sync_kiocb(iocb));
gfs2_glock_dq(&gh); gfs2_glock_dq(gh);
out_uninit: out_uninit:
gfs2_holder_uninit(&gh); gfs2_holder_uninit(gh);
return ret; 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 file *file = iocb->ki_filp;
struct inode *inode = file->f_mapping->host; struct inode *inode = file->f_mapping->host;
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);
size_t len = iov_iter_count(from); size_t len = iov_iter_count(from);
loff_t offset = iocb->ki_pos; loff_t offset = iocb->ki_pos;
struct gfs2_holder gh;
ssize_t ret; ssize_t ret;
/* /*
...@@ -824,8 +824,8 @@ static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from) ...@@ -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 * unfortunately, have the option of only flushing a range like the
* VFS does. * VFS does.
*/ */
gfs2_holder_init(ip->i_gl, LM_ST_DEFERRED, 0, &gh); gfs2_holder_init(ip->i_gl, LM_ST_DEFERRED, 0, gh);
ret = gfs2_glock_nq(&gh); ret = gfs2_glock_nq(gh);
if (ret) if (ret)
goto out_uninit; goto out_uninit;
...@@ -838,9 +838,9 @@ static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from) ...@@ -838,9 +838,9 @@ static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from)
if (ret == -ENOTBLK) if (ret == -ENOTBLK)
ret = 0; ret = 0;
out: out:
gfs2_glock_dq(&gh); gfs2_glock_dq(gh);
out_uninit: out_uninit:
gfs2_holder_uninit(&gh); gfs2_holder_uninit(gh);
return ret; return ret;
} }
...@@ -852,7 +852,7 @@ static ssize_t gfs2_file_read_iter(struct kiocb *iocb, struct iov_iter *to) ...@@ -852,7 +852,7 @@ static ssize_t gfs2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
ssize_t ret; ssize_t ret;
if (iocb->ki_flags & IOCB_DIRECT) { 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)) if (likely(ret != -ENOTBLK))
return ret; return ret;
iocb->ki_flags &= ~IOCB_DIRECT; iocb->ki_flags &= ~IOCB_DIRECT;
...@@ -901,13 +901,12 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -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 file *file = iocb->ki_filp;
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_holder gh;
ssize_t ret; ssize_t ret;
gfs2_size_hint(file, iocb->ki_pos, iov_iter_count(from)); gfs2_size_hint(file, iocb->ki_pos, iov_iter_count(from));
if (iocb->ki_flags & IOCB_APPEND) { if (iocb->ki_flags & IOCB_APPEND) {
struct gfs2_holder gh;
ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh); ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
if (ret) if (ret)
return ret; return ret;
...@@ -931,7 +930,7 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -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; struct address_space *mapping = file->f_mapping;
ssize_t buffered, ret2; 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)) if (ret < 0 || !iov_iter_count(from))
goto out_unlock; goto out_unlock;
......
...@@ -790,9 +790,11 @@ static void gfs2_glock_poke(struct gfs2_glock *gl) ...@@ -790,9 +790,11 @@ static void gfs2_glock_poke(struct gfs2_glock *gl)
struct gfs2_holder gh; struct gfs2_holder gh;
int error; 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) if (!error)
gfs2_glock_dq(&gh); gfs2_glock_dq(&gh);
gfs2_holder_uninit(&gh);
} }
static bool gfs2_try_evict(struct gfs2_glock *gl) static bool gfs2_try_evict(struct gfs2_glock *gl)
...@@ -2106,6 +2108,12 @@ static const char *gflags2str(char *buf, const struct gfs2_glock *gl) ...@@ -2106,6 +2108,12 @@ static const char *gflags2str(char *buf, const struct gfs2_glock *gl)
*p++ = 'o'; *p++ = 'o';
if (test_bit(GLF_BLOCKING, gflags)) if (test_bit(GLF_BLOCKING, gflags))
*p++ = 'b'; *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; *p = 0;
return buf; return buf;
} }
......
...@@ -1092,7 +1092,7 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) ...@@ -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) * or the total number of used blocks (pinned blocks plus AIL blocks)
* is greater than thresh2. * 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. * journal size.
* *
* Returns: errno * Returns: errno
......
...@@ -566,6 +566,7 @@ static void gfs2_dirty_inode(struct inode *inode, int flags) ...@@ -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); ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
if (ret) { if (ret) {
fs_err(sdp, "dirty_inode: glock %d\n", ret); fs_err(sdp, "dirty_inode: glock %d\n", ret);
gfs2_dump_glock(NULL, ip->i_gl, true);
return; return;
} }
need_unlock = 1; need_unlock = 1;
......
...@@ -25,13 +25,28 @@ ...@@ -25,13 +25,28 @@
#include "util.h" #include "util.h"
#include "trace_gfs2.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, int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
unsigned int revokes) unsigned int revokes)
{ {
struct gfs2_trans *tr; struct gfs2_trans *tr;
int error; 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); BUG_ON(blocks == 0 && revokes == 0);
if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))
...@@ -72,18 +87,6 @@ int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks, ...@@ -72,18 +87,6 @@ int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
return error; 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) void gfs2_trans_end(struct gfs2_sbd *sdp)
{ {
struct gfs2_trans *tr = current->journal_info; struct gfs2_trans *tr = current->journal_info;
......
...@@ -2650,7 +2650,7 @@ static inline void filemap_set_wb_err(struct address_space *mapping, int err) ...@@ -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 * @mapping: mapping to check for writeback errors
* @since: previously-sampled errseq_t * @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