summaryrefslogtreecommitdiff
path: root/fs/ocfs2
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-07-24 16:21:27 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-07-24 16:21:27 +0200
commit8f9aa2c90530ab92301a82231ae44f3722becd93 (patch)
treefb282e955b0a880b07131a135257fe3ec764e928 /fs/ocfs2
parent93467b31bec6da512b51544e5e4584f2745e995e (diff)
parent155b42bec9cbb6b8cdc47dd9bd09503a81fbe493 (diff)
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/ocfs2')
-rw-r--r--fs/ocfs2/alloc.c2
-rw-r--r--fs/ocfs2/aops.c13
-rw-r--r--fs/ocfs2/buffer_head_io.c7
-rw-r--r--fs/ocfs2/dlm/dlmdebug.c16
-rw-r--r--fs/ocfs2/dlmglue.c17
-rw-r--r--fs/ocfs2/inode.c206
-rw-r--r--fs/ocfs2/journal.c13
-rw-r--r--fs/ocfs2/journal.h3
-rw-r--r--fs/ocfs2/move_extents.c4
-rw-r--r--fs/ocfs2/ocfs2.h2
-rw-r--r--fs/ocfs2/quota_local.c2
-rw-r--r--fs/ocfs2/refcounttree.c9
-rw-r--r--fs/ocfs2/stack_user.c10
-rw-r--r--fs/ocfs2/super.c2
-rw-r--r--fs/ocfs2/sysfile.c9
15 files changed, 274 insertions, 41 deletions
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
index 6e5fd3f12a84..be09e766ac1f 100644
--- a/fs/ocfs2/alloc.c
+++ b/fs/ocfs2/alloc.c
@@ -7576,7 +7576,7 @@ int ocfs2_trim_mainbm(struct super_block *sb, struct fstrim_range *range)
len = range->len >> osb->s_clustersize_bits;
minlen = range->minlen >> osb->s_clustersize_bits;
- if (minlen >= osb->bitmap_cpg || range->len < sb->s_blocksize)
+ if (minlen >= osb->bitmap_cpg || range->len < osb->s_clustersize)
return -EINVAL;
trace_ocfs2_trim_mainbm(start, len, minlen);
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index 6ec198bdab12..4acdbb70882c 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -2372,6 +2372,15 @@ commit:
unlock:
up_write(&oi->ip_alloc_sem);
+ if (data_ac) {
+ ocfs2_free_alloc_context(data_ac);
+ data_ac = NULL;
+ }
+ if (meta_ac) {
+ ocfs2_free_alloc_context(meta_ac);
+ meta_ac = NULL;
+ }
+
/* everything looks good, let's start the cleanup */
if (!ret && dwc->dw_orphaned) {
BUG_ON(dwc->dw_writer_pid != task_pid_nr(current));
@@ -2383,10 +2392,6 @@ unlock:
ocfs2_inode_unlock(inode, 1);
brelse(di_bh);
out:
- if (data_ac)
- ocfs2_free_alloc_context(data_ac);
- if (meta_ac)
- ocfs2_free_alloc_context(meta_ac);
ocfs2_run_deallocs(osb, &dealloc);
ocfs2_dio_free_write_ctx(inode, dwc);
diff --git a/fs/ocfs2/buffer_head_io.c b/fs/ocfs2/buffer_head_io.c
index 701d27d908d4..6114299b121e 100644
--- a/fs/ocfs2/buffer_head_io.c
+++ b/fs/ocfs2/buffer_head_io.c
@@ -350,8 +350,6 @@ read_failure:
wait_on_buffer(bh);
put_bh(bh);
bhs[i] = NULL;
- } else if (bh && buffer_uptodate(bh)) {
- clear_buffer_uptodate(bh);
}
continue;
}
@@ -380,8 +378,11 @@ read_failure:
BUG_ON(buffer_jbd(bh));
clear_buffer_needs_validate(bh);
status = validate(sb, bh);
- if (status)
+ if (status) {
+ if (buffer_uptodate(bh))
+ clear_buffer_uptodate(bh);
goto read_failure;
+ }
}
}
diff --git a/fs/ocfs2/dlm/dlmdebug.c b/fs/ocfs2/dlm/dlmdebug.c
index fe4fdd09bae3..564567358620 100644
--- a/fs/ocfs2/dlm/dlmdebug.c
+++ b/fs/ocfs2/dlm/dlmdebug.c
@@ -560,6 +560,7 @@ static int debug_lockres_open(struct inode *inode, struct file *file)
struct dlm_ctxt *dlm = inode->i_private;
struct debug_lockres *dl;
void *buf;
+ int status = -ENOMEM;
buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!buf)
@@ -572,16 +573,23 @@ static int debug_lockres_open(struct inode *inode, struct file *file)
dl->dl_len = PAGE_SIZE;
dl->dl_buf = buf;
- dlm_grab(dlm);
- dl->dl_ctxt = dlm;
+ /* ->release uses dl_ctxt after open, so it needs a real pin. */
+ dl->dl_ctxt = dlm_grab(dlm);
+ if (!dl->dl_ctxt) {
+ status = -ENOENT;
+ goto bailseq;
+ }
return 0;
+bailseq:
+ seq_release_private(inode, file);
bailfree:
kfree(buf);
bail:
- mlog_errno(-ENOMEM);
- return -ENOMEM;
+ if (status != -ENOENT)
+ mlog_errno(status);
+ return status;
}
static int debug_lockres_release(struct inode *inode, struct file *file)
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
index 7283bb2c5a31..a23dd8f86c89 100644
--- a/fs/ocfs2/dlmglue.c
+++ b/fs/ocfs2/dlmglue.c
@@ -3134,6 +3134,22 @@ static void *ocfs2_dlm_seq_next(struct seq_file *m, void *v, loff_t *pos)
* - Add last pr/ex unlock times and first lock wait time in usecs
*/
#define OCFS2_DLM_DEBUG_STR_VERSION 4
+
+/*
+ * The debug iterator snapshots lockres by value, so a userspace-stack LVB
+ * pointer copied from the original lockres must be rebased to the copied
+ * lksb before the dump walks the raw bytes.
+ */
+static void ocfs2_dlm_seq_rebase_lvb(struct ocfs2_lock_res *lockres)
+{
+ if (!ocfs2_stack_supports_plocks())
+ return;
+
+ if (lockres->l_lksb.lksb_fsdlm.sb_lvbptr)
+ lockres->l_lksb.lksb_fsdlm.sb_lvbptr =
+ (char *)&lockres->l_lksb + sizeof(struct dlm_lksb);
+}
+
static int ocfs2_dlm_seq_show(struct seq_file *m, void *v)
{
int i;
@@ -3191,6 +3207,7 @@ static int ocfs2_dlm_seq_show(struct seq_file *m, void *v)
lockres->l_blocking);
/* Dump the raw LVB */
+ ocfs2_dlm_seq_rebase_lvb(lockres);
lvb = ocfs2_dlm_lvb(&lockres->l_lksb);
for(i = 0; i < DLM_LVB_LEN; i++)
seq_printf(m, "0x%x\t", lvb[i]);
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index a510a0eb1adc..662dbc845b8b 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -13,6 +13,7 @@
#include <linux/pagemap.h>
#include <linux/quotaops.h>
#include <linux/iversion.h>
+#include <linux/fs_dirent.h>
#include <asm/byteorder.h>
@@ -64,7 +65,40 @@ static int ocfs2_filecheck_read_inode_block_full(struct inode *inode,
static int ocfs2_filecheck_validate_inode_block(struct super_block *sb,
struct buffer_head *bh);
static int ocfs2_filecheck_repair_inode_block(struct super_block *sb,
- struct buffer_head *bh);
+ struct buffer_head *bh);
+
+static bool ocfs2_valid_inode_mode(umode_t mode)
+{
+ return fs_umode_to_ftype(mode) != FT_UNKNOWN;
+}
+
+static bool ocfs2_dinode_has_unexpected_rdev(struct ocfs2_dinode *di)
+{
+ umode_t mode = le16_to_cpu(di->i_mode);
+
+ if (le32_to_cpu(di->i_flags) & OCFS2_SYSTEM_FL)
+ return false;
+
+ return !S_ISCHR(mode) && !S_ISBLK(mode) && di->id1.dev1.i_rdev != 0;
+}
+
+static bool ocfs2_dinode_has_size_without_clusters(struct super_block *sb,
+ struct ocfs2_dinode *di)
+{
+ umode_t mode = le16_to_cpu(di->i_mode);
+
+ if (le32_to_cpu(di->i_flags) & OCFS2_SYSTEM_FL)
+ return false;
+ if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL)
+ return false;
+ if (!le64_to_cpu(di->i_size) || le32_to_cpu(di->i_clusters))
+ return false;
+
+ if (S_ISDIR(mode))
+ return true;
+
+ return !ocfs2_sparse_alloc(OCFS2_SB(sb)) && S_ISREG(mode);
+}
void ocfs2_set_inode_flags(struct inode *inode)
{
@@ -1494,6 +1528,86 @@ int ocfs2_validate_inode_block(struct super_block *sb,
goto bail;
}
+ /*
+ * Reject dinodes whose i_mode does not name one of the seven
+ * canonical POSIX file types. ocfs2_populate_inode() copies
+ * i_mode verbatim into inode->i_mode and then dispatches via
+ * switch (mode & S_IFMT) to file/dir/symlink/special_file iops;
+ * an unrecognised type falls into ocfs2_special_file_iops with
+ * init_special_inode(), which interprets i_rdev. Constrain the
+ * type here so the dispatch only ever sees a value mkfs.ocfs2 /
+ * VFS can produce.
+ */
+ if (!ocfs2_valid_inode_mode(le16_to_cpu(di->i_mode))) {
+ rc = ocfs2_error(sb,
+ "Invalid dinode #%llu: mode 0%o has unknown file type\n",
+ (unsigned long long)bh->b_blocknr,
+ le16_to_cpu(di->i_mode));
+ goto bail;
+ }
+
+ /*
+ * id1.dev1.i_rdev is the device-number arm of the id1 union and
+ * is only meaningful for character and block device inodes. For
+ * any other regular user-visible file type the on-disk value
+ * must be zero. ocfs2_populate_inode() currently runs
+ *
+ * inode->i_rdev = huge_decode_dev(le64_to_cpu(fe->id1.dev1.i_rdev));
+ *
+ * unconditionally, before the S_IFMT switch decides whether the
+ * inode is a special file. As a result, an i_rdev value present
+ * on a non-device inode is silently published into the in-core
+ * inode; a subsequent forced re-read or in-core mode mutation
+ * (cluster peer with raw write access to the shared LUN,
+ * on-disk corruption, or a separately forged dinode) can then
+ * expose the attacker-controlled device number to
+ * init_special_inode() without ever showing an unusual i_mode
+ * at validation time.
+ *
+ * System inodes (OCFS2_SYSTEM_FL) legitimately use the bitmap1
+ * and journal1 arms of the same union (allocator i_used /
+ * i_total counters and the journal ij_flags /
+ * ij_recovery_generation pair); those bytes are not an i_rdev
+ * and must not be checked here. Restrict the cross-check to
+ * non-system inodes, which is the full attacker-controllable
+ * surface.
+ */
+ if (ocfs2_dinode_has_unexpected_rdev(di)) {
+ rc = ocfs2_error(sb,
+ "Invalid dinode #%llu: non-device mode 0%o with i_rdev %llu\n",
+ (unsigned long long)bh->b_blocknr,
+ le16_to_cpu(di->i_mode),
+ (unsigned long long)le64_to_cpu(di->id1.dev1.i_rdev));
+ goto bail;
+ }
+
+ /*
+ * Non-inline directories must not have i_size without allocated
+ * clusters: directory growth adds storage before advancing i_size,
+ * and readdir walks i_size block-by-block. A forged directory
+ * with zero clusters and a huge i_size would repeatedly fault on
+ * holes while advancing through the claimed size.
+ *
+ * Non-inline regular files have the same invariant on non-sparse
+ * volumes. Sparse regular files are different: truncate can
+ * legitimately grow i_size without allocating clusters, so keep
+ * the sparse-alloc carveout for S_IFREG only. System inodes and
+ * inline-data dinodes have their own storage rules.
+ */
+ if (ocfs2_dinode_has_size_without_clusters(sb, di)) {
+ if (S_ISDIR(le16_to_cpu(di->i_mode)))
+ rc = ocfs2_error(sb,
+ "Invalid dinode #%llu: directory i_size %llu with i_clusters 0 and no inline-data flag\n",
+ (unsigned long long)bh->b_blocknr,
+ (unsigned long long)le64_to_cpu(di->i_size));
+ else
+ rc = ocfs2_error(sb,
+ "Invalid dinode #%llu: regular file i_size %llu with i_clusters 0 and no inline-data flag on non-sparse volume\n",
+ (unsigned long long)bh->b_blocknr,
+ (unsigned long long)le64_to_cpu(di->i_size));
+ goto bail;
+ }
+
if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL) {
struct ocfs2_inline_data *data = &di->id2.i_data;
@@ -1525,6 +1639,29 @@ int ocfs2_validate_inode_block(struct super_block *sb,
}
}
+ if (S_ISLNK(le16_to_cpu(di->i_mode)) &&
+ !le32_to_cpu(di->i_clusters)) {
+ int max_inline = ocfs2_fast_symlink_chars(sb);
+ u64 i_size = le64_to_cpu(di->i_size);
+
+ if (i_size >= max_inline) {
+ rc = ocfs2_error(sb,
+ "Invalid dinode #%llu: fast symlink i_size %llu exceeds max %d\n",
+ (unsigned long long)bh->b_blocknr,
+ (unsigned long long)i_size,
+ max_inline - 1);
+ goto bail;
+ }
+
+ if (strnlen((char *)di->id2.i_symlink, i_size + 1) != i_size) {
+ rc = ocfs2_error(sb,
+ "Invalid dinode #%llu: fast symlink is not NUL-terminated at i_size %llu\n",
+ (unsigned long long)bh->b_blocknr,
+ (unsigned long long)i_size);
+ goto bail;
+ }
+ }
+
if (le32_to_cpu(di->i_flags) & OCFS2_CHAIN_FL) {
struct ocfs2_chain_list *cl = &di->id2.i_chain;
u16 bpc = 1 << (OCFS2_SB(sb)->s_clustersize_bits -
@@ -1559,6 +1696,38 @@ int ocfs2_validate_inode_block(struct super_block *sb,
goto bail;
}
+ if (ocfs2_dinode_has_extents(di)) {
+ struct ocfs2_extent_list *el = &di->id2.i_list;
+ u16 count = le16_to_cpu(el->l_count);
+ u16 next_free = le16_to_cpu(el->l_next_free_rec);
+
+ if (count == 0) {
+ rc = ocfs2_error(sb,
+ "Invalid dinode %llu: extent list l_count is zero\n",
+ (unsigned long long)bh->b_blocknr);
+ goto bail;
+ }
+ /*
+ * The exact capacity depends on i_xattr_inline_size, another
+ * unvalidated on-disk field. Inline xattrs only shrink the
+ * list, so the no-xattr maximum is a safe upper bound that a
+ * valid l_count never exceeds.
+ */
+ if (count > ocfs2_extent_recs_per_inode(sb)) {
+ rc = ocfs2_error(sb,
+ "Invalid dinode %llu: extent list l_count %u exceeds max %u\n",
+ (unsigned long long)bh->b_blocknr, count,
+ ocfs2_extent_recs_per_inode(sb));
+ goto bail;
+ }
+ if (next_free > count) {
+ rc = ocfs2_error(sb,
+ "Invalid dinode %llu: extent list l_next_free_rec %u exceeds l_count %u\n",
+ (unsigned long long)bh->b_blocknr, next_free, count);
+ goto bail;
+ }
+ }
+
rc = 0;
bail:
@@ -1624,6 +1793,40 @@ static int ocfs2_filecheck_validate_inode_block(struct super_block *sb,
(unsigned long long)bh->b_blocknr,
le32_to_cpu(di->i_fs_generation));
rc = -OCFS2_FILECHECK_ERR_GENERATION;
+ goto bail;
+ }
+
+ if (!ocfs2_valid_inode_mode(le16_to_cpu(di->i_mode))) {
+ mlog(ML_ERROR,
+ "Filecheck: invalid dinode #%llu: mode 0%o has unknown file type\n",
+ (unsigned long long)bh->b_blocknr,
+ le16_to_cpu(di->i_mode));
+ rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
+ goto bail;
+ }
+
+ if (ocfs2_dinode_has_unexpected_rdev(di)) {
+ mlog(ML_ERROR,
+ "Filecheck: invalid dinode #%llu: non-device mode 0%o with i_rdev %llu\n",
+ (unsigned long long)bh->b_blocknr,
+ le16_to_cpu(di->i_mode),
+ (unsigned long long)le64_to_cpu(di->id1.dev1.i_rdev));
+ rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
+ goto bail;
+ }
+
+ if (ocfs2_dinode_has_size_without_clusters(sb, di)) {
+ if (S_ISDIR(le16_to_cpu(di->i_mode)))
+ mlog(ML_ERROR,
+ "Filecheck: invalid dinode #%llu: directory i_size %llu with i_clusters 0 and no inline-data flag\n",
+ (unsigned long long)bh->b_blocknr,
+ (unsigned long long)le64_to_cpu(di->i_size));
+ else
+ mlog(ML_ERROR,
+ "Filecheck: invalid dinode #%llu: regular file i_size %llu with i_clusters 0 and no inline-data flag on non-sparse volume\n",
+ (unsigned long long)bh->b_blocknr,
+ (unsigned long long)le64_to_cpu(di->i_size));
+ rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
}
bail:
@@ -1812,4 +2015,3 @@ const struct ocfs2_caching_operations ocfs2_inode_caching_ops = {
.co_io_lock = ocfs2_inode_cache_io_lock,
.co_io_unlock = ocfs2_inode_cache_io_unlock,
};
-
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index f9bf3bac085d..d8afbc1a76bb 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -473,8 +473,12 @@ bail:
*/
int ocfs2_assure_trans_credits(handle_t *handle, int nblocks)
{
- int old_nblks = jbd2_handle_buffer_credits(handle);
+ int old_nblks;
+ if (is_handle_aborted(handle))
+ return -EROFS;
+
+ old_nblks = jbd2_handle_buffer_credits(handle);
trace_ocfs2_assure_trans_credits(old_nblks);
if (old_nblks >= nblocks)
return 0;
@@ -1022,11 +1026,8 @@ static int ocfs2_journal_toggle_dirty(struct ocfs2_super *osb,
struct ocfs2_dinode *fe;
fe = (struct ocfs2_dinode *)bh->b_data;
-
- /* The journal bh on the osb always comes from ocfs2_journal_init()
- * and was validated there inside ocfs2_inode_lock_full(). It's a
- * code bug if we mess it up. */
- BUG_ON(!OCFS2_IS_VALID_DINODE(fe));
+ if (WARN_ON(!OCFS2_IS_VALID_DINODE(fe)))
+ return -EIO;
flags = le32_to_cpu(fe->id1.journal1.ij_flags);
if (dirty)
diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h
index 6397170f302f..f8b3b2a3d630 100644
--- a/fs/ocfs2/journal.h
+++ b/fs/ocfs2/journal.h
@@ -196,6 +196,9 @@ static inline void ocfs2_checkpoint_inode(struct inode *inode)
if (ocfs2_mount_local(osb))
return;
+ if (!osb->journal)
+ return;
+
if (!ocfs2_ci_fully_checkpointed(INODE_CACHE(inode))) {
/* WARNING: This only kicks off a single
* checkpoint. If someone races you and adds more
diff --git a/fs/ocfs2/move_extents.c b/fs/ocfs2/move_extents.c
index c53de4439d93..ad1678ee7cc4 100644
--- a/fs/ocfs2/move_extents.c
+++ b/fs/ocfs2/move_extents.c
@@ -534,6 +534,8 @@ static void ocfs2_probe_alloc_group(struct inode *inode, struct buffer_head *bh,
u32 base_cpos = ocfs2_blocks_to_clusters(inode->i_sb,
le64_to_cpu(gd->bg_blkno));
+ *phys_cpos = 0;
+
for (i = base_bit; i < le16_to_cpu(gd->bg_bits); i++) {
used = ocfs2_test_bit(i, (unsigned long *)gd->bg_bitmap);
@@ -555,7 +557,7 @@ static void ocfs2_probe_alloc_group(struct inode *inode, struct buffer_head *bh,
last_free_bits++;
if (last_free_bits == move_len) {
- i -= move_len;
+ i = i - move_len + 1;
*goal_bit = i;
*phys_cpos = base_cpos + i;
break;
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
index 7b50e03dfa66..62cad6522c7a 100644
--- a/fs/ocfs2/ocfs2.h
+++ b/fs/ocfs2/ocfs2.h
@@ -494,8 +494,6 @@ struct ocfs2_super
struct rb_root osb_rf_lock_tree;
struct ocfs2_refcount_tree *osb_ref_tree_lru;
- struct mutex system_file_mutex;
-
/*
* OCFS2 needs to schedule several different types of work which
* require cluster locking, disk I/O, recovery waits, etc. Since these
diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c
index 12cbb4fccda0..f55810c59b1b 100644
--- a/fs/ocfs2/quota_local.c
+++ b/fs/ocfs2/quota_local.c
@@ -302,7 +302,7 @@ static int ocfs2_add_recovery_chunk(struct super_block *sb,
if (!rc)
return -ENOMEM;
rc->rc_chunk = chunk;
- rc->rc_bitmap = kmalloc(sb->s_blocksize, GFP_NOFS);
+ rc->rc_bitmap = kzalloc(sb->s_blocksize, GFP_NOFS);
if (!rc->rc_bitmap) {
kfree(rc);
return -ENOMEM;
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c
index 8eee5be4d1ed..7323bde70caa 100644
--- a/fs/ocfs2/refcounttree.c
+++ b/fs/ocfs2/refcounttree.c
@@ -2131,10 +2131,15 @@ static int ocfs2_remove_refcount_extent(handle_t *handle,
rb->rf_flags = 0;
rb->rf_parent = 0;
rb->rf_cpos = 0;
- memset(&rb->rf_records, 0, sb->s_blocksize -
- offsetof(struct ocfs2_refcount_block, rf_records));
+ rb->rf_records.rl_used = 0;
+ rb->rf_records.rl_reserved2 = 0;
+ rb->rf_records.rl_reserved1 = 0;
+ /* rl_count determines the memset size and fortify object size. */
rb->rf_records.rl_count =
cpu_to_le16(ocfs2_refcount_recs_per_rb(sb));
+ memset(rb->rf_records.rl_recs, 0,
+ le16_to_cpu(rb->rf_records.rl_count) *
+ sizeof(*rb->rf_records.rl_recs));
}
ocfs2_journal_dirty(handle, ref_root_bh);
diff --git a/fs/ocfs2/stack_user.c b/fs/ocfs2/stack_user.c
index 5803f1dee679..91e19d33847c 100644
--- a/fs/ocfs2/stack_user.c
+++ b/fs/ocfs2/stack_user.c
@@ -327,18 +327,14 @@ static int ocfs2_control_install_private(struct file *file)
ocfs2_control_this_node = p->op_this_node;
running_proto.pv_major = p->op_proto.pv_major;
running_proto.pv_minor = p->op_proto.pv_minor;
- }
-
-out_unlock:
- mutex_unlock(&ocfs2_control_lock);
-
- if (!rc && set_p) {
- /* We set the global values successfully */
atomic_inc(&ocfs2_control_opened);
ocfs2_control_set_handshake_state(file,
OCFS2_CONTROL_HANDSHAKE_VALID);
}
+out_unlock:
+ mutex_unlock(&ocfs2_control_lock);
+
return rc;
}
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index b875f01c9756..6dd45c2153f8 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -1997,8 +1997,6 @@ static int ocfs2_initialize_super(struct super_block *sb,
spin_lock_init(&osb->osb_xattr_lock);
ocfs2_init_steal_slots(osb);
- mutex_init(&osb->system_file_mutex);
-
atomic_set(&osb->alloc_stats.moves, 0);
atomic_set(&osb->alloc_stats.local_data, 0);
atomic_set(&osb->alloc_stats.bitmap_data, 0);
diff --git a/fs/ocfs2/sysfile.c b/fs/ocfs2/sysfile.c
index d53a6cc866be..67e492f4b828 100644
--- a/fs/ocfs2/sysfile.c
+++ b/fs/ocfs2/sysfile.c
@@ -98,11 +98,9 @@ struct inode *ocfs2_get_system_file_inode(struct ocfs2_super *osb,
} else
arr = get_local_system_inode(osb, type, slot);
- mutex_lock(&osb->system_file_mutex);
if (arr && ((inode = *arr) != NULL)) {
/* get a ref in addition to the array ref */
inode = igrab(inode);
- mutex_unlock(&osb->system_file_mutex);
BUG_ON(!inode);
return inode;
@@ -112,11 +110,10 @@ struct inode *ocfs2_get_system_file_inode(struct ocfs2_super *osb,
inode = _ocfs2_get_system_file_inode(osb, type, slot);
/* add one more if putting into array for first time */
- if (arr && inode) {
- *arr = igrab(inode);
- BUG_ON(!*arr);
+ if (inode && arr && !*arr && !cmpxchg(&(*arr), NULL, inode)) {
+ inode = igrab(inode);
+ BUG_ON(!inode);
}
- mutex_unlock(&osb->system_file_mutex);
return inode;
}