Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 970e4936 authored by Joel Becker's avatar Joel Becker Committed by Mark Fasheh
Browse files

ocfs2: Validate metadata only when it's read from disk.



Add an optional validation hook to ocfs2_read_blocks().  Now the
validation function is only called when a block was actually read off of
disk.  It is not called when the buffer was in cache.

We add a buffer state bit BH_NeedsValidate to flag these buffers.  It
must always be one higher than the last JBD2 buffer state bit.

The dinode, dirblock, extent_block, and xattr_block validators are
lifted to this scheme directly.  The group_descriptor validator needs to
be split into two pieces.  The first part only needs the gd buffer and
is passed to ocfs2_read_block().  The second part requires the dinode as
well, and is called every time.  It's only 3 compares, so it's tiny.
This also allows us to clean up the non-fatal gd check used by resize.c.
It now has no magic argument.

Signed-off-by: default avatarJoel Becker <joel.becker@oracle.com>
Signed-off-by: default avatarMark Fasheh <mfasheh@suse.com>
parent 4ae1d69b
Loading
Loading
Loading
Loading
+6 −11
Original line number Original line Diff line number Diff line
@@ -684,6 +684,9 @@ static int ocfs2_validate_extent_block(struct super_block *sb,
	struct ocfs2_extent_block *eb =
	struct ocfs2_extent_block *eb =
		(struct ocfs2_extent_block *)bh->b_data;
		(struct ocfs2_extent_block *)bh->b_data;


	mlog(0, "Validating extent block %llu\n",
	     (unsigned long long)bh->b_blocknr);

	if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
	if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
		ocfs2_error(sb,
		ocfs2_error(sb,
			    "Extent block #%llu has bad signature %.*s",
			    "Extent block #%llu has bad signature %.*s",
@@ -719,21 +722,13 @@ int ocfs2_read_extent_block(struct inode *inode, u64 eb_blkno,
	int rc;
	int rc;
	struct buffer_head *tmp = *bh;
	struct buffer_head *tmp = *bh;


	rc = ocfs2_read_block(inode, eb_blkno, &tmp);
	rc = ocfs2_read_block(inode, eb_blkno, &tmp,
	if (rc)
			      ocfs2_validate_extent_block);
		goto out;

	rc = ocfs2_validate_extent_block(inode->i_sb, tmp);
	if (rc) {
		brelse(tmp);
		goto out;
	}


	/* If ocfs2_read_block() got us a new bh, pass it up. */
	/* If ocfs2_read_block() got us a new bh, pass it up. */
	if (!*bh)
	if (!rc && !*bh)
		*bh = tmp;
		*bh = tmp;


out:
	return rc;
	return rc;
}
}


+32 −1
Original line number Original line Diff line number Diff line
@@ -39,6 +39,19 @@


#include "buffer_head_io.h"
#include "buffer_head_io.h"


/*
 * Bits on bh->b_state used by ocfs2.
 *
 * These MUST be after the JBD2 bits.  Currently BH_Unshadow is the last
 * JBD2 bit.
 */
enum ocfs2_state_bits {
	BH_NeedsValidate = BH_Unshadow + 1,
};

/* Expand the magic b_state functions */
BUFFER_FNS(NeedsValidate, needs_validate);

int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
		      struct inode *inode)
		      struct inode *inode)
{
{
@@ -166,7 +179,9 @@ int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block,
}
}


int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,
int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,
		      struct buffer_head *bhs[], int flags)
		      struct buffer_head *bhs[], int flags,
		      int (*validate)(struct super_block *sb,
				      struct buffer_head *bh))
{
{
	int status = 0;
	int status = 0;
	int i, ignore_cache = 0;
	int i, ignore_cache = 0;
@@ -298,6 +313,8 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,


			clear_buffer_uptodate(bh);
			clear_buffer_uptodate(bh);
			get_bh(bh); /* for end_buffer_read_sync() */
			get_bh(bh); /* for end_buffer_read_sync() */
			if (validate)
				set_buffer_needs_validate(bh);
			bh->b_end_io = end_buffer_read_sync;
			bh->b_end_io = end_buffer_read_sync;
			submit_bh(READ, bh);
			submit_bh(READ, bh);
			continue;
			continue;
@@ -328,6 +345,20 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,
				bhs[i] = NULL;
				bhs[i] = NULL;
				continue;
				continue;
			}
			}

			if (buffer_needs_validate(bh)) {
				/* We never set NeedsValidate if the
				 * buffer was held by the journal, so
				 * that better not have changed */
				BUG_ON(buffer_jbd(bh));
				clear_buffer_needs_validate(bh);
				status = validate(inode->i_sb, bh);
				if (status) {
					put_bh(bh);
					bhs[i] = NULL;
					continue;
				}
			}
		}
		}


		/* Always set the buffer in the cache, even if it was
		/* Always set the buffer in the cache, even if it was
+16 −11
Original line number Original line Diff line number Diff line
@@ -31,21 +31,24 @@
void ocfs2_end_buffer_io_sync(struct buffer_head *bh,
void ocfs2_end_buffer_io_sync(struct buffer_head *bh,
			     int uptodate);
			     int uptodate);


static inline int ocfs2_read_block(struct inode	       *inode,
				   u64                  off,
				   struct buffer_head **bh);

int ocfs2_write_block(struct ocfs2_super          *osb,
int ocfs2_write_block(struct ocfs2_super          *osb,
		      struct buffer_head  *bh,
		      struct buffer_head  *bh,
		      struct inode        *inode);
		      struct inode        *inode);
int ocfs2_read_blocks(struct inode	  *inode,
		      u64                  block,
		      int                  nr,
		      struct buffer_head  *bhs[],
		      int                  flags);
int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block,
int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block,
			   unsigned int nr, struct buffer_head *bhs[]);
			   unsigned int nr, struct buffer_head *bhs[]);


/*
 * If not NULL, validate() will be called on a buffer that is freshly
 * read from disk.  It will not be called if the buffer was in cache.
 * Note that if validate() is being used for this buffer, it needs to
 * be set even for a READAHEAD call, as it marks the buffer for later
 * validation.
 */
