projects/linux·commit 26064ea4

Merge tag 'gfs2-4.16.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2

26064ea4 · Linus Torvalds <[email protected]> · 2018-01-31 08:55:58 -08:00

Pull GFS2 updates from Bob Peterson:
 "We've got 30 patches for this merge window. These generally fall into
  five categories:

   - code cleanups

   - patches related to adding PUNCH_HOLE support to GFS2

   - support for new fields in resource group headers

   - a few bug fixes

   - support for new fields in journal log headers. These new fields,
     which were previously unused, are designed to make it easier to
     track down file system corruption, and allow fsck.gfs2 to make more
     intelligent decisions when finding and fixing file system
     corruption.

  Details:

   - Two patches from Abhi Das, to trim the ordered writes list, which
     used to grow uncontrollably until unmount.

   - Several patches from Andreas Gruenbacher: remove an unused
     parameter from function gfs2_write_jdata_pagevec, remove a
     pointless BUG_ON, clean up an error patch in trunc_start, remove
     some unused parameters from truncate, make gfs2_journaled_truncate
     more efficient, clean up the support functions for truncate, fix
     metadata read-ahead for truncate to make it faster, fix up the
     non-recursive truncate code, rework and rename
     gfs2_block_truncate_page, generalize the non-recursive truncate
     code so it can take a range of values for punch_hole support,
     introduce new PUNCH_HOLE support that take advantage of the
     previous patches, add fallocate support with PUNCH_HOLE, fix some
     typos in the comments, add the function gfs2_max_stuffed_size to
     replace a piece of code that was needlessly repeated throughout
     GFS2, a minor cleanup to function gfs2_page_add_databufs, get rid
     of function gfs2_log_header_in in preparation for the new log
     header fields, and also fix up some missing newlines in kernel
     messages.

   - Andy Price added a new field to resource groups to indicate where
     the next one should be, to allow fsck.gfs2 to make better repairs.
     He also added new rindex fields for consistency checking, and added
     a crc field to resource group headers for consistency checking.

   - I reduced redundancy in functions common to freeing dinodes, and
     when writing log headers between the journalling code and journal
     recovery code. Also added new fields to journal log headers based
     on a prototype from Steve Whitehouse, and log the source of journal
     log headers so we can better track down journal corruption. Minor
     comment typo fix and a fix for a BUG in an unlink error path.

   - Steve Whitehouse contributed a patch to fix an incorrect use of the
     gfs2_blk2rgrpd function.

   - Tetsuo Handa contributed a patch that fixes incorrect error
     handling in function init_gfs2_fs"

* tag 'gfs2-4.16.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2: (30 commits)
  gfs2: Add a few missing newlines in messages
  gfs2: Remove inode from ordered write list in gfs2_write_inode()
  GFS2: Don't try to end a non-existent transaction in unlink
  GFS2: Fix minor comment typo
  GFS2: Log the reason for log flushes in every log header
  GFS2: Introduce new gfs2_log_header_v2
  gfs2: Get rid of gfs2_log_header_in
  gfs2: Minor gfs2_page_add_databufs cleanup
  gfs2: Add gfs2_max_stuffed_size
  gfs2: Typo fixes
  gfs2: Implement fallocate(FALLOC_FL_PUNCH_HOLE)
  gfs2: Turn trunc_dealloc into punch_hole
  gfs2: Generalize truncate code
  Turn gfs2_block_truncate_page into gfs2_block_zero_range
  gfs2: Improve non-recursive delete algorithm
  gfs2: Fix metadata read-ahead during truncate
  gfs2: Clean up {lookup,fillup}_metapath
  gfs2: Remove minor gfs2_journaled_truncate inefficiencies
  gfs2: truncate: Remove unnecessary oldsize parameters
  gfs2: Clean up trunc_start error path
  ...
Commit
26064ea409b4d4acb05903a36f3fe2fdccb3d8aa
Parents
c9cc8d01 · af38816e

Merge commit. Changes below are compared with the first parent: c9cc8d01.

Changes

24 files changed · +758 −427

