Whamcloud - gitweb
LU-8066 obd: final pieces for sysfs/debugfs support. 08/28108/24
authorJames Simmons <uja.ornl@yahoo.com>
Thu, 22 Feb 2018 17:26:16 +0000 (12:26 -0500)
committerOleg Drokin <oleg.drokin@intel.com>
Tue, 6 Mar 2018 23:58:39 +0000 (23:58 +0000)
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>
22 files changed:
lustre/autoconf/lustre-core.m4
lustre/include/lprocfs_status.h
lustre/include/lustre_compat.h
lustre/include/obd.h
lustre/include/obd_class.h
lustre/lod/lod_dev.c
lustre/lod/lod_internal.h
lustre/lod/lproc_lod.c
lustre/lov/lov_internal.h
lustre/lov/lov_obd.c
lustre/lov/lproc_lov.c
lustre/mgs/lproc_mgs.c
lustre/obdclass/genops.c
lustre/obdclass/llog_test.c
lustre/obdclass/lprocfs_status.c
lustre/obdclass/lprocfs_status_server.c
lustre/obdecho/echo_client.c
lustre/osp/lproc_osp.c
lustre/osp/osp_dev.c
lustre/osp/osp_internal.h
lustre/ptlrpc/lproc_ptlrpc.c
lustre/ptlrpc/sec_lproc.c

index cfe5efb..3539bf9 100644 (file)
@@ -1593,6 +1593,24 @@ truncate_pagecache_old_size, [
 ]) # 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
@@ -2836,6 +2854,7 @@ AC_DEFUN([LC_PROG_LINUX], [
 
        # 3.12
        LC_OLDSIZE_TRUNCATE_PAGECACHE
+       LC_PTR_ERR_OR_ZERO_MISSING
        LC_KIOCB_KI_LEFT
 
        # 3.13
index 87e8e5a..863afd9 100644 (file)
@@ -490,10 +490,14 @@ extern int lprocfs_add_clear_entry(struct obd_device * obd,
 #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);
@@ -553,16 +557,14 @@ static inline int LPROCFS_ENTRY_CHECK(struct inode *inode)
 { 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,
@@ -577,6 +579,7 @@ extern int lprocfs_uuid_seq_show(struct seq_file *m, void *data);
 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);
@@ -595,6 +598,8 @@ extern ssize_t
 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);
@@ -658,10 +663,75 @@ extern int lprocfs_seq_release(struct inode *, struct file *);
 #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)  \
 {                                                                      \
index 4a3a0cf..37cca5a 100644 (file)
@@ -392,6 +392,16 @@ static inline void truncate_inode_pages_final(struct address_space *map)
 }
 #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
index 42fba9a..1644a1e 100644 (file)
@@ -102,13 +102,15 @@ struct obd_type {
        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 {
@@ -704,6 +706,7 @@ struct obd_device {
        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;
index 9eb9ceb..25bf2d6 100644 (file)
@@ -32,7 +32,7 @@
 #ifndef __CLASS_OBD_H
 #define __CLASS_OBD_H
 
-
+#include <linux/kobject.h>
 #include <obd_support.h>
 #include <lustre_import.h>
 #include <lustre_net.h>
@@ -63,6 +63,7 @@ struct lu_device_type;
 
 /* 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);
index 0c2ddcb..eb7192c 100644 (file)
@@ -2057,9 +2057,14 @@ static struct obd_ops lod_obd_device_ops = {
        .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);
@@ -2073,10 +2078,42 @@ static int __init lod_init(void)
                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,
@@ -2086,11 +2123,14 @@ static int __init lod_init(void)
                       (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);
 }
index 022f7a9..f6bee8a 100644 (file)
@@ -167,7 +167,6 @@ struct lod_device {
        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;
@@ -211,6 +210,7 @@ struct lod_device {
        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;
index 429b9fe..b7621f1 100644 (file)
@@ -847,10 +847,11 @@ static const struct file_operations lod_proc_target_fops = {
  */
 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);
@@ -887,6 +888,19 @@ int lod_procfs_init(struct lod_device *lod)
                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 */
@@ -921,17 +935,22 @@ out:
 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);
 }
 
index a609e90..bba4a8d 100644 (file)
@@ -305,7 +305,7 @@ void lsm_free_plain(struct lov_stripe_md *lsm);
 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
index 88844e8..c5ac570 100644 (file)
@@ -793,8 +793,8 @@ int lov_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
         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
@@ -813,26 +813,27 @@ int lov_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
                        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;
 }
index f8e6d54..a8d9b69 100644 (file)
@@ -296,7 +296,7 @@ struct lprocfs_vars lprocfs_lov_obd_vars[] = {
        { 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,
index 0592675..4a95b02 100644 (file)
@@ -231,13 +231,13 @@ int lproc_mgs_setup(struct mgs_device *mgs, const char *osd_name)
        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);
 
index cd006e7..9ea1d91 100644 (file)
@@ -165,10 +165,7 @@ void class_put_type(struct obd_type *type)
 
 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 = {
@@ -176,18 +173,46 @@ 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);
@@ -227,18 +252,40 @@ int class_register_type(struct obd_ops *dt_ops, struct md_ops *md_ops,
                }
        }
 #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);
                }
        }