int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,
		      struct buffer_head *bhs[], int flags,
		      int (*validate)(struct super_block *sb,
				      struct buffer_head *bh));

int ocfs2_write_super_or_backup(struct ocfs2_super *osb,
int ocfs2_write_super_or_backup(struct ocfs2_super *osb,
				struct buffer_head *bh);
				struct buffer_head *bh);


@@ -53,7 +56,9 @@ int ocfs2_write_super_or_backup(struct ocfs2_super *osb,
#define OCFS2_BH_READAHEAD         8
#define OCFS2_BH_READAHEAD         8


static inline int ocfs2_read_block(struct inode *inode, u64 off,
static inline int ocfs2_read_block(struct inode *inode, u64 off,
				   struct buffer_head **bh)
				   struct buffer_head **bh,
				   int (*validate)(struct super_block *sb,
						   struct buffer_head *bh))
{
{
	int status = 0;
	int status = 0;


@@ -63,7 +68,7 @@ static inline int ocfs2_read_block(struct inode *inode, u64 off,
		goto bail;
		goto bail;
	}
	}


	status = ocfs2_read_blocks(inode, off, 1, bh, 0);
	status = ocfs2_read_blocks(inode, off, 1, bh, 0, validate);


bail:
bail:
	return status;
	return status;
+4 −9
Original line number Original line Diff line number Diff line
@@ -214,6 +214,8 @@ static int ocfs2_validate_dir_block(struct super_block *sb,
	 * Nothing yet.  We don't validate dirents here, that's handled
	 * Nothing yet.  We don't validate dirents here, that's handled
	 * in-place when the code walks them.
	 * in-place when the code walks them.
	 */
	 */
	mlog(0, "Validating dirblock %llu\n",
	     (unsigned long long)bh->b_blocknr);


	return 0;
	return 0;
}
}
@@ -255,20 +257,13 @@ static int ocfs2_read_dir_block(struct inode *inode, u64 v_block,
		goto out;
		goto out;
	}
	}


	rc = ocfs2_read_blocks(inode, p_blkno, 1, &tmp, flags);
	rc = ocfs2_read_blocks(inode, p_blkno, 1, &tmp, flags,
			       ocfs2_validate_dir_block);
	if (rc) {
	if (rc) {
		mlog_errno(rc);
		mlog_errno(rc);
		goto out;
		goto out;
	}
	}


	if (!(flags & OCFS2_BH_READAHEAD)) {
		rc = ocfs2_validate_dir_block(inode->i_sb, tmp);
		if (rc) {
			brelse(tmp);
			goto out;
		}
	}

	/* If ocfs2_read_blocks() got us a new bh, pass it up.  */
	/* If ocfs2_read_blocks() got us a new bh, pass it up.  */
	if (!*bh)
	if (!*bh)
		*bh = tmp;
		*bh = tmp;
+5 −13
Original line number Original line Diff line number Diff line
@@ -1255,6 +1255,9 @@ int ocfs2_validate_inode_block(struct super_block *sb,
	int rc = -EINVAL;
	int rc = -EINVAL;
	struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data;
	struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data;


	mlog(0, "Validating dinode %llu\n",
	     (unsigned long long)bh->b_blocknr);

	BUG_ON(!buffer_uptodate(bh));
	BUG_ON(!buffer_uptodate(bh));


	if (!OCFS2_IS_VALID_DINODE(di)) {
	if (!OCFS2_IS_VALID_DINODE(di)) {
@@ -1300,23 +1303,12 @@ int ocfs2_read_inode_block_full(struct inode *inode, struct buffer_head **bh,
	struct buffer_head *tmp = *bh;
	struct buffer_head *tmp = *bh;


	rc = ocfs2_read_blocks(inode, OCFS2_I(inode)->ip_blkno, 1, &tmp,
	rc = ocfs2_read_blocks(inode, OCFS2_I(inode)->ip_blkno, 1, &tmp,
			       flags);
			       flags, ocfs2_validate_inode_block);
	if (rc)
		goto out;

	if (!(flags & OCFS2_BH_READAHEAD)) {
		rc = ocfs2_validate_inode_block(inode->i_sb, tmp);
		if (rc) {
			brelse(tmp);
			goto out;
		}
	}


	/* If ocfs2_read_blocks() got us a new bh, pass it up. */
	/* If ocfs2_read_blocks() got us a new bh, pass it up. */
	if (!*bh)
	if (!rc && !*bh)
		*bh = tmp;
		*bh = tmp;


out:
	return rc;
	return rc;
}
}


Loading