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

Commit 300df7dc authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jlbec/ocfs2:
  ocfs2/net: Use wait_event() in o2net_send_message_vec()
  ocfs2: Adjust rightmost path in ocfs2_add_branch.
  ocfs2: fdatasync should skip unimportant metadata writeout
  ocfs2: Remove redundant gotos in ocfs2_mount_volume()
  ocfs2: Add statistics for the checksum and ecc operations.
  ocfs2 patch to track delayed orphan scan timer statistics
  ocfs2: timer to queue scan of all orphan slots
  ocfs2: Correct ordering of ip_alloc_sem and localloc locks for directories
  ocfs2: Fix possible deadlock in quota recovery
  ocfs2: Fix possible deadlock with quotas in ocfs2_setattr()
  ocfs2: Fix lock inversion in ocfs2_local_read_info()
  ocfs2: Fix possible deadlock in ocfs2_global_read_dquot()
  ocfs2: update comments in masklog.h
  ocfs2: Don't printk the error when listing too many xattrs.
parents 661adc42 9af0b38f
Loading
Loading
Loading
Loading
+76 −4
Original line number Diff line number Diff line
@@ -475,6 +475,12 @@ struct ocfs2_path {
#define path_leaf_el(_path) ((_path)->p_node[(_path)->p_tree_depth].el)
#define path_num_items(_path) ((_path)->p_tree_depth + 1)

static int ocfs2_find_path(struct inode *inode, struct ocfs2_path *path,
			   u32 cpos);
static void ocfs2_adjust_rightmost_records(struct inode *inode,
					   handle_t *handle,
					   struct ocfs2_path *path,
					   struct ocfs2_extent_rec *insert_rec);
/*
 * Reset the actual path elements so that we can re-use the structure
 * to build another path. Generally, this involves freeing the buffer
@@ -1012,6 +1018,54 @@ static inline u32 ocfs2_sum_rightmost_rec(struct ocfs2_extent_list *el)
		ocfs2_rec_clusters(el, &el->l_recs[i]);
}

/*
 * Change range of the branches in the right most path according to the leaf
 * extent block's rightmost record.
 */
static int ocfs2_adjust_rightmost_branch(handle_t *handle,
					 struct inode *inode,
					 struct ocfs2_extent_tree *et)
{
	int status;
	struct ocfs2_path *path = NULL;
	struct ocfs2_extent_list *el;
	struct ocfs2_extent_rec *rec;

	path = ocfs2_new_path_from_et(et);
	if (!path) {
		status = -ENOMEM;
		return status;
	}

	status = ocfs2_find_path(inode, path, UINT_MAX);
	if (status < 0) {
		mlog_errno(status);
		goto out;
	}

	status = ocfs2_extend_trans(handle, path_num_items(path) +
				    handle->h_buffer_credits);
	if (status < 0) {
		mlog_errno(status);
		goto out;
	}

	status = ocfs2_journal_access_path(inode, handle, path);
	if (status < 0) {
		mlog_errno(status);
		goto out;
	}

	el = path_leaf_el(path);
	rec = &el->l_recs[le32_to_cpu(el->l_next_free_rec) - 1];

	ocfs2_adjust_rightmost_records(inode, handle, path, rec);

out:
	ocfs2_free_path(path);
	return status;
}

/*
 * Add an entire tree branch to our inode. eb_bh is the extent block
 * to start at, if we don't want to start the branch at the dinode
@@ -1038,7 +1092,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
	struct ocfs2_extent_block *eb;
	struct ocfs2_extent_list  *eb_el;
	struct ocfs2_extent_list  *el;
	u32 new_cpos;
	u32 new_cpos, root_end;

	mlog_entry_void();

@@ -1055,6 +1109,27 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,

	new_blocks = le16_to_cpu(el->l_tree_depth);

	eb = (struct ocfs2_extent_block *)(*last_eb_bh)->b_data;
	new_cpos = ocfs2_sum_rightmost_rec(&eb->h_list);
	root_end = ocfs2_sum_rightmost_rec(et->et_root_el);

	/*
	 * If there is a gap before the root end and the real end
	 * of the righmost leaf block, we need to remove the gap
	 * between new_cpos and root_end first so that the tree
	 * is consistent after we add a new branch(it will start
	 * from new_cpos).
	 */
	if (root_end > new_cpos) {
		mlog(0, "adjust the cluster end from %u to %u\n",
		     root_end, new_cpos);
		status = ocfs2_adjust_rightmost_branch(handle, inode, et);
		if (status) {
			mlog_errno(status);
			goto bail;
		}
	}

	/* allocate the number of new eb blocks we need */
	new_eb_bhs = kcalloc(new_blocks, sizeof(struct buffer_head *),
			     GFP_KERNEL);
@@ -1071,9 +1146,6 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
		goto bail;
	}

	eb = (struct ocfs2_extent_block *)(*last_eb_bh)->b_data;
	new_cpos = ocfs2_sum_rightmost_rec(&eb->h_list);

	/* Note: new_eb_bhs[new_blocks - 1] is the guy which will be
	 * linked with the rest of the tree.
	 * conversly, new_eb_bhs[0] is the new bottommost leaf.
+176 −8
Original line number Diff line number Diff line
@@ -22,6 +22,9 @@
#include <linux/crc32.h>
#include <linux/buffer_head.h>
#include <linux/bitops.h>
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/byteorder.h>

#include <cluster/masklog.h>
@@ -222,6 +225,155 @@ void ocfs2_hamming_fix_block(void *data, unsigned int blocksize,
	ocfs2_hamming_fix(data, blocksize * 8, 0, fix);
}


/*
 * Debugfs handling.
 */