FileStatusAddDelContent
fs/gfs2/Kconfigmodified+2−0View file
fs/gfs2/aops.cmodified+18−17View file
fs/gfs2/bmap.cmodified+401−182View file
fs/gfs2/bmap.hmodified+1−0View file
fs/gfs2/dir.cmodified+1−2View file
fs/gfs2/file.cmodified+15−8View file
fs/gfs2/glops.cmodified+13−6View file
fs/gfs2/incore.hmodified+5−1View file
fs/gfs2/inode.cmodified+4−7View file
fs/gfs2/lock_dlm.cmodified+2−2View file
fs/gfs2/log.cmodified+92−32View file
fs/gfs2/log.hmodified+3−7View file
fs/gfs2/lops.cmodified+10−8View file
fs/gfs2/lops.hmodified+3−0View file
fs/gfs2/main.cmodified+44−46View file
fs/gfs2/ops_fstype.cmodified+1−1View file
fs/gfs2/quota.cmodified+2−1View file
fs/gfs2/recovery.cmodified+31−79View file
fs/gfs2/rgrp.cmodified+27−11View file
fs/gfs2/super.cmodified+15−4View file
fs/gfs2/sys.cmodified+2−2View file
fs/gfs2/trace_gfs2.hmodified+7−4View file
fs/gfs2/trans.cmodified+2−2View file
include/uapi/linux/gfs2_ondisk.hmodified+57−5View file

Only the first 600 diff lines are shown. Download the complete patch.

fs/gfs2/Kconfig

View file
diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig
index 43c827a..c0225d4 100644
--- a/fs/gfs2/Kconfig
+++ b/fs/gfs2/Kconfig
@@ -3,6 +3,8 @@ config GFS2_FS
depends on (64BIT || LBDAF)
select FS_POSIX_ACL
select CRC32
+ select CRYPTO
+ select CRYPTO_CRC32C
select QUOTACTL
select FS_IOMAP
help

fs/gfs2/aops.c

