linux/fs/orangefs/orangefs-mod.c
Zhang Xiaoxu ea60a4ad0c orangefs: Fix sysfs not cleanup when dev init failed
When the dev init failed, should cleanup the sysfs, otherwise, the
module will never be loaded since can not create duplicate sysfs
directory:

  sysfs: cannot create duplicate filename '/fs/orangefs'

  CPU: 1 PID: 6549 Comm: insmod Tainted: G        W          6.0.0+ #44
  Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-1.fc33 04/01/2014
  Call Trace:
   <TASK>
   dump_stack_lvl+0x34/0x44
   sysfs_warn_dup.cold+0x17/0x24
   sysfs_create_dir_ns+0x16d/0x180
   kobject_add_internal+0x156/0x3a0
   kobject_init_and_add+0xcf/0x120
   orangefs_sysfs_init+0x7e/0x3a0 [orangefs]
   orangefs_init+0xfe/0x1000 [orangefs]
   do_one_initcall+0x87/0x2a0
   do_init_module+0xdf/0x320
   load_module+0x2f98/0x3330
   __do_sys_finit_module+0x113/0x1b0
   do_syscall_64+0x35/0x80
   entry_SYSCALL_64_after_hwframe+0x46/0xb0

  kobject_add_internal failed for orangefs with -EEXIST, don't try to register things with the same name in the same directory.

Fixes: 2f83ace371 ("orangefs: put register_chrdev immediately before register_filesystem")
Signed-off-by: Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
Signed-off-by: Mike Marshall <hubcap@omnibond.com>
2022-12-07 15:18:29 -05:00

