#define DEBUG_SUBSYSTEM S_CLASS
#include <linux/pid_namespace.h>
-#include <linux/kthread.h>
+#include <linux/workqueue.h>
+#include <lustre_compat.h>
#include <obd_class.h>
#include <lustre_log.h>
#include <lprocfs_status.h>
EXPORT_SYMBOL(obdo_cachep);
static struct kmem_cache *import_cachep;
-static LIST_HEAD(obd_zombie_imports);
-static LIST_HEAD(obd_zombie_exports);
-static DEFINE_SPINLOCK(obd_zombie_impexp_lock);
+static struct workqueue_struct *zombie_wq;
-static void obd_zombie_impexp_notify(void);
static void obd_zombie_export_add(struct obd_export *exp);
static void obd_zombie_import_add(struct obd_import *imp);
static void print_export_data(struct obd_export *exp,
static void class_sysfs_release(struct kobject *kobj)
{
- struct obd_type *type = container_of(kobj, struct obd_type,
- typ_kobj);
-
- complete(&type->typ_kobj_unregister);
+ OBD_FREE(kobj, sizeof(*kobj));
}
static struct kobj_type class_ktype = {
.release = class_sysfs_release,
};
+struct kobject *class_setup_tunables(const char *name)
+{
+ struct kobject *kobj;
+ int rc;
+
+#ifdef HAVE_SERVER_SUPPORT
+ kobj = kset_find_obj(lustre_kset, name);
+ if (kobj)
+ return kobj;
+#endif
+ OBD_ALLOC(kobj, sizeof(*kobj));
+ if (!kobj)
+ return ERR_PTR(-ENOMEM);
+
+ kobj->kset = lustre_kset;
+ kobject_init(kobj, &class_ktype);
+ rc = kobject_add(kobj, &lustre_kset->kobj, "%s", name);
+ if (rc) {
+ kobject_put(kobj);
+ return ERR_PTR(rc);
+ }
+ return kobj;
+}
+EXPORT_SYMBOL(class_setup_tunables);
+
#define CLASS_MAX_NAME 1024
int class_register_type(struct obd_ops *dt_ops, struct md_ops *md_ops,
bool enable_proc, struct lprocfs_vars *vars,
const char *name, struct lu_device_type *ldt)
{
- struct obd_type *type;
- int rc = 0;
- ENTRY;
+ struct obd_type *type;
+#ifdef HAVE_SERVER_SUPPORT
+ struct qstr dname;
+#endif /* HAVE_SERVER_SUPPORT */
+ int rc = 0;
- /* sanity check */
- LASSERT(strnlen(name, CLASS_MAX_NAME) < CLASS_MAX_NAME);
+ ENTRY;
+ /* sanity check */
+ LASSERT(strnlen(name, CLASS_MAX_NAME) < CLASS_MAX_NAME);
if (class_search_type(name)) {
CDEBUG(D_IOCTL, "Type %s already registered\n", name);
}
}
#endif
- type->typ_kobj.kset = lustre_kset;
- init_completion(&type->typ_kobj_unregister);
- rc = kobject_init_and_add(&type->typ_kobj, &class_ktype,
- &lustre_kset->kobj, "%s", type->typ_name);
- if (rc)
+#ifdef HAVE_SERVER_SUPPORT
+ dname.name = name;
+ dname.len = strlen(dname.name);
+ dname.hash = ll_full_name_hash(debugfs_lustre_root, dname.name,
+ dname.len);
+ type->typ_debugfs_entry = d_lookup(debugfs_lustre_root, &dname);
+ if (type->typ_debugfs_entry) {
+ dput(type->typ_debugfs_entry);
+ type->typ_sym_filter = true;
+ goto dir_exist;
+ }
+#endif /* HAVE_SERVER_SUPPORT */
+
+ type->typ_debugfs_entry = ldebugfs_register(type->typ_name,
+ debugfs_lustre_root,
+ NULL, type);
+ if (IS_ERR_OR_NULL(type->typ_debugfs_entry)) {
+ rc = type->typ_debugfs_entry ? PTR_ERR(type->typ_debugfs_entry)
+ : -ENOMEM;
+ type->typ_debugfs_entry = NULL;
GOTO(failed, rc);
+ }
+#ifdef HAVE_SERVER_SUPPORT
+dir_exist:
+#endif
+ type->typ_kobj = class_setup_tunables(type->typ_name);
+ if (IS_ERR(type->typ_kobj))
+ GOTO(failed, rc = PTR_ERR(type->typ_kobj));
if (ldt) {
type->typ_lu = ldt;
rc = lu_device_type_init(ldt);
if (rc) {
- kobject_put(&type->typ_kobj);
+ kobject_put(type->typ_kobj);
GOTO(failed, rc);
}
}
RETURN(0);
failed:
+#ifdef HAVE_SERVER_SUPPORT
+ if (type->typ_sym_filter)
+ type->typ_debugfs_entry = NULL;
+#endif
+ if (!IS_ERR_OR_NULL(type->typ_debugfs_entry))
+ ldebugfs_remove(&type->typ_debugfs_entry);
if (type->typ_name != NULL) {
#ifdef CONFIG_PROC_FS
if (type->typ_procroot != NULL)
RETURN(-EBUSY);
}
- kobject_put(&type->typ_kobj);
- wait_for_completion(&type->typ_kobj_unregister);
+ kobject_put(type->typ_kobj);
/* we do not use type->typ_procroot as for compatibility purposes
* other modules can share names (i.e. lod can use lov entry). so
if (type->typ_procsym != NULL)
lprocfs_remove(&type->typ_procsym);
#endif
+#ifdef HAVE_SERVER_SUPPORT
+ if (type->typ_sym_filter)
+ type->typ_debugfs_entry = NULL;
+#endif
+ if (!IS_ERR_OR_NULL(type->typ_debugfs_entry))
+ ldebugfs_remove(&type->typ_debugfs_entry);
+
if (type->typ_lu)
lu_device_type_fini(type->typ_lu);
}
}
EXPORT_SYMBOL(class_export_put);
+
+static void obd_zombie_exp_cull(struct work_struct *ws)
+{
+ struct obd_export *export;
+
+ export = container_of(ws, struct obd_export, exp_zombie_work);
+ class_export_destroy(export);
+}
+
/* Creates a new export, adds it to the hash table, and returns a
* pointer to it. The refcount is 2: one for the hash reference, and
* one for the pointer returned by this function. */
spin_lock_init(&export->exp_bl_list_lock);
INIT_LIST_HEAD(&export->exp_bl_list);
INIT_LIST_HEAD(&export->exp_stale_list);
+ INIT_WORK(&export->exp_zombie_work, obd_zombie_exp_cull);
export->exp_sp_peer = LUSTRE_SP_ANY;
export->exp_flvr.sf_rpc = SPTLRPC_FLVR_INVALID;
{
ENTRY;
- LASSERT(list_empty(&imp->imp_zombie_chain));
LASSERT_ATOMIC_GT_LT(&imp->imp_refcount, 0, LI_POISON);
CDEBUG(D_INFO, "import %p refcount=%d obd=%s\n", imp,
}
}
+static void obd_zombie_imp_cull(struct work_struct *ws)
+{
+ struct obd_import *import;
+
+ import = container_of(ws, struct obd_import, imp_zombie_work);
+ class_import_destroy(import);
+}
+
struct obd_import *class_new_import(struct obd_device *obd)
{
struct obd_import *imp;
return NULL;
INIT_LIST_HEAD(&imp->imp_pinger_chain);
- INIT_LIST_HEAD(&imp->imp_zombie_chain);
INIT_LIST_HEAD(&imp->imp_replay_list);
INIT_LIST_HEAD(&imp->imp_sending_list);
INIT_LIST_HEAD(&imp->imp_delayed_list);
imp->imp_obd = class_incref(obd, "import", imp);
mutex_init(&imp->imp_sec_mutex);
init_waitqueue_head(&imp->imp_recovery_waitq);
+ INIT_WORK(&imp->imp_zombie_work, obd_zombie_imp_cull);
if (curr_pid_ns->child_reaper)
imp->imp_sec_refpid = curr_pid_ns->child_reaper->pid;
spin_unlock(&exp->exp_lock);
list_move(&exp->exp_obd_chain, &work_list);
- evicted++;
- CDEBUG(D_HA, "%s: disconnect stale client %s@%s\n",
- obd->obd_name, exp->exp_client_uuid.uuid,
- exp->exp_connection == NULL ? "<unknown>" :
- libcfs_nid2str(exp->exp_connection->c_peer.nid));
- print_export_data(exp, "EVICTING", 0, D_HA);
- }
+ evicted++;
+ CDEBUG(D_HA, "%s: disconnect stale client %s@%s\n",
+ obd->obd_name, exp->exp_client_uuid.uuid,
+ obd_export_nid2str(exp));
+ print_export_data(exp, "EVICTING", 0, D_HA);
+ }
spin_unlock(&obd->obd_dev_lock);
if (evicted)
}
EXPORT_SYMBOL(class_fail_export);
-char *obd_export_nid2str(struct obd_export *exp)
-{
- if (exp->exp_connection != NULL)
- return libcfs_nid2str(exp->exp_connection->c_peer.nid);
-
- return "(no nid)";
-}
-EXPORT_SYMBOL(obd_export_nid2str);
-
int obd_export_evict_by_nid(struct obd_device *obd, const char *nid)
{
struct cfs_hash *nid_hash;
list_for_each_entry(exp, &obd->obd_delayed_exports, exp_obd_chain)
print_export_data(exp, "DELAYED", locks, debug_level);
spin_unlock(&obd->obd_dev_lock);
- spin_lock(&obd_zombie_impexp_lock);
- list_for_each_entry(exp, &obd_zombie_exports, exp_obd_chain)
- print_export_data(exp, "ZOMBIE", locks, debug_level);
- spin_unlock(&obd_zombie_impexp_lock);
}
void obd_exports_barrier(struct obd_device *obd)
}
EXPORT_SYMBOL(obd_exports_barrier);
-/* Total amount of zombies to be destroyed */
-static int zombies_count = 0;
-
-/**
- * kill zombie imports and exports
- */
-void obd_zombie_impexp_cull(void)
-{
- struct obd_import *import;
- struct obd_export *export;
- ENTRY;
-
- do {
- spin_lock(&obd_zombie_impexp_lock);
-
- import = NULL;
- if (!list_empty(&obd_zombie_imports)) {
- import = list_entry(obd_zombie_imports.next,
- struct obd_import,
- imp_zombie_chain);
- list_del_init(&import->imp_zombie_chain);
- }
-
- export = NULL;
- if (!list_empty(&obd_zombie_exports)) {
- export = list_entry(obd_zombie_exports.next,
- struct obd_export,
- exp_obd_chain);
- list_del_init(&export->exp_obd_chain);
- }
-
- spin_unlock(&obd_zombie_impexp_lock);
-
- if (import != NULL) {
- class_import_destroy(import);
- spin_lock(&obd_zombie_impexp_lock);
- zombies_count--;
- spin_unlock(&obd_zombie_impexp_lock);
- }
-
- if (export != NULL) {
- class_export_destroy(export);
- spin_lock(&obd_zombie_impexp_lock);
- zombies_count--;
- spin_unlock(&obd_zombie_impexp_lock);
- }
-
- cond_resched();
- } while (import != NULL || export != NULL);
- EXIT;
-}
-
-static DECLARE_COMPLETION(obd_zombie_start);
-static DECLARE_COMPLETION(obd_zombie_stop);
-static unsigned long obd_zombie_flags;
-static DECLARE_WAIT_QUEUE_HEAD(obd_zombie_waitq);
-static pid_t obd_zombie_pid;
-
-enum {
- OBD_ZOMBIE_STOP = 0x0001,
-};
-
-/**
- * check for work for kill zombie import/export thread.
- */
-static int obd_zombie_impexp_check(void *arg)
-{
- int rc;
-
- spin_lock(&obd_zombie_impexp_lock);
- rc = (zombies_count == 0) &&
- !test_bit(OBD_ZOMBIE_STOP, &obd_zombie_flags);
- spin_unlock(&obd_zombie_impexp_lock);
-
- RETURN(rc);
-}
-
/**
* Add export to the obd_zombe thread and notify it.
*/
LASSERT(!list_empty(&exp->exp_obd_chain));
list_del_init(&exp->exp_obd_chain);
spin_unlock(&exp->exp_obd->obd_dev_lock);
- spin_lock(&obd_zombie_impexp_lock);
- zombies_count++;
- list_add(&exp->exp_obd_chain, &obd_zombie_exports);
- spin_unlock(&obd_zombie_impexp_lock);
- obd_zombie_impexp_notify();
+ queue_work(zombie_wq, &exp->exp_zombie_work);
}
/**
*/
static void obd_zombie_import_add(struct obd_import *imp) {
LASSERT(imp->imp_sec == NULL);
- spin_lock(&obd_zombie_impexp_lock);
- LASSERT(list_empty(&imp->imp_zombie_chain));
- zombies_count++;
- list_add(&imp->imp_zombie_chain, &obd_zombie_imports);
- spin_unlock(&obd_zombie_impexp_lock);
- obd_zombie_impexp_notify();
-}
-
-/**
- * notify import/export destroy thread about new zombie.
- */
-static void obd_zombie_impexp_notify(void)
-{
- /*
- * Make sure obd_zomebie_impexp_thread get this notification.
- * It is possible this signal only get by obd_zombie_barrier, and
- * barrier gulps this notification and sleeps away and hangs ensues
- */
- wake_up_all(&obd_zombie_waitq);
-}
-
-/**
- * check whether obd_zombie is idle
- */
-static int obd_zombie_is_idle(void)
-{
- int rc;
-
- LASSERT(!test_bit(OBD_ZOMBIE_STOP, &obd_zombie_flags));
- spin_lock(&obd_zombie_impexp_lock);
- rc = (zombies_count == 0);
- spin_unlock(&obd_zombie_impexp_lock);
- return rc;
+ queue_work(zombie_wq, &imp->imp_zombie_work);
}
/**
*/
void obd_zombie_barrier(void)
{
- struct l_wait_info lwi = { 0 };
-
- if (obd_zombie_pid == current_pid())
- /* don't wait for myself */
- return;
- l_wait_event(obd_zombie_waitq, obd_zombie_is_idle(), &lwi);
+ flush_workqueue(zombie_wq);
}
EXPORT_SYMBOL(obd_zombie_barrier);
EXPORT_SYMBOL(obd_stale_export_adjust);
/**
- * destroy zombie export/import thread.
- */
-static int obd_zombie_impexp_thread(void *unused)
-{
- unshare_fs_struct();
- complete(&obd_zombie_start);
-
- obd_zombie_pid = current_pid();
-
- while (!test_bit(OBD_ZOMBIE_STOP, &obd_zombie_flags)) {
- struct l_wait_info lwi = { 0 };
-
- l_wait_event(obd_zombie_waitq,
- !obd_zombie_impexp_check(NULL), &lwi);
- obd_zombie_impexp_cull();
-
- /*
- * Notify obd_zombie_barrier callers that queues
- * may be empty.
- */
- wake_up(&obd_zombie_waitq);
- }
-
- complete(&obd_zombie_stop);
-
- RETURN(0);
-}
-
-
-/**
* start destroy zombie import/export thread
*/
int obd_zombie_impexp_init(void)
{
- struct task_struct *task;
-
- task = kthread_run(obd_zombie_impexp_thread, NULL, "obd_zombid");
- if (IS_ERR(task))
- RETURN(PTR_ERR(task));
+ zombie_wq = alloc_workqueue("obd_zombid", 0, 0);
+ if (!zombie_wq)
+ return -ENOMEM;
- wait_for_completion(&obd_zombie_start);
- RETURN(0);
+ return 0;
}
+
/**
* stop destroy zombie import/export thread
*/
void obd_zombie_impexp_stop(void)
{
- set_bit(OBD_ZOMBIE_STOP, &obd_zombie_flags);
- obd_zombie_impexp_notify();
- wait_for_completion(&obd_zombie_stop);
+ destroy_workqueue(zombie_wq);
LASSERT(list_empty(&obd_stale_exports));
}
if (it != NULL &&
(it->it_op == IT_GETATTR || it->it_op == IT_LOOKUP ||
it->it_op == IT_READDIR ||
- (it->it_op == IT_LAYOUT && !(it->it_flags & FMODE_WRITE))))
+ (it->it_op == IT_LAYOUT && !(it->it_flags & MDS_FMODE_WRITE))))
return true;
return false;
}