#ifdef CONFIG_DEBUG_FS

static int blockcheck_u64_get(void *data, u64 *val)
{
	*val = *(u64 *)data;
	return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(blockcheck_fops, blockcheck_u64_get, NULL, "%llu\n");

static struct dentry *blockcheck_debugfs_create(const char *name,
						struct dentry *parent,
						u64 *value)
{
	return debugfs_create_file(name, S_IFREG | S_IRUSR, parent, value,
				   &blockcheck_fops);
}

static void ocfs2_blockcheck_debug_remove(struct ocfs2_blockcheck_stats *stats)
{
	if (stats) {
		debugfs_remove(stats->b_debug_check);
		stats->b_debug_check = NULL;
		debugfs_remove(stats->b_debug_failure);
		stats->b_debug_failure = NULL;
		debugfs_remove(stats->b_debug_recover);
		stats->b_debug_recover = NULL;
		debugfs_remove(stats->b_debug_dir);
		stats->b_debug_dir = NULL;
	}
}

static int ocfs2_blockcheck_debug_install(struct ocfs2_blockcheck_stats *stats,
					  struct dentry *parent)
{
	int rc = -EINVAL;

	if (!stats)
		goto out;

	stats->b_debug_dir = debugfs_create_dir("blockcheck", parent);
	if (!stats->b_debug_dir)
		goto out;

	stats->b_debug_check =
		blockcheck_debugfs_create("blocks_checked",
					  stats->b_debug_dir,
					  &stats->b_check_count);

	stats->b_debug_failure =
		blockcheck_debugfs_create("checksums_failed",
					  stats->b_debug_dir,
					  &stats->b_failure_count);

	stats->b_debug_recover =
		blockcheck_debugfs_create("ecc_recoveries",
					  stats->b_debug_dir,
					  &stats->b_recover_count);
	if (stats->b_debug_check && stats->b_debug_failure &&
	    stats->b_debug_recover)
		rc = 0;

out:
	if (rc)
		ocfs2_blockcheck_debug_remove(stats);
	return rc;
}
#else
static inline int ocfs2_blockcheck_debug_install(struct ocfs2_blockcheck_stats *stats,
						 struct dentry *parent)
{
	return 0;
}

static inline void ocfs2_blockcheck_debug_remove(struct ocfs2_blockcheck_stats *stats)
{
}
#endif  /* CONFIG_DEBUG_FS */

/* Always-called wrappers for starting and stopping the debugfs files */
int ocfs2_blockcheck_stats_debugfs_install(struct ocfs2_blockcheck_stats *stats,
					   struct dentry *parent)
{
	return ocfs2_blockcheck_debug_install(stats, parent);
}

void ocfs2_blockcheck_stats_debugfs_remove(struct ocfs2_blockcheck_stats *stats)
{
	ocfs2_blockcheck_debug_remove(stats);
}

static void ocfs2_blockcheck_inc_check(struct ocfs2_blockcheck_stats *stats)
{
	u64 new_count;

	if (!stats)
		return;

	spin_lock(&stats->b_lock);
	stats->b_check_count++;
	new_count = stats->b_check_count;
	spin_unlock(&stats->b_lock);

	if (!new_count)
		mlog(ML_NOTICE, "Block check count has wrapped\n");
}

static void ocfs2_blockcheck_inc_failure(struct ocfs2_blockcheck_stats *stats)
{
	u64 new_count;

	if (!stats)
		return;

	spin_lock(&stats->b_lock);
	stats->b_failure_count++;
	new_count = stats->b_failure_count;
	spin_unlock(&stats->b_lock);

	if (!new_count)
		mlog(ML_NOTICE, "Checksum failure count has wrapped\n");
}

static void ocfs2_blockcheck_inc_recover(struct ocfs2_blockcheck_stats *stats)
{
	u64 new_count;

	if (!stats)
		return;

	spin_lock(&stats->b_lock);
	stats->b_recover_count++;
	new_count = stats->b_recover_count;
	spin_unlock(&stats->b_lock);

	if (!new_count)
		mlog(ML_NOTICE, "ECC recovery count has wrapped\n");
}



/*
 * These are the low-level APIs for using the ocfs2_block_check structure.
 */

/*
 * This function generates check information for a block.
 * data is the block to be checked.  bc is a pointer to the
@@ -266,12 +418,15 @@ void ocfs2_block_check_compute(void *data, size_t blocksize,
 * Again, the data passed in should be the on-disk endian.
 */
int ocfs2_block_check_validate(void *data, size_t blocksize,
			       struct ocfs2_block_check *bc)
			       struct ocfs2_block_check *bc,
			       struct ocfs2_blockcheck_stats *stats)
{
	int rc = 0;
	struct ocfs2_block_check check;
	u32 crc, ecc;