View file
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c
index 1daf15a..2f725b4 100644
--- a/fs/gfs2/aops.c
+++ b/fs/gfs2/aops.c
@@ -39,18 +39,21 @@
static void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page,
- unsigned int from, unsigned int to)
+ unsigned int from, unsigned int len)
{
struct buffer_head *head = page_buffers(page);
unsigned int bsize = head->b_size;
struct buffer_head *bh;
+ unsigned int to = from + len;
unsigned int start, end;
for (bh = head, start = 0; bh != head || !start;
bh = bh->b_this_page, start = end) {
end = start + bsize;
- if (end <= from || start >= to)
+ if (end <= from)
continue;
+ if (start >= to)
+ break;
if (gfs2_is_jdata(ip))
set_buffer_uptodate(bh);
gfs2_trans_add_data(ip->i_gl, bh);
@@ -189,7 +192,7 @@ static int __gfs2_jdata_writepage(struct page *page, struct writeback_control *w
create_empty_buffers(page, inode->i_sb->s_blocksize,
BIT(BH_Dirty)|BIT(BH_Uptodate));
}
- gfs2_page_add_databufs(ip, page, 0, sdp->sd_vfs->s_blocksize-1);
+ gfs2_page_add_databufs(ip, page, 0, sdp->sd_vfs->s_blocksize);
}
return gfs2_write_full_page(page, gfs2_get_block_noalloc, wbc);
}
@@ -255,7 +258,6 @@ static int gfs2_writepages(struct address_space *mapping,
* @wbc: The writeback control
* @pvec: The vector of pages
* @nr_pages: The number of pages to write
- * @end: End position
* @done_index: Page index
*
* Returns: non-zero if loop should terminate, zero otherwise
@@ -264,7 +266,7 @@ static int gfs2_writepages(struct address_space *mapping,
static int gfs2_write_jdata_pagevec(struct address_space *mapping,
struct writeback_control *wbc,
struct pagevec *pvec,
- int nr_pages, pgoff_t end,
+ int nr_pages,
pgoff_t *done_index)
{
struct inode *inode = mapping->host;
@@ -402,7 +404,7 @@ retry:
if (nr_pages == 0)
break;
- ret = gfs2_write_jdata_pagevec(mapping, wbc, &pvec, nr_pages, end, &done_index);
+ ret = gfs2_write_jdata_pagevec(mapping, wbc, &pvec, nr_pages, &done_index);
if (ret)
done = 1;
if (ret > 0)
@@ -446,7 +448,8 @@ static int gfs2_jdata_writepages(struct address_space *mapping,
ret = gfs2_write_cache_jdata(mapping, wbc);
if (ret == 0 && wbc->sync_mode == WB_SYNC_ALL) {
- gfs2_log_flush(sdp, ip->i_gl, NORMAL_FLUSH);
+ gfs2_log_flush(sdp, ip->i_gl, GFS2_LOG_HEAD_FLUSH_NORMAL |
+ GFS2_LFC_JDATA_WPAGES);
ret = gfs2_write_cache_jdata(mapping, wbc);
}
return ret;
@@ -483,8 +486,8 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
return error;
kaddr = kmap_atomic(page);
- if (dsize > (dibh->b_size - sizeof(struct gfs2_dinode)))
- dsize = (dibh->b_size - sizeof(struct gfs2_dinode));
+ if (dsize > gfs2_max_stuffed_size(ip))
+ dsize = gfs2_max_stuffed_size(ip);
memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode), dsize);
memset(kaddr + dsize, 0, PAGE_SIZE - dsize);
kunmap_atomic(kaddr);
@@ -501,10 +504,9 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
* @file: The file to read a page for
* @page: The page to read
*
- * This is the core of gfs2's readpage. Its used by the internal file
- * reading code as in that case we already hold the glock. Also its
+ * This is the core of gfs2's readpage. It's used by the internal file
+ * reading code as in that case we already hold the glock. Also it's
* called by gfs2_readpage() once the required lock has been granted.
- *
*/
static int __gfs2_readpage(void *file, struct page *page)
@@ -725,7 +727,7 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
if (gfs2_is_stuffed(ip)) {
error = 0;
- if (pos + len > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) {
+ if (pos + len > gfs2_max_stuffed_size(ip)) {
error = gfs2_unstuff_dinode(ip, page);
if (error == 0)
goto prepare_write;
@@ -832,7 +834,8 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
void *kaddr;
unsigned char *buf = dibh->b_data + sizeof(struct gfs2_dinode);
- BUG_ON((pos + len) > (dibh->b_size - sizeof(struct gfs2_dinode)));
+ BUG_ON(pos + len > gfs2_max_stuffed_size(ip));
+
kaddr = kmap_atomic(page);
memcpy(buf + pos, kaddr + pos, copied);
flush_dcache_page(page);
@@ -890,8 +893,6 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
struct gfs2_sbd *sdp = GFS2_SB(inode);
struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
struct buffer_head *dibh;
- unsigned int from = pos & (PAGE_SIZE - 1);
- unsigned int to = from + len;
int ret;
struct gfs2_trans *tr = current->journal_info;
BUG_ON(!tr);
@@ -909,7 +910,7 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
return gfs2_stuffed_write_end(inode, dibh, pos, len, copied, page);
if (!gfs2_is_writeback(ip))
- gfs2_page_add_databufs(ip, page, from, to);
+ gfs2_page_add_databufs(ip, page, pos & ~PAGE_MASK, len);
ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
if (tr->tr_num_buf_new)

fs/gfs2/bmap.c

View file
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index d5f0d96..8686379 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -69,8 +69,8 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
void *kaddr = kmap(page);
u64 dsize = i_size_read(inode);
- if (dsize > (dibh->b_size - sizeof(struct gfs2_dinode)))
- dsize = dibh->b_size - sizeof(struct gfs2_dinode);
+ if (dsize > gfs2_max_stuffed_size(ip))
+ dsize = gfs2_max_stuffed_size(ip);
memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode), dsize);
memset(kaddr + dsize, 0, PAGE_SIZE - dsize);
@@ -279,14 +279,13 @@ static inline __be64 *metapointer(unsigned int height, const struct metapath *mp
return p + mp->mp_list[height];
}
-static void gfs2_metapath_ra(struct gfs2_glock *gl,
- const struct buffer_head *bh, const __be64 *pos)
+static void gfs2_metapath_ra(struct gfs2_glock *gl, __be64 *start, __be64 *end)
{
- struct buffer_head *rabh;
- const __be64 *endp = (const __be64 *)(bh->b_data + bh->b_size);
const __be64 *t;
- for (t = pos; t < endp; t++) {
+ for (t = start; t < end; t++) {
+ struct buffer_head *rabh;
+
if (!*t)
continue;
@@ -305,21 +304,22 @@ static void gfs2_metapath_ra(struct gfs2_glock *gl,
}
}
-/**
- * lookup_mp_height - helper function for lookup_metapath
- * @ip: the inode
- * @mp: the metapath
- * @h: the height which needs looking up
- */
-static int lookup_mp_height(struct gfs2_inode *ip, struct metapath *mp, int h)
+static int __fillup_metapath(struct gfs2_inode *ip, struct metapath *mp,
+ unsigned int x, unsigned int h)
{
- __be64 *ptr = metapointer(h, mp);
- u64 dblock = be64_to_cpu(*ptr);
-
- if (!dblock)
- return h + 1;
+ for (; x < h; x++) {
+ __be64 *ptr = metapointer(x, mp);
+ u64 dblock = be64_to_cpu(*ptr);
+ int ret;
- return gfs2_meta_indirect_buffer(ip, h + 1, dblock, &mp->mp_bh[h + 1]);
+ if (!dblock)
+ break;
+ ret = gfs2_meta_indirect_buffer(ip, x + 1, dblock, &mp->mp_bh[x + 1]);
+ if (ret)
+ return ret;
+ }
+ mp->mp_aheight = x + 1;
+ return 0;
}
/**
@@ -336,25 +336,12 @@ static int lookup_mp_height(struct gfs2_inode *ip, struct metapath *mp, int h)
* at which it found the unallocated block. Blocks which are found are
* added to the mp->mp_bh[] list.
*
- * Returns: error or height of metadata tree
+ * Returns: error
*/
static int lookup_metapath(struct gfs2_inode *ip, struct metapath *mp)
{
- unsigned int end_of_metadata = ip->i_height - 1;
- unsigned int x;
- int ret;
-
- for (x = 0; x < end_of_metadata; x++) {
- ret = lookup_mp_height(ip, mp, x);
- if (ret)
- goto out;
- }
-
- ret = ip->i_height;
-out:
- mp->mp_aheight = ret;
- return ret;
+ return __fillup_metapath(ip, mp, 0, ip->i_height - 1);
}
/**
@@ -365,25 +352,25 @@ out:
*
* Similar to lookup_metapath, but does lookups for a range of heights
*
- * Returns: error or height of metadata tree
+ * Returns: error or the number of buffers filled
*/
static int fillup_metapath(struct gfs2_inode *ip, struct metapath *mp, int h)
{
- unsigned int start_h = h - 1;
+ unsigned int x = 0;
int ret;
if (h) {
/* find the first buffer we need to look up. */
- while (start_h > 0 && mp->mp_bh[start_h] == NULL)
- start_h--;
- for (; start_h < h; start_h++) {
- ret = lookup_mp_height(ip, mp, start_h);
- if (ret)
- return ret;
+ for (x = h - 1; x > 0; x--) {
+ if (mp->mp_bh[x])
+ break;
}
}
- return ip->i_height;
+ ret = __fillup_metapath(ip, mp, x, h);
+ if (ret)
+ return ret;
+ return mp->mp_aheight - x - 1;
}
static inline void release_metapath(struct metapath *mp)
@@ -474,13 +461,6 @@ enum alloc_state {
/* ALLOC_UNSTUFF = 3, TBD and rather complicated */
};
-static inline unsigned int hptrs(struct gfs2_sbd *sdp, const unsigned int hgt)
-{
- if (hgt)
- return sdp->sd_inptrs;
- return sdp->sd_diptrs;
-}
-
/**
* gfs2_bmap_alloc - Build a metadata tree of the requested height
* @inode: The GFS2 inode
@@ -788,7 +768,7 @@ int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length,
goto do_alloc;
ret = lookup_metapath(ip, &mp);
- if (ret < 0)
+ if (ret)
goto out_release;
if (mp.mp_aheight != ip->i_height)
@@ -913,17 +893,18 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi
}
/**
- * gfs2_block_truncate_page - Deal with zeroing out data for truncate
+ * gfs2_block_zero_range - Deal with zeroing out data
*
* This is partly borrowed from ext3.
*/
-static int gfs2_block_truncate_page(struct address_space *mapping, loff_t from)
+static int gfs2_block_zero_range(struct inode *inode, loff_t from,
+ unsigned int length)
{
- struct inode *inode = mapping->host;
+ struct address_space *mapping = inode->i_mapping;
struct gfs2_inode *ip = GFS2_I(inode);
unsigned long index = from >> PAGE_SHIFT;
unsigned offset = from & (PAGE_SIZE-1);
- unsigned blocksize, iblock, length, pos;
+ unsigned blocksize, iblock, pos;
struct buffer_head *bh;
struct page *page;
int err;
@@ -933,7 +914,6 @@ static int gfs2_block_truncate_page(struct address_space *mapping, loff_t from)
return 0;
blocksize = inode->i_sb->s_blocksize;
- length = blocksize - (offset & (blocksize - 1));
iblock = index << (PAGE_SHIFT - inode->i_sb->s_blocksize_bits);
if (!page_has_buffers(page))
@@ -1003,11 +983,24 @@ static int gfs2_journaled_truncate(struct inode *inode, u64 oldsize, u64 newsize
int error;
while (oldsize != newsize) {
+ struct gfs2_trans *tr;
+ unsigned int offs;
+
chunk = oldsize - newsize;
if (chunk > max_chunk)
chunk = max_chunk;
+
+ offs = oldsize & ~PAGE_MASK;
+ if (offs && chunk > PAGE_SIZE)
+ chunk = offs + ((chunk - offs) & PAGE_MASK);
+
truncate_pagecache(inode, oldsize - chunk);
oldsize -= chunk;
+
+ tr = current->journal_info;
+ if (!test_bit(TR_TOUCHED, &tr->tr_flags))
+ continue;
+
gfs2_trans_end(sdp);
error = gfs2_trans_begin(sdp, RES_DINODE, GFS2_JTRUNC_REVOKES);
if (error)
@@ -1017,13 +1010,13 @@ static int gfs2_journaled_truncate(struct inode *inode, u64 oldsize, u64 newsize
return 0;
}
-static int trunc_start(struct inode *inode, u64 oldsize, u64 newsize)
+static int trunc_start(struct inode *inode, u64 newsize)
{
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode);
- struct address_space *mapping = inode->i_mapping;
- struct buffer_head *dibh;
+ struct buffer_head *dibh = NULL;
int journaled = gfs2_is_jdata(ip);
+ u64 oldsize = inode->i_size;
int error;
if (journaled)
@@ -1042,10 +1035,13 @@ static int trunc_start(struct inode *inode, u64 oldsize, u64 newsize)
if (gfs2_is_stuffed(ip)) {
gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + newsize);
} else {
- if (newsize & (u64)(sdp->sd_sb.sb_bsize - 1)) {
- error = gfs2_block_truncate_page(mapping, newsize);
+ 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_brelse;
+ goto out;
}
ip->i_diskflags |= GFS2_DIF_TRUNC_IN_PROG;
}
@@ -1059,15 +1055,10 @@ static int trunc_start(struct inode *inode, u64 oldsize, u64 newsize)
else
truncate_pagecache(inode, newsize);
- if (error) {
- brelse(dibh);
- return error;
- }
-
-out_brelse:
- brelse(dibh);
out:
- gfs2_trans_end(sdp);
+ brelse(dibh);
+ if (current->journal_info)
+ gfs2_trans_end(sdp);
return error;
}
@@ -1075,10 +1066,11 @@ out:
* sweep_bh_for_rgrps - find an rgrp in a meta buffer and free blocks therein
* @ip: inode
* @rg_gh: holder of resource group glock
- * @mp: current metapath fully populated with buffers
+ * @bh: buffer head to sweep
+ * @start: starting point in bh
+ * @end: end point in bh
+ * @meta: true if bh points to metadata (rather than data)
* @btotal: place to keep count of total blocks freed
- * @hgt: height we're processing
- * @first: true if this is the first call to this function for this height
*
* We sweep a metadata buffer (provided by the metapath) for blocks we need to
* free, and free them all. However, we do it one rgrp at a time. If this
@@ -1093,47 +1085,46 @@ out:
* *btotal has the total number of blocks freed
*/
static int sweep_bh_for_rgrps(struct gfs2_inode *ip, struct gfs2_holder *rd_gh,
- const struct metapath *mp, u32 *btotal, int hgt,
- bool preserve1)
+ struct buffer_head *bh, __be64 *start, __be64 *end,
+ bool meta, u32 *btotal)
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_rgrpd *rgd;
struct gfs2_trans *tr;
- struct buffer_head *bh = mp->mp_bh[hgt];
- __be64 *top, *bottom, *p;
+ __be64 *p;
int blks_outside_rgrp;
u64 bn, bstart, isize_blks;
s64 blen; /* needs to be s64 or gfs2_add_inode_blocks breaks */
- int meta = ((hgt != ip->i_height - 1) ? 1 : 0);
int ret = 0;
bool buf_in_tr = false; /* buffer was added to transaction */
- if (gfs2_metatype_check(sdp, bh,
- (hgt ? GFS2_METATYPE_IN : GFS2_METATYPE_DI)))
- return -EIO;
-
more_rgrps:
+ rgd = NULL;
+ if (gfs2_holder_initialized(rd_gh)) {
+ rgd = gfs2_glock2rgrp(rd_gh->gh_gl);
+ gfs2_assert_withdraw(sdp,
+ gfs2_glock_is_locked_by_me(rd_gh->gh_gl));
+ }
blks_outside_rgrp = 0;
bstart = 0;
blen = 0;
- top = metapointer(hgt, mp); /* first ptr from metapath */
- /* If we're keeping some data at the truncation point, we've got to
- preserve the metadata tree by adding 1 to the starting metapath. */
- if (preserve1)
- top++;
- bottom = (__be64 *)(bh->b_data + bh->b_size);
-
- for (p = top; p < bottom; p++) {
+ for (p = start; p < end; p++) {
if (!*p)
continue;
bn = be64_to_cpu(*p);
- if (gfs2_holder_initialized(rd_gh)) {
- rgd = gfs2_glock2rgrp(rd_gh->gh_gl);
- gfs2_assert_withdraw(sdp,
- gfs2_glock_is_locked_by_me(rd_gh->gh_gl));
+
+ if (rgd) {
+ if (!rgrp_contains_block(rgd, bn)) {
+ blks_outside_rgrp++;
+ continue;
+ }
} else {
- rgd = gfs2_blk2rgrpd(sdp, bn, false);
+ rgd = gfs2_blk2rgrpd(sdp, bn, true);
+ if (unlikely(!rgd)) {
+ ret = -EIO;
+ goto out;
+ }
ret = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,
0, rd_gh);
if (ret)
@@ -1145,11 +1136,6 @@ more_rgrps:
gfs2_rs_deltree(&ip->i_res);
}
- if (!rgrp_contains_block(rgd, bn)) {
- blks_outside_rgrp++;
- continue;
- }
-
/* The size of our transactions will be unknown until we
actually process all the metadata blocks that relate to
the rgrp. So we estimate. We know it can't be more than
@@ -1168,7 +1154,7 @@ more_rgrps:
jblocks_rqsted += isize_blks;
revokes = jblocks_rqsted;
if (meta)
- revokes += hptrs(sdp, hgt);
+ revokes += end - start;
else if (ip->i_depth)
revokes += sdp->sd_inptrs;
ret = gfs2_trans_begin(sdp, jblocks_rqsted, revokes);
@@ -1226,7 +1212,11 @@ out_unlock:
outside the rgrp we just processed,
do it all over again. */
if (current->journal_info) {
- struct buffer_head *dibh = mp->mp_bh[0];
+ struct buffer_head *dibh;
+
+ ret = gfs2_meta_inode_buffer(ip, &dibh);
+ if (ret)
+ goto out;
/* Every transaction boundary, we rewrite the dinode
to keep its di_blocks current in case of failure. */
@@ -1234,6 +1224,7 @@ out_unlock:
current_time(&ip->i_inode);
gfs2_trans_add_meta(ip->i_gl, dibh);
gfs2_dinode_out(ip, dibh->b_data);
+ brelse(dibh);
up_write(&ip->i_rw_mutex);
gfs2_trans_end(sdp);
}
@@ -1245,38 +1236,48 @@ out:
return ret;
}
+static bool mp_eq_to_hgt(struct metapath *mp, __u16 *list, unsigned int h)
+{
+ if (memcmp(mp->mp_list, list, h * sizeof(mp->mp_list[0])))
+ return false;
+ return true;
+}
+
/**
* find_nonnull_ptr - find a non-null pointer given a metapath and height
- * assumes the metapath is valid (with buffers) out to height h
* @mp: starting metapath
* @h: desired height to search
*
+ * Assumes the metapath is valid (with buffers) out to height h.
* Returns: true if a non-null pointer was found in the metapath buffer
* false if all remaining pointers are NULL in the buffer
*/
static bool find_nonnull_ptr(struct gfs2_sbd *sdp, struct metapath *mp,
- unsigned int h)
+ unsigned int h,
+ __u16 *end_list, unsigned int end_aligned)
{
- __be64 *ptr;
- unsigned int ptrs = hptrs(sdp, h) - 1;
+ struct buffer_head *bh = mp->mp_bh[h];
+ __be64 *first, *ptr, *end;
+
+ first = metaptr1(h, mp);
+ ptr = first + mp->mp_list[h];
+ end = (__be64 *)(bh->b_data + bh->b_size);
+ if (end_list && mp_eq_to_hgt(mp, end_list, h)) {
+ bool keep_end = h < end_aligned;
+ end = first + end_list[h] + keep_end;
+ }
- while (true) {
- ptr = metapointer(h, mp);
+ while (ptr < end) {
if (*ptr) { /* if we have a non-null pointer */
- /* Now zero the metapath after the current height. */
+ mp->mp_list[h] = ptr - first;
h++;
if (h < GFS2_MAX_META_HEIGHT)
- memset(&mp->mp_list[h], 0,
- (GFS2_MAX_META_HEIGHT - h) *
- sizeof(mp->mp_list[0]));
+ mp->mp_list[h] = 0;
return true;
}
-
- if (mp->mp_list[h] < ptrs)
- mp->mp_list[h]++;
- else
- return false; /* no more pointers in this buffer */
+ ptr++;
}
+ return false;
}

This diff is incomplete. Download the complete patch.

fs/gfs2/bmap.h

View file

This diff is incomplete. Download the complete patch.

fs/gfs2/dir.c

View file

This diff is incomplete. Download the complete patch.

fs/gfs2/file.c

View file

This diff is incomplete. Download the complete patch.

fs/gfs2/glops.c

View file

This diff is incomplete. Download the complete patch.

fs/gfs2/incore.h

View file

This diff is incomplete. Download the complete patch.

fs/gfs2/inode.c

View file

This diff is incomplete. Download the complete patch.

fs/gfs2/lock_dlm.c

View file

This diff is incomplete. Download the complete patch.

fs/gfs2/log.c

View file

This diff is incomplete. Download the complete patch.

fs/gfs2/log.h

View file

This diff is incomplete. Download the complete patch.

fs/gfs2/lops.c

View file

This diff is incomplete. Download the complete patch.

fs/gfs2/lops.h

View file

This diff is incomplete. Download the complete patch.

fs/gfs2/main.c

View file

This diff is incomplete. Download the complete patch.

fs/gfs2/ops_fstype.c

View file

This diff is incomplete. Download the complete patch.

fs/gfs2/quota.c

View file

This diff is incomplete. Download the complete patch.

fs/gfs2/recovery.c

View file

This diff is incomplete. Download the complete patch.

fs/gfs2/rgrp.c

View file

This diff is incomplete. Download the complete patch.

fs/gfs2/super.c

View file

This diff is incomplete. Download the complete patch.

fs/gfs2/sys.c

View file

This diff is incomplete. Download the complete patch.

fs/gfs2/trace_gfs2.h

View file

This diff is incomplete. Download the complete patch.

fs/gfs2/trans.c

View file

This diff is incomplete. Download the complete patch.

include/uapi/linux/gfs2_ondisk.h

View file

This diff is incomplete. Download the complete patch.