This patch puts in place the basics needed for debugfs.
It also creates class_setup_tunables so sysfs kobject
creation is handled for both obd_devices and llite. Add a
special LDEBUGFS_FOPS_WR_ONLY since often in this case
i_private is not set so any attempt to call PDE_DATA(inode)
will cause it to crash. Make lprocfs_obd_setup select either
debugfs or procfs but not both.
Handle the special symlinks needed for both debugfs
and sysfs with the server case. For lod we need to
create "lov" and osp we create "osc" for both sysfs
and debugfs. Handle the complex case of when a node
is both a server and client. For debugfs we can take
advantage of d_lookup() and for sysfs kset_find_obj()
to avoid special access to struct obd_type. This also
places the burden on the server lod/osp modules instead
of the client lov/osc modules.
Change-Id: I87090859db4da2300ab9e2aa3c23cb3773276103
Signed-off-by: James Simmons <uja.ornl@yahoo.com>
Reviewed-on: https://review.whamcloud.com/28108
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Dmitry Eremin <dmitry.eremin@intel.com>
Reviewed-by: Ben Evans <bevans@cray.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
]) # LC_OLDSIZE_TRUNCATE_PAGECACHE
#
+# LC_PTR_ERR_OR_ZERO
+#
+# For some reason SLES11SP4 is missing the PTR_ERR_OR_ZERO macro
+# It was added to linux kernel 3.12
+#
+AC_DEFUN([LC_PTR_ERR_OR_ZERO_MISSING], [
+LB_CHECK_COMPILE([if 'PTR_ERR_OR_ZERO' is missing],
+is_err_or_null, [
+ #include <linux/err.h>
+],[
+ if (PTR_ERR_OR_ZERO(NULL)) return 0;
+],[
+ AC_DEFINE(HAVE_PTR_ERR_OR_ZERO, 1,
+ ['PTR_ERR_OR_ZERO' exist])
+])
+]) # LC_PTR_ERR_OR_ZERO_MISSING
+
+#
# LC_HAVE_DENTRY_D_U_D_ALIAS
#
# 3.11 kernel moved d_alias to the union d_u in struct dentry
# 3.12
LC_OLDSIZE_TRUNCATE_PAGECACHE
+ LC_PTR_ERR_OR_ZERO_MISSING
LC_KIOCB_KI_LEFT
# 3.13
#ifdef HAVE_SERVER_SUPPORT
extern int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *peer_nid);
extern int lprocfs_exp_cleanup(struct obd_export *exp);
+struct dentry *ldebugfs_add_symlink(const char *name, const char *target,
+ const char *format, ...);
#else
static inline int lprocfs_exp_cleanup(struct obd_export *exp)
{ return 0; }
#endif
+struct dentry *ldebugfs_add_simple(struct dentry *root, char *name, void *data,
+ const struct file_operations *fops);
extern struct proc_dir_entry *
lprocfs_add_simple(struct proc_dir_entry *root, char *name,
void *data, const struct file_operations *fops);
{ return 0; }
#endif
-extern int lprocfs_obd_setup(struct obd_device *dev, bool uuid_only);
+extern int lprocfs_obd_setup(struct obd_device *obd, bool uuid_only);
extern int lprocfs_obd_cleanup(struct obd_device *obd);
#ifdef HAVE_SERVER_SUPPORT
extern const struct file_operations lprocfs_evict_client_fops;
#endif
-extern int ldebugfs_seq_create(struct dentry *parent, const char *name,
- umode_t mode,
- const struct file_operations *seq_fops,
- void *data);
+int ldebugfs_seq_create(struct dentry *parent, const char *name, umode_t mode,
+ const struct file_operations *seq_fops, void *data);
extern int lprocfs_seq_create(struct proc_dir_entry *parent, const char *name,
mode_t mode,
const struct file_operations *seq_fops,
extern int lprocfs_name_seq_show(struct seq_file *m, void *data);
extern int lprocfs_server_uuid_seq_show(struct seq_file *m, void *data);
extern int lprocfs_conn_uuid_seq_show(struct seq_file *m, void *data);
+ssize_t conn_uuid_show(struct kobject *kobj, struct attribute *attr, char *buf);
extern int lprocfs_import_seq_show(struct seq_file *m, void *data);
extern int lprocfs_state_seq_show(struct seq_file *m, void *data);
extern int lprocfs_connect_flags_seq_show(struct seq_file *m, void *data);
lprocfs_evict_client_seq_write(struct file *file, const char __user *buffer,
size_t count, loff_t *off);
#endif
+ssize_t ping_store(struct kobject *kobj, struct attribute *attr,
+ const char *buffer, size_t count);
extern ssize_t
lprocfs_ping_seq_write(struct file *file, const char __user *buffer,
size_t count, loff_t *off);
#define LPROCFS_CLIMP_EXIT(obd) \
up_read(&(obd)->u.cli.cl_sem);
+/* write the name##_seq_show function, call LDEBUGFS_SEQ_FOPS_RO for read-only
+ * debugfs entries; otherwise, you will define name##_seq_write function also
+ * for a read-write debugfs entry, and then call LDEBUGFS_SEQ_FOPS instead.
+ * Finally, call ldebugfs_seq_create(obd, filename, 0444, &name#_fops, data);
+ */
+#define __LDEBUGFS_SEQ_FOPS(name, custom_seq_write) \
+static int name##_single_open(struct inode *inode, struct file *file) \
+{ \
+ return single_open(file, name##_seq_show, inode->i_private); \
+} \
+static const struct file_operations name##_fops = { \
+ .owner = THIS_MODULE, \
+ .open = name##_single_open, \
+ .read = seq_read, \
+ .write = custom_seq_write, \
+ .llseek = seq_lseek, \
+ .release = single_release, \
+}
+
+#define LDEBUGFS_SEQ_FOPS_RO(name) __LDEBUGFS_SEQ_FOPS(name, NULL)
+#define LDEBUGFS_SEQ_FOPS(name) __LDEBUGFS_SEQ_FOPS(name, \
+ name##_seq_write)
+
+#define LDEBUGFS_SEQ_FOPS_RO_TYPE(name, type) \
+ static int name##_##type##_seq_show(struct seq_file *m, void *v)\
+ { \
+ return lprocfs_##type##_seq_show(m, m->private); \
+ } \
+ LDEBUGFS_SEQ_FOPS_RO(name##_##type)
+
+#define LDEBUGFS_SEQ_FOPS_RW_TYPE(name, type) \
+ static int name##_##type##_seq_show(struct seq_file *m, void *v)\
+ { \
+ return lprocfs_##type##_seq_show(m, m->private); \
+ } \
+ static ssize_t name##_##type##_seq_write(struct file *file, \
+ const char __user *buffer, size_t count, \
+ loff_t *off) \
+ { \
+ struct seq_file *seq = file->private_data; \
+ return ldebugfs_##type##_seq_write(file, buffer, count, \
+ seq->private); \
+ } \
+ LDEBUGFS_SEQ_FOPS(name##_##type);
+
+#define LDEBUGFS_FOPS_WR_ONLY(name, type) \
+ static ssize_t name##_##type##_write(struct file *file, \
+ const char __user *buffer, size_t count, \
+ loff_t *off) \
+ { \
+ return ldebugfs_##type##_seq_write(file, buffer, count, \
+ off); \
+ } \
+ static int name##_##type##_open(struct inode *inode, \
+ struct file *file) \
+ { \
+ return single_open(file, NULL, inode->i_private); \
+ } \
+ static const struct file_operations name##_##type##_fops = { \
+ .open = name##_##type##_open, \
+ .write = name##_##type##_write, \
+ .release = single_release, \
+ };
+
/* write the name##_seq_show function, call LPROC_SEQ_FOPS_RO for read-only
- proc entries; otherwise, you will define name##_seq_write function also for
- a read-write proc entry, and then call LPROC_SEQ_SEQ instead. Finally,
- call lprocfs_obd_seq_create(obd, filename, 0444, &name#_fops, data); */
+ * proc entries; otherwise, you will define name##_seq_write function also for
+ * a read-write proc entry, and then call LPROC_SEQ_FOPS instead. Finally,
+ * call ldebugfs_obd_seq_create(obd, filename, 0444, &name#_fops, data);
+ */
#define __LPROC_SEQ_FOPS(name, custom_seq_write) \
static int name##_single_open(struct inode *inode, struct file *file) \
{ \
}
#endif
+#ifndef HAVE_PTR_ERR_OR_ZERO
+static inline int __must_check PTR_ERR_OR_ZERO(__force const void *ptr)
+{
+ if (IS_ERR(ptr))
+ return PTR_ERR(ptr);
+ else
+ return 0;
+}
+#endif
+
#ifndef SIZE_MAX
#define SIZE_MAX (~(size_t)0)
#endif
struct md_ops *typ_md_ops;
struct proc_dir_entry *typ_procroot;
struct proc_dir_entry *typ_procsym;
- __u32 typ_sym_filter;
+ struct dentry *typ_debugfs_entry;
+#ifdef HAVE_SERVER_SUPPORT
+ bool typ_sym_filter;
+#endif
char *typ_name;
int typ_refcnt;
struct lu_device_type *typ_lu;
spinlock_t obd_type_lock;
- struct kobject typ_kobj;
- struct completion typ_kobj_unregister;
+ struct kobject *typ_kobj;
};
struct brw_page {
unsigned int obd_md_cntr_base;
struct lprocfs_stats *obd_md_stats;
+ struct dentry *obd_debugfs_entry;
struct proc_dir_entry *obd_proc_entry;
struct proc_dir_entry *obd_proc_exports_entry;
struct proc_dir_entry *obd_svc_procroot;
#ifndef __CLASS_OBD_H
#define __CLASS_OBD_H
-
+#include <linux/kobject.h>
#include <obd_support.h>
#include <lustre_import.h>
#include <lustre_net.h>
/* genops.c */
struct obd_export *class_conn2export(struct lustre_handle *);
+struct kobject *class_setup_tunables(const char *name);
int class_register_type(struct obd_ops *, struct md_ops *, bool enable_proc,
struct lprocfs_vars *module_vars,
const char *nm, struct lu_device_type *ldt);
.o_pool_del = lod_pool_del,
};
+static struct obd_type sym;
+
static int __init lod_init(void)
{
+ struct dentry *symlink;
struct obd_type *type;
+ struct kobject *kobj;
+ struct qstr dname;
int rc;
rc = lu_kmem_init(lod_caches);
return rc;
}
- /* create "lov" entry in procfs for compatibility purposes */
+ /* create "lov" entry for compatibility purposes */
+ dname.name = "lov";
+ dname.len = strlen(dname.name);
+ dname.hash = ll_full_name_hash(debugfs_lustre_root, dname.name,
+ dname.len);
+ symlink = d_lookup(debugfs_lustre_root, &dname);
+ if (!symlink) {
+ symlink = debugfs_create_dir(dname.name, debugfs_lustre_root);
+ if (IS_ERR_OR_NULL(symlink)) {
+ rc = symlink ? PTR_ERR(symlink) : -ENOMEM;
+ GOTO(no_lov, rc);
+ }
+ sym.typ_debugfs_entry = symlink;
+ } else {
+ dput(symlink);
+ }
+
+ kobj = kset_find_obj(lustre_kset, dname.name);
+ if (kobj) {
+ kobject_put(kobj);
+ goto try_proc;
+ }
+
+ kobj = class_setup_tunables(dname.name);
+ if (IS_ERR(kobj)) {
+ rc = PTR_ERR(kobj);
+ if (sym.typ_debugfs_entry)
+ ldebugfs_remove(&sym.typ_debugfs_entry);
+ GOTO(no_lov, rc);
+ }
+ sym.typ_kobj = kobj;
+
+try_proc:
type = class_search_type(LUSTRE_LOV_NAME);
if (type != NULL && type->typ_procroot != NULL)
- return rc;
+ GOTO(no_lov, rc);
type = class_search_type(LUSTRE_LOD_NAME);
type->typ_procsym = lprocfs_register("lov", proc_lustre_root,
(int)PTR_ERR(type->typ_procsym));
type->typ_procsym = NULL;
}
+no_lov:
return rc;
}
static void __exit lod_exit(void)
{
+ ldebugfs_remove(&sym.typ_debugfs_entry);
+ kobject_put(sym.typ_kobj);
class_unregister_type(LUSTRE_LOD_NAME);
lu_kmem_fini(lod_caches);
}
struct dt_device lod_dt_dev;
struct obd_export *lod_child_exp;
struct dt_device *lod_child;
- struct proc_dir_entry *lod_proc_entry;
struct lprocfs_stats *lod_stats;
spinlock_t lod_connects_lock;
int lod_connects;
enum lustre_sec_part lod_sp_me;
struct proc_dir_entry *lod_symlink;
+ struct dentry *lod_debugfs;
/* ROOT object, used to fetch FS default striping */
struct lod_object *lod_md_root;
*/
int lod_procfs_init(struct lod_device *lod)
{
- struct obd_device *obd = lod2obd(lod);
- struct proc_dir_entry *lov_proc_dir = NULL;
- struct obd_type *type;
- int rc;
+ struct obd_device *obd = lod2obd(lod);
+ struct proc_dir_entry *lov_proc_dir;
+ struct obd_type *type;
+ struct kobject *lov;
+ int rc;
obd->obd_vars = lprocfs_lod_obd_vars;
rc = lprocfs_obd_setup(obd, true);
GOTO(out, rc);
}
+ lov = kset_find_obj(lustre_kset, "lov");
+ if (lov) {
+ rc = sysfs_create_link(lov, &obd->obd_kset.kobj,
+ obd->obd_name);
+ kobject_put(lov);
+ }
+
+ lod->lod_debugfs = ldebugfs_add_symlink(obd->obd_name, "lov",
+ "../lod/%s", obd->obd_name);
+ if (!lod->lod_debugfs)
+ CERROR("%s: failed to create LOV debugfs symlink\n",
+ obd->obd_name);
+
/* If the real LOV is present which is the case for setups
* with both server and clients on the same node then use
* the LOV's proc root */
void lod_procfs_fini(struct lod_device *lod)
{
struct obd_device *obd = lod2obd(lod);
+ struct kobject *lov;
if (lod->lod_symlink != NULL) {
lprocfs_remove(&lod->lod_symlink);
lod->lod_symlink = NULL;
}
- if (lod->lod_pool_proc_entry != NULL) {
- lprocfs_remove(&lod->lod_pool_proc_entry);
- lod->lod_pool_proc_entry = NULL;
+ lov = kset_find_obj(lustre_kset, "lov");
+ if (lov) {
+ sysfs_remove_link(lov, obd->obd_name);
+ kobject_put(lov);
}
+ if (!IS_ERR_OR_NULL(lod->lod_debugfs))
+ ldebugfs_remove(&lod->lod_debugfs);
+
lprocfs_obd_cleanup(obd);
}
void dump_lsm(unsigned int level, const struct lov_stripe_md *lsm);
/* lproc_lov.c */
-extern struct file_operations lov_proc_target_fops;
+extern const struct file_operations lov_proc_target_fops;
#ifdef CONFIG_PROC_FS
extern struct lprocfs_vars lprocfs_lov_obd_vars[];
#endif
if (rc)
GOTO(out, rc);
-#ifdef CONFIG_PROC_FS
obd->obd_vars = lprocfs_lov_obd_vars;
+#ifdef CONFIG_PROC_FS
/* If this is true then both client (lov) and server
* (lod) are on the same node. The lod layer if loaded
* first will register the lov proc directory. In that
obd->obd_proc_entry = NULL;
}
}
+#endif
rc = lprocfs_obd_setup(obd, false);
- if (!rc) {
- rc = lprocfs_seq_create(obd->obd_proc_entry, "target_obd",
- 0444, &lov_proc_target_fops, obd);
- if (rc)
- CWARN("Error adding the target_obd file\n");
-
- lov->lov_pool_proc_entry = lprocfs_register("pools",
- obd->obd_proc_entry,
- NULL, NULL);
- if (IS_ERR(lov->lov_pool_proc_entry)) {
- rc = PTR_ERR(lov->lov_pool_proc_entry);
- CERROR("error %d setting up lprocfs for pools\n", rc);
- lov->lov_pool_proc_entry = NULL;
- }
- }
-#endif
- RETURN(0);
+ if (rc)
+ GOTO(out, rc);
+ rc = lprocfs_seq_create(obd->obd_proc_entry, "target_obd", 0444,
+ &lov_proc_target_fops, obd);
+ if (rc)
+ CWARN("%s: Error adding the target_obd file : rc %d\n",
+ obd->obd_name, rc);
+
+ lov->lov_pool_proc_entry = lprocfs_register("pools",
+ obd->obd_proc_entry,
+ NULL, NULL);
+ if (IS_ERR(lov->lov_pool_proc_entry)) {
+ rc = PTR_ERR(lov->lov_pool_proc_entry);
+ CERROR("%s: error setting up ldebugfs for pools : rc %d\n",
+ obd->obd_name, rc);
+ lov->lov_pool_proc_entry = NULL;
+ }
out:
return rc;
}
{ NULL }
};
-struct file_operations lov_proc_target_fops = {
+const struct file_operations lov_proc_target_fops = {
.owner = THIS_MODULE,
.open = lov_target_seq_open,
.read = seq_read,
if (rc != 0)
GOTO(out, rc);
- rc = lprocfs_obd_seq_create(obd, "filesystems", 0444,
- &mgs_fs_fops, obd);
+ rc = ldebugfs_seq_create(obd->obd_debugfs_entry, "filesystems", 0444,
+ &mgs_fs_fops, obd);
if (rc != 0)
GOTO(out, rc);
- rc = lprocfs_obd_seq_create(obd, "srpc_rules", 0400,
- &mgsself_srpc_fops, obd);
+ rc = ldebugfs_seq_create(obd->obd_debugfs_entry, "srpc_rules", 0400,
+ &mgsself_srpc_fops, obd);
if (rc != 0)
GOTO(out, rc);
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);
static int __init llog_test_init(void)
{
- return class_register_type(&llog_obd_ops, NULL, true, NULL,
+ return class_register_type(&llog_obd_ops, NULL, false, NULL,
"llog_test", NULL);
}
}
EXPORT_SYMBOL(lprocfs_seq_release);
+struct dentry *ldebugfs_add_simple(struct dentry *root,
+ char *name, void *data,
+ const struct file_operations *fops)
+{
+ struct dentry *entry;
+ umode_t mode = 0;
+
+ if (!root || !name || !fops)
+ return ERR_PTR(-EINVAL);
+
+ if (fops->read)
+ mode = 0444;
+ if (fops->write)
+ mode |= 0200;
+ entry = debugfs_create_file(name, mode, root, data, fops);
+ if (IS_ERR_OR_NULL(entry)) {
+ CERROR("LprocFS: No memory to create <debugfs> entry %s", name);
+ return entry ?: ERR_PTR(-ENOMEM);
+ }
+ return entry;
+}
+EXPORT_SYMBOL(ldebugfs_add_simple);
+
struct proc_dir_entry *
lprocfs_add_simple(struct proc_dir_entry *root, char *name,
void *data, const struct file_operations *fops)
}
LUSTRE_RO_ATTR(filesfree);
+ssize_t conn_uuid_show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+ struct obd_device *obd = container_of(kobj, struct obd_device,
+ obd_kset.kobj);
+ struct ptlrpc_connection *conn;
+ ssize_t count;
+
+ LPROCFS_CLIMP_CHECK(obd);
+ conn = obd->u.cli.cl_import->imp_connection;
+ if (conn && obd->u.cli.cl_import)
+ count = sprintf(buf, "%s\n", conn->c_remote_uuid.uuid);
+ else
+ count = sprintf(buf, "%s\n", "<none>");
+
+ LPROCFS_CLIMP_EXIT(obd);
+ return count;
+}
+EXPORT_SYMBOL(conn_uuid_show);
+
int lprocfs_server_uuid_seq_show(struct seq_file *m, void *data)
{
struct obd_device *obd = data;
int lprocfs_obd_setup(struct obd_device *obd, bool uuid_only)
{
+ struct lprocfs_vars *debugfs_vars = NULL;
int rc;
if (!obd || obd->obd_magic != OBD_DEVICE_MAGIC)
if (obd->obd_attrs)
obd->obd_ktype.default_attrs = obd->obd_attrs;
- obd->obd_kset.kobj.parent = &obd->obd_type->typ_kobj;
+ obd->obd_kset.kobj.parent = obd->obd_type->typ_kobj;
obd->obd_kset.kobj.ktype = &obd->obd_ktype;
init_completion(&obd->obd_kobj_unregister);
rc = kset_register(&obd->obd_kset);
return rc;
}
- if (obd->obd_proc_entry)
- GOTO(already_registered, rc);
+ if (!obd->obd_type->typ_procroot)
+ debugfs_vars = obd->obd_vars;
+ obd->obd_debugfs_entry = ldebugfs_register(obd->obd_name,
+ obd->obd_type->typ_debugfs_entry,
+ debugfs_vars, obd);
+ if (IS_ERR_OR_NULL(obd->obd_debugfs_entry)) {
+ rc = obd->obd_debugfs_entry ? PTR_ERR(obd->obd_debugfs_entry)
+ : -ENOMEM;
+ CERROR("error %d setting up debugfs for %s\n",
+ rc, obd->obd_name);
+ obd->obd_debugfs_entry = NULL;
+ lprocfs_obd_cleanup(obd);
+ return rc;
+ }
- LASSERT(obd->obd_type->typ_procroot != NULL);
+ if (obd->obd_proc_entry || !obd->obd_type->typ_procroot)
+ GOTO(already_registered, rc);
obd->obd_proc_entry = lprocfs_register(obd->obd_name,
obd->obd_type->typ_procroot,
obd->obd_proc_entry = NULL;
}
+ if (!IS_ERR_OR_NULL(obd->obd_debugfs_entry))
+ ldebugfs_remove(&obd->obd_debugfs_entry);
+
sysfs_remove_group(&obd->obd_kset.kobj, &obd->obd_attrs_group);
kset_unregister(&obd->obd_kset);
wait_for_completion(&obd->obd_kobj_unregister);
if (rc)
return rc;
seq = file->private_data;
- seq->private = inode->i_private ? : PDE_DATA(inode);
+ seq->private = inode->i_private ? inode->i_private : PDE_DATA(inode);
return 0;
}
#include <lprocfs_status.h>
#include <lustre_nodemap.h>
+#define MAX_STRING_SIZE 128
+
+struct dentry *ldebugfs_add_symlink(const char *name, const char *target,
+ const char *format, ...)
+{
+ struct dentry *entry = NULL;
+ struct dentry *parent;
+ struct qstr dname;
+ va_list ap;
+ char *dest;
+
+ if (!target || !format)
+ return NULL;
+
+ dname.name = target;
+ dname.len = strlen(dname.name);
+ dname.hash = ll_full_name_hash(parent, dname.name, dname.len);
+ parent = d_lookup(debugfs_lustre_root, &dname);
+ if (!parent)
+ return NULL;
+
+ OBD_ALLOC_WAIT(dest, MAX_STRING_SIZE + 1);
+ if (!dest)
+ goto no_entry;
+
+ va_start(ap, format);
+ vsnprintf(dest, MAX_STRING_SIZE, format, ap);
+ va_end(ap);
+
+ entry = debugfs_create_symlink(name, parent, dest);
+ if (IS_ERR_OR_NULL(entry)) {
+ CERROR("LdebugFS: Could not create symbolic link from %s to %s\n",
+ name, dest);
+ entry = NULL;
+ }
+
+ OBD_FREE(dest, MAX_STRING_SIZE + 1);
+no_entry:
+ dput(parent);
+ return entry;
+}
+EXPORT_SYMBOL(ldebugfs_add_symlink);
+
#ifdef CONFIG_PROC_FS
int lprocfs_evict_client_open(struct inode *inode, struct file *f)
if (rc != 0)
goto failed_0;
- rc = class_register_type(&echo_obd_ops, NULL, true, NULL,
+ rc = class_register_type(&echo_obd_ops, NULL, false, NULL,
LUSTRE_ECHO_NAME, NULL);
if (rc != 0)
goto failed_1;
rc = lu_kmem_init(echo_caches);
if (rc == 0) {
- rc = class_register_type(&echo_client_obd_ops, NULL, true, NULL,
- LUSTRE_ECHO_CLIENT_NAME,
+ rc = class_register_type(&echo_client_obd_ops, NULL, false,
+ NULL, LUSTRE_ECHO_CLIENT_NAME,
&echo_device_type);
if (rc)
lu_kmem_fini(echo_caches);
{ NULL }
};
+void osp_lprocfs_fini(struct osp_device *osp)
+{
+ struct obd_device *obd = osp->opd_obd;
+ struct kobject *osc;
+
+ osc = kset_find_obj(lustre_kset, "osc");
+ if (osc) {
+ sysfs_remove_link(osc, obd->obd_name);
+ kobject_put(osc);
+ }
+
+ if (!IS_ERR_OR_NULL(osp->opd_debugfs))
+ ldebugfs_remove(&osp->opd_debugfs);
+
+ ptlrpc_lprocfs_unregister_obd(obd);
+ if (osp->opd_symlink)
+ lprocfs_remove(&osp->opd_symlink);
+}
+
/**
* Initialize OSP lprocfs
*
*/
void osp_lprocfs_init(struct osp_device *osp)
{
- struct obd_device *obd = osp->opd_obd;
- struct proc_dir_entry *osc_proc_dir = NULL;
- struct obd_type *type;
- int rc;
+ struct obd_device *obd = osp->opd_obd;
+ struct proc_dir_entry *osc_proc_dir = NULL;
+ struct obd_type *type;
+ struct kobject *osc;
+ int rc;
if (osp->opd_connect_mdt)
obd->obd_vars = lprocfs_osp_md_vars;
/* If the real OSC is present which is the case for setups
* with both server and clients on the same node then use
+ * the OSC's proc root
+ */
+ osc = kset_find_obj(lustre_kset, "osc");
+ if (osc) {
+ rc = sysfs_create_link(osc, &obd->obd_kset.kobj,
+ obd->obd_name);
+ kobject_put(osc);
+ }
+
+ osp->opd_debugfs = ldebugfs_add_symlink(obd->obd_name, "osc",
+ "../osp/%s", obd->obd_name);
+ if (!osp->opd_debugfs)
+ CERROR("%s: failed to create OSC debugfs symlink\n",
+ obd->obd_name);
+
+ /* If the real OSC is present which is the case for setups
+ * with both server and clients on the same node then use
* the OSC's proc root */
type = class_search_type(LUSTRE_OSC_NAME);
if (type != NULL && type->typ_procroot != NULL)
out_fid:
obd_fid_fini(osp->opd_obd);
out_proc:
- ptlrpc_lprocfs_unregister_obd(obd);
- if (osp->opd_symlink)
- lprocfs_remove(&osp->opd_symlink);
+ osp_lprocfs_fini(osp);
client_obd_cleanup(obd);
out_ref:
ptlrpcd_decref();
obd_disconnect(osp->opd_storage_exp);
}
- if (osp->opd_symlink)
- lprocfs_remove(&osp->opd_symlink);
-
LASSERT(osp->opd_obd);
- ptlrpc_lprocfs_unregister_obd(osp->opd_obd);
+ osp_lprocfs_fini(osp);
if (osp->opd_connect_mdt) {
struct client_obd *cli = &osp->opd_obd->u.cli;
struct llog_operations osp_mds_ost_orig_logops;
+static struct obd_type sym;
+
/**
* Initialize OSP module.
*
*/
static int __init osp_init(void)
{
+ struct dentry *symlink;
struct obd_type *type;
+ struct kobject *kobj;
+ struct qstr dname;
int rc;
rc = lu_kmem_init(osp_caches);
if (rc)
return rc;
-
rc = class_register_type(&osp_obd_device_ops, NULL, true, NULL,
LUSTRE_OSP_NAME, &osp_device_type);
if (rc != 0) {
osp_mds_ost_orig_logops.lop_add = llog_cat_add_rec;
osp_mds_ost_orig_logops.lop_declare_add = llog_cat_declare_add_rec;
- /* create "osc" entry in procfs for compatibility purposes */
+ /* create "osc" entry for compatibility purposes */
+ dname.name = "osc";
+ dname.len = strlen(dname.name);
+ dname.hash = ll_full_name_hash(debugfs_lustre_root, dname.name,
+ dname.len);
+ symlink = d_lookup(debugfs_lustre_root, &dname);
+ if (!symlink) {
+ symlink = debugfs_create_dir(dname.name, debugfs_lustre_root);
+ if (IS_ERR_OR_NULL(symlink)) {
+ rc = symlink ? PTR_ERR(symlink) : -ENOMEM;
+ GOTO(no_osc, rc);
+ }
+ sym.typ_debugfs_entry = symlink;
+ } else {
+ dput(symlink);
+ }
+
+ kobj = kset_find_obj(lustre_kset, dname.name);
+ if (kobj) {
+ kobject_put(kobj);
+ goto try_proc;
+ }
+
+ kobj = class_setup_tunables(dname.name);
+ if (IS_ERR(kobj)) {
+ rc = PTR_ERR(kobj);
+ if (sym.typ_debugfs_entry)
+ ldebugfs_remove(&sym.typ_debugfs_entry);
+ GOTO(no_osc, rc);
+ }
+ sym.typ_kobj = kobj;
+
+try_proc:
type = class_search_type(LUSTRE_OSC_NAME);
if (type != NULL && type->typ_procroot != NULL)
- return rc;
+ GOTO(no_osc, rc);
type = class_search_type(LUSTRE_OSP_NAME);
type->typ_procsym = lprocfs_register("osc", proc_lustre_root,
(int) PTR_ERR(type->typ_procsym));
type->typ_procsym = NULL;
}
+no_osc:
return rc;
}
*/
static void __exit osp_exit(void)
{
+ ldebugfs_remove(&sym.typ_debugfs_entry);
+ kobject_put(sym.typ_kobj);
class_unregister_type(LUSTRE_LWP_NAME);
class_unregister_type(LUSTRE_OSP_NAME);
lu_kmem_fini(osp_caches);
time64_t opd_statfs_maxage;
struct proc_dir_entry *opd_symlink;
+ struct dentry *opd_debugfs;
/* If the caller wants to do some idempotent async operations on
* remote server, it can append the async remote requests on the
/* lproc_osp.c */
void osp_lprocfs_init(struct osp_device *osp);
+void osp_lprocfs_fini(struct osp_device *osp);
/* osp_sync.c */
int osp_sync_declare_add(const struct lu_env *env, struct osp_object *o,
}
EXPORT_SYMBOL(ptlrpc_lprocfs_unregister_obd);
+ssize_t ping_store(struct kobject *kobj, struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct obd_device *obd = container_of(kobj, struct obd_device,
+ obd_kset.kobj);
+ struct ptlrpc_request *req;
+ int rc;
+
+ ENTRY;
+ LPROCFS_CLIMP_CHECK(obd);
+ req = ptlrpc_prep_ping(obd->u.cli.cl_import);
+ LPROCFS_CLIMP_EXIT(obd);
+ if (!req)
+ RETURN(-ENOMEM);
+
+ req->rq_send_state = LUSTRE_IMP_FULL;
+
+ rc = ptlrpc_queue_wait(req);
+ ptlrpc_req_finished(req);
+
+ RETURN(rc >= 0 ? count : rc);
+}
+EXPORT_SYMBOL(ping_store);
+
ssize_t
lprocfs_ping_seq_write(struct file *file, const char __user *buffer,
size_t count, loff_t *off)
out:
return 0;
}
+
LPROC_SEQ_FOPS_RO(sptlrpc_info_lprocfs);
static int sptlrpc_ctxs_lprocfs_seq_show(struct seq_file *seq, void *v)
out:
return 0;
}
+
LPROC_SEQ_FOPS_RO(sptlrpc_ctxs_lprocfs);
int sptlrpc_lprocfs_cliobd_attach(struct obd_device *dev)
return -EINVAL;
}
- rc = lprocfs_obd_seq_create(dev, "srpc_info", 0444,
- &sptlrpc_info_lprocfs_fops, dev);
+ rc = ldebugfs_seq_create(dev->obd_debugfs_entry, "srpc_info", 0444,
+ &sptlrpc_info_lprocfs_fops, dev);
if (rc) {
CERROR("create proc entry srpc_info for %s: %d\n",
dev->obd_name, rc);
return rc;
}
- rc = lprocfs_obd_seq_create(dev, "srpc_contexts", 0444,
- &sptlrpc_ctxs_lprocfs_fops, dev);
+ rc = ldebugfs_seq_create(dev->obd_debugfs_entry, "srpc_contexts",
+ 0444, &sptlrpc_ctxs_lprocfs_fops, dev);
if (rc) {
CERROR("create proc entry srpc_contexts for %s: %d\n",
dev->obd_name, rc);