232 lines
5.9 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* (C) 2001 Clemson University and The University of Chicago
*
* Changes by Acxiom Corporation to add proc file handler for pvfs2 client
* parameters, Copyright Acxiom Corporation, 2005.
*
* See COPYING in top-level directory.
*/
#include "protocol.h"
#include "orangefs-kernel.h"
#include "orangefs-debugfs.h"
#include "orangefs-sysfs.h"
/* ORANGEFS_VERSION is a ./configure define */
#ifndef ORANGEFS_VERSION
#define ORANGEFS_VERSION "upstream"
#endif
/*
* global variables declared here
*/
struct orangefs_stats orangefs_stats;
/* the size of the hash tables for ops in progress */
int hash_table_size = 509;
static ulong module_parm_debug_mask;
__u64 orangefs_gossip_debug_mask;
int op_timeout_secs = ORANGEFS_DEFAULT_OP_TIMEOUT_SECS;
int slot_timeout_secs = ORANGEFS_DEFAULT_SLOT_TIMEOUT_SECS;
int orangefs_cache_timeout_msecs = 500;
int orangefs_dcache_timeout_msecs = 50;
int orangefs_getattr_timeout_msecs = 50;
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ORANGEFS Development Team");
MODULE_DESCRIPTION("The Linux Kernel VFS interface to ORANGEFS");
MODULE_PARM_DESC(module_parm_debug_mask, "debugging level (see orangefs-debug.h for values)");
MODULE_PARM_DESC(op_timeout_secs, "Operation timeout in seconds");
MODULE_PARM_DESC(slot_timeout_secs, "Slot timeout in seconds");
MODULE_PARM_DESC(hash_table_size,
"size of hash table for operations in progress");
static struct file_system_type orangefs_fs_type = {
.name = "pvfs2",
.mount = orangefs_mount,
.kill_sb = orangefs_kill_sb,
.owner = THIS_MODULE,
};
module_param(hash_table_size, int, 0);
module_param(module_parm_debug_mask, ulong, 0644);
module_param(op_timeout_secs, int, 0);
module_param(slot_timeout_secs, int, 0);
/*
* Blocks non-priority requests from being queued for servicing. This
* could be used for protecting the request list data structure, but
* for now it's only being used to stall the op addition to the request
* list
*/
DEFINE_MUTEX(orangefs_request_mutex);
/* hash table for storing operations waiting for matching downcall */
struct list_head *orangefs_htable_ops_in_progress;
DEFINE_SPINLOCK(orangefs_htable_ops_in_progress_lock);
/* list for queueing upcall operations */
LIST_HEAD(orangefs_request_list);
/* used to protect the above orangefs_request_list */
DEFINE_SPINLOCK(orangefs_request_list_lock);
/* used for incoming request notification */
DECLARE_WAIT_QUEUE_HEAD(orangefs_request_list_waitq);
static int __init orangefs_init(void)
{
int ret;
__u32 i = 0;
if (op_timeout_secs < 0)
op_timeout_secs = 0;
if (slot_timeout_secs < 0)
slot_timeout_secs = 0;
/* initialize global book keeping data structures */
ret = op_cache_initialize();
if (ret < 0)
goto out;
ret = orangefs_inode_cache_initialize();
if (ret < 0)
goto cleanup_op;
orangefs_htable_ops_in_progress =
kcalloc(hash_table_size, sizeof(struct list_head), GFP_KERNEL);
if (!orangefs_htable_ops_in_progress) {
ret = -ENOMEM;
goto cleanup_inode;
}
/* initialize a doubly linked at each hash table index */
for (i = 0; i < hash_table_size; i++)
INIT_LIST_HEAD(&orangefs_htable_ops_in_progress[i]);
ret = fsid_key_table_initialize();
if (ret < 0)
goto cleanup_progress_table;
/*
* Build the contents of /sys/kernel/debug/orangefs/debug-help
* from the keywords in the kernel keyword/mask array.
*
* The keywords in the client keyword/mask array are
* unknown at boot time.
*
* orangefs_prepare_debugfs_help_string will be used again
* later to rebuild the debug-help-string after the client starts
* and passes along the needed info. The argument signifies
* which time orangefs_prepare_debugfs_help_string is being
* called.
*/
ret = orangefs_prepare_debugfs_help_string(1);
if (ret)
goto cleanup_key_table;
orangefs_debugfs_init(module_parm_debug_mask);
ret = orangefs_sysfs_init();
if (ret)
goto sysfs_init_failed;
/* Initialize the orangefsdev subsystem. */
ret = orangefs_dev_init();
if (ret < 0) {
gossip_err("%s: could not initialize device subsystem %d!\n",
__func__,
ret);
goto cleanup_sysfs;
}
ret = register_filesystem(&orangefs_fs_type);
if (ret == 0) {
pr_info("%s: module version %s loaded\n",
__func__,
ORANGEFS_VERSION);
goto out;
}
orangefs_dev_cleanup();
cleanup_sysfs:
orangefs_sysfs_exit();
sysfs_init_failed:
orangefs_debugfs_cleanup();
cleanup_key_table:
fsid_key_table_finalize();
cleanup_progress_table:
kfree(orangefs_htable_ops_in_progress);
cleanup_inode:
orangefs_inode_cache_finalize();
cleanup_op:
op_cache_finalize();
out:
return ret;
}
static void __exit orangefs_exit(void)
{
int i = 0;
gossip_debug(GOSSIP_INIT_DEBUG, "orangefs: orangefs_exit called\n");
unregister_filesystem(&orangefs_fs_type);
orangefs_debugfs_cleanup();
orangefs_sysfs_exit();
fsid_key_table_finalize();
orangefs_dev_cleanup();
BUG_ON(!list_empty(&orangefs_request_list));
for (i = 0; i < hash_table_size; i++)
BUG_ON(!list_empty(&orangefs_htable_ops_in_progress[i]));
orangefs_inode_cache_finalize();
op_cache_finalize();
kfree(orangefs_htable_ops_in_progress);
pr_info("orangefs: module version %s unloaded\n", ORANGEFS_VERSION);
}
/*
* What we do in this function is to walk the list of operations
* that are in progress in the hash table and mark them as purged as well.
*/
void purge_inprogress_ops(void)
{
int i;
for (i = 0; i < hash_table_size; i++) {
struct orangefs_kernel_op_s *op;
struct orangefs_kernel_op_s *next;
spin_lock(&orangefs_htable_ops_in_progress_lock);
list_for_each_entry_safe(op,
next,
&orangefs_htable_ops_in_progress[i],
list) {
set_op_state_purged(op);
gossip_debug(GOSSIP_DEV_DEBUG,
"%s: op:%s: op_state:%d: process:%s:\n",
__func__,
get_opname_string(op),
op->op_state,
current->comm);
}
spin_unlock(&orangefs_htable_ops_in_progress_lock);
}
}
module_init(orangefs_init);
module_exit(orangefs_exit);