@@ -250,6 +297,12 @@ int class_register_type(struct obd_ops *dt_ops, struct md_ops *md_ops,
        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)
@@ -285,8 +338,7 @@ int class_unregister_type(const char *name)
                 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
@@ -298,6 +350,13 @@ int class_unregister_type(const char *name)
        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);
 
index 109f087..f9a0eb3 100644 (file)
@@ -2133,7 +2133,7 @@ static struct obd_ops llog_obd_ops = {
 
 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);
 }
 
index 3e9eed2..5d985fd 100644 (file)
@@ -59,6 +59,29 @@ int lprocfs_seq_release(struct inode *inode, struct file *file)
 }
 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)
@@ -505,6 +528,25 @@ static ssize_t filesfree_show(struct kobject *kobj, struct attribute *attr,
 }
 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;
@@ -1163,6 +1205,7 @@ static void obd_sysfs_release(struct kobject *kobj)
 
 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)
@@ -1177,7 +1220,7 @@ int lprocfs_obd_setup(struct obd_device *obd, bool uuid_only)
        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);
@@ -1195,10 +1238,23 @@ int lprocfs_obd_setup(struct obd_device *obd, bool uuid_only)
                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,
@@ -1230,6 +1286,9 @@ int lprocfs_obd_cleanup(struct obd_device *obd)
                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);
@@ -1498,7 +1557,7 @@ static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
        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;
 }
 
index 0e07dd6..bbd81a9 100644 (file)
 #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)
index 081a339..6e25a02 100644 (file)
@@ -3071,7 +3071,7 @@ static int __init obdecho_init(void)
         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;
@@ -3079,8 +3079,8 @@ static int __init obdecho_init(void)
 
        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);
index f320818..03a03db 100644 (file)
@@ -1009,6 +1009,25 @@ static struct lprocfs_vars lprocfs_osp_osd_vars[] = {
        { 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
  *
@@ -1016,10 +1035,11 @@ static struct lprocfs_vars lprocfs_osp_osd_vars[] = {
  */
 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;
@@ -1044,6 +1064,23 @@ void osp_lprocfs_init(struct osp_device *osp)
 
        /* 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)
index daac499..21dd9e7 100644 (file)
@@ -1232,9 +1232,7 @@ out_last_used:
 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();
@@ -1348,11 +1346,8 @@ static struct lu_device *osp_device_fini(const struct lu_env *env,
                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;
@@ -1914,6 +1909,8 @@ static struct obd_ops osp_obd_device_ops = {
 
 struct llog_operations osp_mds_ost_orig_logops;
 
+static struct obd_type sym;
+
 /**
  * Initialize OSP module.
  *
@@ -1928,14 +1925,16 @@ struct llog_operations osp_mds_ost_orig_logops;
  */
 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) {
@@ -1956,10 +1955,42 @@ static int __init osp_init(void)
        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,
@@ -1969,6 +2000,7 @@ static int __init osp_init(void)
                       (int) PTR_ERR(type->typ_procsym));
                type->typ_procsym = NULL;
        }
+no_osc:
        return rc;
 }
 
@@ -1980,6 +2012,8 @@ static int __init osp_init(void)
  */
 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);
index b18f5da..a842528 100644 (file)
@@ -250,6 +250,7 @@ struct osp_device {
        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
@@ -805,6 +806,7 @@ int osp_init_pre_fid(struct osp_device *osp);
 
 /* 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,
index 4418f86..ee4e78e 100644 (file)
@@ -1296,6 +1296,30 @@ void ptlrpc_lprocfs_unregister_obd(struct obd_device *obd)
 }
 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)
index 96acb18..04ffd16 100644 (file)
@@ -110,6 +110,7 @@ static int sptlrpc_info_lprocfs_seq_show(struct seq_file *seq, void *v)
 out:
         return 0;
 }
+
 LPROC_SEQ_FOPS_RO(sptlrpc_info_lprocfs);
 
 static int sptlrpc_ctxs_lprocfs_seq_show(struct seq_file *seq, void *v)
@@ -136,6 +137,7 @@ 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)
@@ -152,16 +154,16 @@ 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);