	ocfs2_blockcheck_inc_check(stats);

	check.bc_crc32e = le32_to_cpu(bc->bc_crc32e);
	check.bc_ecc = le16_to_cpu(bc->bc_ecc);

@@ -282,6 +437,7 @@ int ocfs2_block_check_validate(void *data, size_t blocksize,
	if (crc == check.bc_crc32e)
		goto out;

	ocfs2_blockcheck_inc_failure(stats);
	mlog(ML_ERROR,
	     "CRC32 failed: stored: %u, computed %u.  Applying ECC.\n",
	     (unsigned int)check.bc_crc32e, (unsigned int)crc);
@@ -292,8 +448,10 @@ int ocfs2_block_check_validate(void *data, size_t blocksize,

	/* And check the crc32 again */
	crc = crc32_le(~0, data, blocksize);
	if (crc == check.bc_crc32e)
	if (crc == check.bc_crc32e) {
		ocfs2_blockcheck_inc_recover(stats);
		goto out;
	}

	mlog(ML_ERROR, "Fixed CRC32 failed: stored: %u, computed %u\n",
	     (unsigned int)check.bc_crc32e, (unsigned int)crc);
@@ -366,7 +524,8 @@ void ocfs2_block_check_compute_bhs(struct buffer_head **bhs, int nr,
 * Again, the data passed in should be the on-disk endian.
 */
int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
				   struct ocfs2_block_check *bc)
				   struct ocfs2_block_check *bc,
				   struct ocfs2_blockcheck_stats *stats)
{
	int i, rc = 0;
	struct ocfs2_block_check check;
@@ -377,6 +536,8 @@ int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
	if (!nr)
		return 0;

	ocfs2_blockcheck_inc_check(stats);

	check.bc_crc32e = le32_to_cpu(bc->bc_crc32e);
	check.bc_ecc = le16_to_cpu(bc->bc_ecc);

@@ -388,6 +549,7 @@ int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
	if (crc == check.bc_crc32e)
		goto out;

	ocfs2_blockcheck_inc_failure(stats);
	mlog(ML_ERROR,
	     "CRC32 failed: stored: %u, computed %u.  Applying ECC.\n",
	     (unsigned int)check.bc_crc32e, (unsigned int)crc);
@@ -416,8 +578,10 @@ int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
	/* And check the crc32 again */
	for (i = 0, crc = ~0; i < nr; i++)
		crc = crc32_le(crc, bhs[i]->b_data, bhs[i]->b_size);
	if (crc == check.bc_crc32e)
	if (crc == check.bc_crc32e) {
		ocfs2_blockcheck_inc_recover(stats);
		goto out;
	}

	mlog(ML_ERROR, "Fixed CRC32 failed: stored: %u, computed %u\n",
	     (unsigned int)check.bc_crc32e, (unsigned int)crc);
@@ -448,9 +612,11 @@ int ocfs2_validate_meta_ecc(struct super_block *sb, void *data,
			    struct ocfs2_block_check *bc)
{
	int rc = 0;
	struct ocfs2_super *osb = OCFS2_SB(sb);

	if (ocfs2_meta_ecc(OCFS2_SB(sb)))
		rc = ocfs2_block_check_validate(data, sb->s_blocksize, bc);
	if (ocfs2_meta_ecc(osb))
		rc = ocfs2_block_check_validate(data, sb->s_blocksize, bc,
						&osb->osb_ecc_stats);

	return rc;
}
@@ -468,9 +634,11 @@ int ocfs2_validate_meta_ecc_bhs(struct super_block *sb,
				struct ocfs2_block_check *bc)
{
	int rc = 0;
	struct ocfs2_super *osb = OCFS2_SB(sb);

	if (ocfs2_meta_ecc(OCFS2_SB(sb)))
		rc = ocfs2_block_check_validate_bhs(bhs, nr, bc);
	if (ocfs2_meta_ecc(osb))
		rc = ocfs2_block_check_validate_bhs(bhs, nr, bc,
						    &osb->osb_ecc_stats);

	return rc;
}
+27 −2
Original line number Diff line number Diff line
@@ -21,6 +21,24 @@
#define OCFS2_BLOCKCHECK_H


/* Count errors and error correction from blockcheck.c */
struct ocfs2_blockcheck_stats {
	spinlock_t b_lock;
	u64 b_check_count;	/* Number of blocks we've checked */
	u64 b_failure_count;	/* Number of failed checksums */
	u64 b_recover_count;	/* Number of blocks fixed by ecc */

	/*
	 * debugfs entries, used if this is passed to
	 * ocfs2_blockcheck_stats_debugfs_install()
	 */
	struct dentry *b_debug_dir;	/* Parent of the debugfs  files */
	struct dentry *b_debug_check;	/* Exposes b_check_count */
	struct dentry *b_debug_failure;	/* Exposes b_failure_count */
	struct dentry *b_debug_recover;	/* Exposes b_recover_count */
};


/* High level block API */
void ocfs2_compute_meta_ecc(struct super_block *sb, void *data,
			    struct ocfs2_block_check *bc);
@@ -37,11 +55,18 @@ int ocfs2_validate_meta_ecc_bhs(struct super_block *sb,
void ocfs2_block_check_compute(void *data, size_t blocksize,
			       struct ocfs2_block_check *bc);
int ocfs2_block_check_validate(void *data, size_t blocksize,
			       struct ocfs2_block_check *bc);
			       struct ocfs2_block_check *bc,
			       struct ocfs2_blockcheck_stats *stats);
void ocfs2_block_check_compute_bhs(struct buffer_head **bhs, int nr,
				   struct ocfs2_block_check *bc);
int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
				   struct ocfs2_block_check *bc);
				   struct ocfs2_block_check *bc,
				   struct ocfs2_blockcheck_stats *stats);

/* Debug Initialization */
int ocfs2_blockcheck_stats_debugfs_install(struct ocfs2_blockcheck_stats *stats,
					   struct dentry *parent);
void ocfs2_blockcheck_stats_debugfs_remove(struct ocfs2_blockcheck_stats *stats);

/*
 * Hamming code functions
+17 −18
Original line number Diff line number Diff line
@@ -48,34 +48,33 @@
 * only emit the appropriage printk() when the caller passes in a constant
 * mask, as is almost always the case.
 *
 * All this bitmask nonsense is hidden from the /proc interface so that Joel
 * doesn't have an aneurism.  Reading the file gives a straight forward
 * indication of which bits are on or off:
 * 	ENTRY off
 * 	EXIT off
 * All this bitmask nonsense is managed from the files under
 * /sys/fs/o2cb/logmask/.  Reading the files gives a straightforward
 * indication of which bits are allowed (allow) or denied (off/deny).
 * 	ENTRY deny
 * 	EXIT deny
 * 	TCP off
 * 	MSG off
 * 	SOCKET off
 * 	ERROR off
 * 	NOTICE on
 * 	ERROR allow
 * 	NOTICE allow
 *
 * Writing changes the state of a given bit and requires a strictly formatted
 * single write() call:
 *
 * 	write(fd, "ENTRY on", 8);
 * 	write(fd, "allow", 5);
 *
 * would turn the entry bit on.  "1" is also accepted in the place of "on", and
 * "off" and "0" behave as expected.
 * Echoing allow/deny/off string into the logmask files can flip the bits
 * on or off as expected; here is the bash script for example:
 *
 * Some trivial shell can flip all the bits on or off:
 *
 * log_mask="/proc/fs/ocfs2_nodemanager/log_mask"
 * cat $log_mask | (
 * 	while read bit status; do
 * 		# $1 is "on" or "off", say
 * 		echo "$bit $1" > $log_mask
 * log_mask="/sys/fs/o2cb/log_mask"
 * for node in ENTRY EXIT TCP MSG SOCKET ERROR NOTICE; do
 *	echo allow >"$log_mask"/"$node"
 * done
 * )
 *
 * The debugfs.ocfs2 tool can also flip the bits with the -l option:
 *
 * debugfs.ocfs2 -l TCP allow
 */

/* for task_struct */
+2 −5
Original line number Diff line number Diff line
@@ -974,7 +974,7 @@ static int o2net_tx_can_proceed(struct o2net_node *nn,
int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec,
			   size_t caller_veclen, u8 target_node, int *status)
{
	int ret, error = 0;
	int ret;
	struct o2net_msg *msg = NULL;
	size_t veclen, caller_bytes = 0;
	struct kvec *vec = NULL;
@@ -1015,10 +1015,7 @@ int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec,

	o2net_set_nst_sock_time(&nst);

	ret = wait_event_interruptible(nn->nn_sc_wq,
				       o2net_tx_can_proceed(nn, &sc, &error));
	if (!ret && error)
		ret = error;
	wait_event(nn->nn_sc_wq, o2net_tx_can_proceed(nn, &sc, &ret));
	if (ret)
		goto out;

Loading