提交 300df7dc 编写于 作者: L Linus Torvalds

Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jlbec/ocfs2

* '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.
......@@ -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.
......
......@@ -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;
}
......
......@@ -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
......
......@@ -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="/sys/fs/o2cb/log_mask"
* for node in ENTRY EXIT TCP MSG SOCKET ERROR NOTICE; do
* echo allow >"$log_mask"/"$node"
* done
*
* 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
* done
* )
* The debugfs.ocfs2 tool can also flip the bits with the -l option:
*
* debugfs.ocfs2 -l TCP allow
*/
/* for task_struct */
......
......@@ -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;
......
......@@ -2900,6 +2900,8 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
alloc = ocfs2_clusters_for_bytes(sb, bytes);
dx_alloc = 0;
down_write(&oi->ip_alloc_sem);
if (ocfs2_supports_indexed_dirs(osb)) {
credits += ocfs2_add_dir_index_credits(sb);
......@@ -2940,8 +2942,6 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
goto out;
}
down_write(&oi->ip_alloc_sem);
/*
* Prepare for worst case allocation scenario of two separate
* extents in the unindexed tree.
......@@ -2953,7 +2953,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
mlog_errno(ret);
goto out_sem;
goto out;
}
if (vfs_dq_alloc_space_nodirty(dir,
......@@ -3172,10 +3172,8 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
ocfs2_commit_trans(osb, handle);
out_sem:
up_write(&oi->ip_alloc_sem);
out:
up_write(&oi->ip_alloc_sem);
if (data_ac)
ocfs2_free_alloc_context(data_ac);
if (meta_ac)
......@@ -3322,11 +3320,15 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
brelse(new_bh);
new_bh = NULL;
down_write(&OCFS2_I(dir)->ip_alloc_sem);
drop_alloc_sem = 1;
dir_i_size = i_size_read(dir);
credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS;
goto do_extend;
}
down_write(&OCFS2_I(dir)->ip_alloc_sem);
drop_alloc_sem = 1;
dir_i_size = i_size_read(dir);
mlog(0, "extending dir %llu (i_size = %lld)\n",
(unsigned long long)OCFS2_I(dir)->ip_blkno, dir_i_size);
......@@ -3370,9 +3372,6 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
credits++; /* For attaching the new dirent block to the
* dx_root */
down_write(&OCFS2_I(dir)->ip_alloc_sem);
drop_alloc_sem = 1;
handle = ocfs2_start_trans(osb, credits);
if (IS_ERR(handle)) {
status = PTR_ERR(handle);
......@@ -3435,10 +3434,10 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
*new_de_bh = new_bh;
get_bh(*new_de_bh);
bail:
if (drop_alloc_sem)
up_write(&OCFS2_I(dir)->ip_alloc_sem);
if (handle)
ocfs2_commit_trans(osb, handle);
if (drop_alloc_sem)
up_write(&OCFS2_I(dir)->ip_alloc_sem);
if (data_ac)
ocfs2_free_alloc_context(data_ac);
......
......@@ -248,6 +248,10 @@ static struct ocfs2_lock_res_ops ocfs2_nfs_sync_lops = {
.flags = 0,
};
static struct ocfs2_lock_res_ops ocfs2_orphan_scan_lops = {
.flags = LOCK_TYPE_REQUIRES_REFRESH|LOCK_TYPE_USES_LVB,
};
static struct ocfs2_lock_res_ops ocfs2_dentry_lops = {
.get_osb = ocfs2_get_dentry_osb,
.post_unlock = ocfs2_dentry_post_unlock,
......@@ -637,6 +641,19 @@ static void ocfs2_nfs_sync_lock_res_init(struct ocfs2_lock_res *res,
&ocfs2_nfs_sync_lops, osb);
}
static void ocfs2_orphan_scan_lock_res_init(struct ocfs2_lock_res *res,
struct ocfs2_super *osb)
{
struct ocfs2_orphan_scan_lvb *lvb;
ocfs2_lock_res_init_once(res);
ocfs2_build_lock_name(OCFS2_LOCK_TYPE_ORPHAN_SCAN, 0, 0, res->l_name);
ocfs2_lock_res_init_common(osb, res, OCFS2_LOCK_TYPE_ORPHAN_SCAN,
&ocfs2_orphan_scan_lops, osb);
lvb = ocfs2_dlm_lvb(&res->l_lksb);
lvb->lvb_version = OCFS2_ORPHAN_LVB_VERSION;
}
void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres,
struct ocfs2_file_private *fp)
{
......@@ -2352,6 +2369,37 @@ void ocfs2_inode_unlock(struct inode *inode,
mlog_exit_void();
}
int ocfs2_orphan_scan_lock(struct ocfs2_super *osb, u32 *seqno, int ex)
{
struct ocfs2_lock_res *lockres;
struct ocfs2_orphan_scan_lvb *lvb;
int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR;
int status = 0;
lockres = &osb->osb_orphan_scan.os_lockres;
status = ocfs2_cluster_lock(osb, lockres, level, 0, 0);
if (status < 0)
return status;
lvb = ocfs2_dlm_lvb(&lockres->l_lksb);
if (lvb->lvb_version == OCFS2_ORPHAN_LVB_VERSION)
*seqno = be32_to_cpu(lvb->lvb_os_seqno);
return status;
}
void ocfs2_orphan_scan_unlock(struct ocfs2_super *osb, u32 seqno, int ex)
{
struct ocfs2_lock_res *lockres;
struct ocfs2_orphan_scan_lvb *lvb;
int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR;
lockres = &osb->osb_orphan_scan.os_lockres;
lvb = ocfs2_dlm_lvb(&lockres->l_lksb);
lvb->lvb_version = OCFS2_ORPHAN_LVB_VERSION;
lvb->lvb_os_seqno = cpu_to_be32(seqno);
ocfs2_cluster_unlock(osb, lockres, level);
}
int ocfs2_super_lock(struct ocfs2_super *osb,
int ex)
{
......@@ -2842,6 +2890,7 @@ int ocfs2_dlm_init(struct ocfs2_super *osb)
ocfs2_super_lock_res_init(&osb->osb_super_lockres, osb);
ocfs2_rename_lock_res_init(&osb->osb_rename_lockres, osb);
ocfs2_nfs_sync_lock_res_init(&osb->osb_nfs_sync_lockres, osb);
ocfs2_orphan_scan_lock_res_init(&osb->osb_orphan_scan.os_lockres, osb);
osb->cconn = conn;
......@@ -2878,6 +2927,7 @@ void ocfs2_dlm_shutdown(struct ocfs2_super *osb,
ocfs2_lock_res_free(&osb->osb_super_lockres);
ocfs2_lock_res_free(&osb->osb_rename_lockres);
ocfs2_lock_res_free(&osb->osb_nfs_sync_lockres);
ocfs2_lock_res_free(&osb->osb_orphan_scan.os_lockres);
ocfs2_cluster_disconnect(osb->cconn, hangup_pending);
osb->cconn = NULL;
......@@ -3061,6 +3111,7 @@ static void ocfs2_drop_osb_locks(struct ocfs2_super *osb)
ocfs2_simple_drop_lockres(osb, &osb->osb_super_lockres);
ocfs2_simple_drop_lockres(osb, &osb->osb_rename_lockres);
ocfs2_simple_drop_lockres(osb, &osb->osb_nfs_sync_lockres);
ocfs2_simple_drop_lockres(osb, &osb->osb_orphan_scan.os_lockres);
}
int ocfs2_drop_inode_locks(struct inode *inode)
......
......@@ -62,6 +62,14 @@ struct ocfs2_qinfo_lvb {
__be32 lvb_free_entry;
};
#define OCFS2_ORPHAN_LVB_VERSION 1
struct ocfs2_orphan_scan_lvb {
__u8 lvb_version;
__u8 lvb_reserved[3];
__be32 lvb_os_seqno;
};
/* ocfs2_inode_lock_full() 'arg_flags' flags */
/* don't wait on recovery. */
#define OCFS2_META_LOCK_RECOVERY (0x01)
......@@ -113,6 +121,9 @@ int ocfs2_super_lock(struct ocfs2_super *osb,
int ex);
void ocfs2_super_unlock(struct ocfs2_super *osb,
int ex);
int ocfs2_orphan_scan_lock(struct ocfs2_super *osb, u32 *seqno, int ex);
void ocfs2_orphan_scan_unlock(struct ocfs2_super *osb, u32 seqno, int ex);
int ocfs2_rename_lock(struct ocfs2_super *osb);
void ocfs2_rename_unlock(struct ocfs2_super *osb);
int ocfs2_nfs_sync_lock(struct ocfs2_super *osb, int ex);
......
......@@ -187,6 +187,9 @@ static int ocfs2_sync_file(struct file *file,
if (err)
goto bail;
if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
goto bail;
journal = osb->journal->j_journal;
err = jbd2_journal_force_commit(journal);
......@@ -894,9 +897,9 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
struct ocfs2_super *osb = OCFS2_SB(sb);
struct buffer_head *bh = NULL;
handle_t *handle = NULL;
int locked[MAXQUOTAS] = {0, 0};
int credits, qtype;
struct ocfs2_mem_dqinfo *oinfo;
int qtype;
struct dquot *transfer_from[MAXQUOTAS] = { };
struct dquot *transfer_to[MAXQUOTAS] = { };
mlog_entry("(0x%p, '%.*s')\n", dentry,
dentry->d_name.len, dentry->d_name.name);
......@@ -969,30 +972,37 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
if ((attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
(attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
credits = OCFS2_INODE_UPDATE_CREDITS;
/*
* Gather pointers to quota structures so that allocation /
* freeing of quota structures happens here and not inside
* vfs_dq_transfer() where we have problems with lock ordering
*/
if (attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid
&& OCFS2_HAS_RO_COMPAT_FEATURE(sb,
OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
oinfo = sb_dqinfo(sb, USRQUOTA)->dqi_priv;
status = ocfs2_lock_global_qf(oinfo, 1);
if (status < 0)
transfer_to[USRQUOTA] = dqget(sb, attr->ia_uid,
USRQUOTA);
transfer_from[USRQUOTA] = dqget(sb, inode->i_uid,
USRQUOTA);
if (!transfer_to[USRQUOTA] || !transfer_from[USRQUOTA]) {
status = -ESRCH;
goto bail_unlock;
credits += ocfs2_calc_qinit_credits(sb, USRQUOTA) +
ocfs2_calc_qdel_credits(sb, USRQUOTA);
locked[USRQUOTA] = 1;
}
}
if (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid
&& OCFS2_HAS_RO_COMPAT_FEATURE(sb,
OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) {
oinfo = sb_dqinfo(sb, GRPQUOTA)->dqi_priv;
status = ocfs2_lock_global_qf(oinfo, 1);
if (status < 0)
transfer_to[GRPQUOTA] = dqget(sb, attr->ia_gid,
GRPQUOTA);
transfer_from[GRPQUOTA] = dqget(sb, inode->i_gid,
GRPQUOTA);
if (!transfer_to[GRPQUOTA] || !transfer_from[GRPQUOTA]) {
status = -ESRCH;
goto bail_unlock;
credits += ocfs2_calc_qinit_credits(sb, GRPQUOTA) +
ocfs2_calc_qdel_credits(sb, GRPQUOTA);
locked[GRPQUOTA] = 1;
}
}
handle = ocfs2_start_trans(osb, credits);
handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS +
2 * ocfs2_quota_trans_credits(sb));
if (IS_ERR(handle)) {
status = PTR_ERR(handle);
mlog_errno(status);
......@@ -1030,12 +1040,6 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
bail_commit:
ocfs2_commit_trans(osb, handle);
bail_unlock:
for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
if (!locked[qtype])
continue;
oinfo = sb_dqinfo(sb, qtype)->dqi_priv;
ocfs2_unlock_global_qf(oinfo, 1);
}
ocfs2_inode_unlock(inode, 1);
bail_unlock_rw:
if (size_change)
......@@ -1043,6 +1047,12 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
bail:
brelse(bh);
/* Release quota pointers in case we acquired them */
for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
dqput(transfer_to[qtype]);
dqput(transfer_from[qtype]);
}
if (!status && attr->ia_valid & ATTR_MODE) {
status = ocfs2_acl_chmod(inode);
if (status < 0)
......
......@@ -28,6 +28,8 @@
#include <linux/slab.h>
#include <linux/highmem.h>
#include <linux/kthread.h>
#include <linux/time.h>
#include <linux/random.h>
#define MLOG_MASK_PREFIX ML_JOURNAL
#include <cluster/masklog.h>
......@@ -52,6 +54,8 @@
DEFINE_SPINLOCK(trans_inc_lock);
#define ORPHAN_SCAN_SCHEDULE_TIMEOUT 300000
static int ocfs2_force_read_journal(struct inode *inode);
static int ocfs2_recover_node(struct ocfs2_super *osb,
int node_num, int slot_num);
......@@ -1841,6 +1845,113 @@ int ocfs2_mark_dead_nodes(struct ocfs2_super *osb)
return status;
}
/*
* Scan timer should get fired every ORPHAN_SCAN_SCHEDULE_TIMEOUT. Add some
* randomness to the timeout to minimize multple nodes firing the timer at the
* same time.
*/
static inline unsigned long ocfs2_orphan_scan_timeout(void)
{
unsigned long time;
get_random_bytes(&time, sizeof(time));
time = ORPHAN_SCAN_SCHEDULE_TIMEOUT + (time % 5000);
return msecs_to_jiffies(time);
}
/*
* ocfs2_queue_orphan_scan calls ocfs2_queue_recovery_completion for
* every slot, queuing a recovery of the slot on the ocfs2_wq thread. This
* is done to catch any orphans that are left over in orphan directories.
*
* ocfs2_queue_orphan_scan gets called every ORPHAN_SCAN_SCHEDULE_TIMEOUT
* seconds. It gets an EX lock on os_lockres and checks sequence number
* stored in LVB. If the sequence number has changed, it means some other
* node has done the scan. This node skips the scan and tracks the
* sequence number. If the sequence number didn't change, it means a scan
* hasn't happened. The node queues a scan and increments the
* sequence number in the LVB.
*/
void ocfs2_queue_orphan_scan(struct ocfs2_super *osb)
{
struct ocfs2_orphan_scan *os;
int status, i;
u32 seqno = 0;
os = &osb->osb_orphan_scan;
status = ocfs2_orphan_scan_lock(osb, &seqno, DLM_LOCK_EX);
if (status < 0) {
if (status != -EAGAIN)
mlog_errno(status);
goto out;
}
if (os->os_seqno != seqno) {
os->os_seqno = seqno;
goto unlock;
}
for (i = 0; i < osb->max_slots; i++)
ocfs2_queue_recovery_completion(osb->journal, i, NULL, NULL,
NULL);
/*
* We queued a recovery on orphan slots, increment the sequence
* number and update LVB so other node will skip the scan for a while
*/
seqno++;
os->os_count++;
os->os_scantime = CURRENT_TIME;
unlock:
ocfs2_orphan_scan_unlock(osb, seqno, DLM_LOCK_EX);
out:
return;
}
/* Worker task that gets fired every ORPHAN_SCAN_SCHEDULE_TIMEOUT millsec */
void ocfs2_orphan_scan_work(struct work_struct *work)
{
struct ocfs2_orphan_scan *os;
struct ocfs2_super *osb;
os = container_of(work, struct ocfs2_orphan_scan,
os_orphan_scan_work.work);
osb = os->os_osb;
mutex_lock(&os->os_lock);
ocfs2_queue_orphan_scan(osb);
schedule_delayed_work(&os->os_orphan_scan_work,
ocfs2_orphan_scan_timeout());
mutex_unlock(&os->os_lock);
}
void ocfs2_orphan_scan_stop(struct ocfs2_super *osb)
{
struct ocfs2_orphan_scan *os;
os = &osb->osb_orphan_scan;
mutex_lock(&os->os_lock);
cancel_delayed_work(&os->os_orphan_scan_work);
mutex_unlock(&os->os_lock);
}
int ocfs2_orphan_scan_init(struct ocfs2_super *osb)
{
struct ocfs2_orphan_scan *os;
os = &osb->osb_orphan_scan;
os->os_osb = osb;
os->os_count = 0;
os->os_scantime = CURRENT_TIME;
mutex_init(&os->os_lock);
INIT_DELAYED_WORK(&os->os_orphan_scan_work,
ocfs2_orphan_scan_work);
schedule_delayed_work(&os->os_orphan_scan_work,
ocfs2_orphan_scan_timeout());
return 0;
}
struct ocfs2_orphan_filldir_priv {
struct inode *head;
struct ocfs2_super *osb;
......
......@@ -144,6 +144,10 @@ static inline void ocfs2_inode_set_new(struct ocfs2_super *osb,
}
/* Exported only for the journal struct init code in super.c. Do not call. */
int ocfs2_orphan_scan_init(struct ocfs2_super *osb);
void ocfs2_orphan_scan_stop(struct ocfs2_super *osb);
void ocfs2_orphan_scan_exit(struct ocfs2_super *osb);
void ocfs2_complete_recovery(struct work_struct *work);
void ocfs2_wait_for_recovery(struct ocfs2_super *osb);
......
......@@ -47,6 +47,9 @@
#include "ocfs2_fs.h"
#include "ocfs2_lockid.h"
/* For struct ocfs2_blockcheck_stats */
#include "blockcheck.h"
/* Most user visible OCFS2 inodes will have very few pieces of
* metadata, but larger files (including bitmaps, etc) must be taken
* into account when designing an access scheme. We allow a small
......@@ -151,6 +154,16 @@ struct ocfs2_lock_res {
#endif
};
struct ocfs2_orphan_scan {
struct mutex os_lock;
struct ocfs2_super *os_osb;
struct ocfs2_lock_res os_lockres; /* lock to synchronize scans */
struct delayed_work os_orphan_scan_work;
struct timespec os_scantime; /* time this node ran the scan */
u32 os_count; /* tracks node specific scans */
u32 os_seqno; /* tracks cluster wide scans */
};
struct ocfs2_dlm_debug {
struct kref d_refcnt;
struct dentry *d_locking_state;
......@@ -295,6 +308,7 @@ struct ocfs2_super
struct ocfs2_dinode *local_alloc_copy;
struct ocfs2_quota_recovery *quota_rec;
struct ocfs2_blockcheck_stats osb_ecc_stats;
struct ocfs2_alloc_stats alloc_stats;
char dev_str[20]; /* "major,minor" of the device */
......@@ -341,6 +355,8 @@ struct ocfs2_super
unsigned int *osb_orphan_wipes;
wait_queue_head_t osb_wipe_event;
struct ocfs2_orphan_scan osb_orphan_scan;
/* used to protect metaecc calculation check of xattr. */
spinlock_t osb_xattr_lock;
......
......@@ -48,6 +48,7 @@ enum ocfs2_lock_type {
OCFS2_LOCK_TYPE_FLOCK,
OCFS2_LOCK_TYPE_QINFO,
OCFS2_LOCK_TYPE_NFS_SYNC,
OCFS2_LOCK_TYPE_ORPHAN_SCAN,
OCFS2_NUM_LOCK_TYPES
};
......@@ -85,6 +86,9 @@ static inline char ocfs2_lock_type_char(enum ocfs2_lock_type type)
case OCFS2_LOCK_TYPE_NFS_SYNC:
c = 'Y';
break;
case OCFS2_LOCK_TYPE_ORPHAN_SCAN:
c = 'P';
break;
default:
c = '\0';
}
......@@ -104,6 +108,7 @@ static char *ocfs2_lock_type_strings[] = {
[OCFS2_LOCK_TYPE_OPEN] = "Open",
[OCFS2_LOCK_TYPE_FLOCK] = "Flock",
[OCFS2_LOCK_TYPE_QINFO] = "Quota",
[OCFS2_LOCK_TYPE_ORPHAN_SCAN] = "OrphanScan",
};
static inline const char *ocfs2_lock_type_string(enum ocfs2_lock_type type)
......
......@@ -421,6 +421,7 @@ int ocfs2_global_read_dquot(struct dquot *dquot)
OCFS2_DQUOT(dquot)->dq_originodes = dquot->dq_dqb.dqb_curinodes;
if (!dquot->dq_off) { /* No real quota entry? */
/* Upgrade to exclusive lock for allocation */
ocfs2_qinfo_unlock(info, 0);
err = ocfs2_qinfo_lock(info, 1);
if (err < 0)
goto out_qlock;
......@@ -435,7 +436,8 @@ int ocfs2_global_read_dquot(struct dquot *dquot)
out_qlock:
if (ex)
ocfs2_qinfo_unlock(info, 1);
ocfs2_qinfo_unlock(info, 0);
else
ocfs2_qinfo_unlock(info, 0);
out:
if (err < 0)
mlog_errno(err);
......
......@@ -444,10 +444,6 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
mlog_entry("ino=%lu type=%u", (unsigned long)lqinode->i_ino, type);
status = ocfs2_lock_global_qf(oinfo, 1);
if (status < 0)
goto out;
list_for_each_entry_safe(rchunk, next, &(rec->r_list[type]), rc_list) {
chunk = rchunk->rc_chunk;
hbh = NULL;
......@@ -480,12 +476,18 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
type);
goto out_put_bh;
}
status = ocfs2_lock_global_qf(oinfo, 1);
if (status < 0) {
mlog_errno(status);
goto out_put_dquot;
}
handle = ocfs2_start_trans(OCFS2_SB(sb),
OCFS2_QSYNC_CREDITS);
if (IS_ERR(handle)) {
status = PTR_ERR(handle);
mlog_errno(status);
goto out_put_dquot;
goto out_drop_lock;
}
mutex_lock(&sb_dqopt(sb)->dqio_mutex);
spin_lock(&dq_data_lock);
......@@ -523,6 +525,8 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
out_commit:
mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
ocfs2_commit_trans(OCFS2_SB(sb), handle);
out_drop_lock:
ocfs2_unlock_global_qf(oinfo, 1);
out_put_dquot:
dqput(dquot);
out_put_bh:
......@@ -537,8 +541,6 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
if (status < 0)
break;
}
ocfs2_unlock_global_qf(oinfo, 1);
out:
if (status < 0)
free_recovery_list(&(rec->r_list[type]));
mlog_exit(status);
......@@ -655,6 +657,9 @@ static int ocfs2_local_read_info(struct super_block *sb, int type)
struct ocfs2_quota_recovery *rec;
int locked = 0;
/* We don't need the lock and we have to acquire quota file locks
* which will later depend on this lock */
mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
info->dqi_maxblimit = 0x7fffffffffffffffLL;
info->dqi_maxilimit = 0x7fffffffffffffffLL;
oinfo = kmalloc(sizeof(struct ocfs2_mem_dqinfo), GFP_NOFS);
......@@ -733,6 +738,7 @@ static int ocfs2_local_read_info(struct super_block *sb, int type)
goto out_err;
}
mutex_lock(&sb_dqopt(sb)->dqio_mutex);
return 0;
out_err:
if (oinfo) {
......@@ -746,6 +752,7 @@ static int ocfs2_local_read_info(struct super_block *sb, int type)
kfree(oinfo);
}
brelse(bh);
mutex_lock(&sb_dqopt(sb)->dqio_mutex);
return -1;
}
......
......@@ -119,10 +119,12 @@ static void ocfs2_release_system_inodes(struct ocfs2_super *osb);
static int ocfs2_check_volume(struct ocfs2_super *osb);
static int ocfs2_verify_volume(struct ocfs2_dinode *di,
struct buffer_head *bh,
u32 sectsize);
u32 sectsize,
struct ocfs2_blockcheck_stats *stats);
static int ocfs2_initialize_super(struct super_block *sb,
struct buffer_head *bh,
int sector_size);
int sector_size,
struct ocfs2_blockcheck_stats *stats);
static int ocfs2_get_sector(struct super_block *sb,
struct buffer_head **bh,
int block,
......@@ -207,6 +209,7 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len)
int i;
struct ocfs2_cluster_connection *cconn = osb->cconn;
struct ocfs2_recovery_map *rm = osb->recovery_map;
struct ocfs2_orphan_scan *os;
out += snprintf(buf + out, len - out,
"%10s => Id: %-s Uuid: %-s Gen: 0x%X Label: %-s\n",
......@@ -308,6 +311,13 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len)
i, osb->slot_recovery_generations[i]);
}
os = &osb->osb_orphan_scan;
out += snprintf(buf + out, len - out, "Orphan Scan=> ");
out += snprintf(buf + out, len - out, "Local: %u Global: %u ",
os->os_count, os->os_seqno);
out += snprintf(buf + out, len - out, " Last Scan: %lu seconds ago\n",
(get_seconds() - os->os_scantime.tv_sec));
return out;
}
......@@ -693,7 +703,8 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
static int ocfs2_sb_probe(struct super_block *sb,
struct buffer_head **bh,
int *sector_size)
int *sector_size,
struct ocfs2_blockcheck_stats *stats)
{
int status, tmpstat;
struct ocfs1_vol_disk_hdr *hdr;
......@@ -759,7 +770,8 @@ static int ocfs2_sb_probe(struct super_block *sb,
goto bail;
}
di = (struct ocfs2_dinode *) (*bh)->b_data;
status = ocfs2_verify_volume(di, *bh, blksize);
memset(stats, 0, sizeof(struct ocfs2_blockcheck_stats));
status = ocfs2_verify_volume(di, *bh, blksize, stats);
if (status >= 0)
goto bail;
brelse(*bh);
......@@ -965,6 +977,7 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
struct ocfs2_super *osb = NULL;
struct buffer_head *bh = NULL;
char nodestr[8];
struct ocfs2_blockcheck_stats stats;
mlog_entry("%p, %p, %i", sb, data, silent);
......@@ -974,13 +987,13 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
}
/* probe for superblock */
status = ocfs2_sb_probe(sb, &bh, &sector_size);
status = ocfs2_sb_probe(sb, &bh, &sector_size, &stats);
if (status < 0) {
mlog(ML_ERROR, "superblock probe failed!\n");
goto read_super_error;
}
status = ocfs2_initialize_super(sb, bh, sector_size);
status = ocfs2_initialize_super(sb, bh, sector_size, &stats);
osb = OCFS2_SB(sb);
if (status < 0) {
mlog_errno(status);
......@@ -1090,6 +1103,18 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
goto read_super_error;
}
if (ocfs2_meta_ecc(osb)) {
status = ocfs2_blockcheck_stats_debugfs_install(
&osb->osb_ecc_stats,
osb->osb_debug_root);
if (status) {
mlog(ML_ERROR,
"Unable to create blockcheck statistics "
"files\n");
goto read_super_error;
}
}
status = ocfs2_mount_volume(sb);
if (osb->root_inode)
inode = igrab(osb->root_inode);
......@@ -1760,13 +1785,8 @@ static int ocfs2_mount_volume(struct super_block *sb)
}
status = ocfs2_truncate_log_init(osb);
if (status < 0) {
if (status < 0)
mlog_errno(status);
goto leave;
}
if (ocfs2_mount_local(osb))
goto leave;
leave:
if (unlock_super)
......@@ -1796,6 +1816,8 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
ocfs2_truncate_log_shutdown(osb);
ocfs2_orphan_scan_stop(osb);
/* This will disable recovery and flush any recovery work. */
ocfs2_recovery_exit(osb);
......@@ -1833,6 +1855,7 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
if (osb->cconn)
ocfs2_dlm_shutdown(osb, hangup_needed);
ocfs2_blockcheck_stats_debugfs_remove(&osb->osb_ecc_stats);
debugfs_remove(osb->osb_debug_root);
if (hangup_needed)
......@@ -1880,7 +1903,8 @@ static int ocfs2_setup_osb_uuid(struct ocfs2_super *osb, const unsigned char *uu
static int ocfs2_initialize_super(struct super_block *sb,
struct buffer_head *bh,
int sector_size)
int sector_size,
struct ocfs2_blockcheck_stats *stats)
{
int status;
int i, cbits, bbits;
......@@ -1939,6 +1963,9 @@ static int ocfs2_initialize_super(struct super_block *sb,
atomic_set(&osb->alloc_stats.bg_allocs, 0);
atomic_set(&osb->alloc_stats.bg_extends, 0);
/* Copy the blockcheck stats from the superblock probe */
osb->osb_ecc_stats = *stats;
ocfs2_init_node_maps(osb);
snprintf(osb->dev_str, sizeof(osb->dev_str), "%u,%u",
......@@ -1951,6 +1978,13 @@ static int ocfs2_initialize_super(struct super_block *sb,
goto bail;
}
status = ocfs2_orphan_scan_init(osb);
if (status) {
mlog(ML_ERROR, "Unable to initialize delayed orphan scan\n");
mlog_errno(status);
goto bail;
}
init_waitqueue_head(&osb->checkpoint_event);
atomic_set(&osb->needs_checkpoint, 0);
......@@ -2169,7 +2203,8 @@ static int ocfs2_initialize_super(struct super_block *sb,
*/
static int ocfs2_verify_volume(struct ocfs2_dinode *di,
struct buffer_head *bh,
u32 blksz)
u32 blksz,
struct ocfs2_blockcheck_stats *stats)
{
int status = -EAGAIN;
......@@ -2182,7 +2217,8 @@ static int ocfs2_verify_volume(struct ocfs2_dinode *di,
OCFS2_FEATURE_INCOMPAT_META_ECC) {
status = ocfs2_block_check_validate(bh->b_data,
bh->b_size,
&di->i_check);
&di->i_check,
stats);
if (status)
goto out;
}
......
......@@ -3154,7 +3154,7 @@ static int ocfs2_iterate_xattr_buckets(struct inode *inode,
le32_to_cpu(bucket_xh(bucket)->xh_entries[0].xe_name_hash));
if (func) {
ret = func(inode, bucket, para);
if (ret)
if (ret && ret != -ERANGE)
mlog_errno(ret);
/* Fall through to bucket_relse() */
}
......@@ -3261,7 +3261,8 @@ static int ocfs2_xattr_tree_list_index_block(struct inode *inode,
ocfs2_list_xattr_bucket,
&xl);
if (ret) {
mlog_errno(ret);
if (ret != -ERANGE)
mlog_errno(ret);
goto out;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册