Whamcloud - gitweb
LU-5275 lprocfs: reduce scope of params_tree.h
[fs/lustre-release.git] / lustre / obdclass / lprocfs_status.c
index c52e301..259b79c 100644 (file)
@@ -27,7 +27,7 @@
  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
- * Copyright (c) 2011, 2013, Intel Corporation.
+ * Copyright (c) 2011, 2014, Intel Corporation.
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
@@ -117,7 +117,213 @@ struct proc_dir_entry *lprocfs_add_symlink(const char *name,
 }
 EXPORT_SYMBOL(lprocfs_add_symlink);
 
+#ifdef HAVE_ONLY_PROCFS_SEQ
 static const struct file_operations lprocfs_generic_fops = { };
+#else
+
+ssize_t
+lprocfs_fops_read(struct file *f, char __user *buf, size_t size, loff_t *ppos)
+{
+       struct inode *inode = f->f_dentry->d_inode;
+       struct proc_dir_entry *dp = PDE(inode);
+       char *page, *start = NULL;
+       int rc, eof = 1, count;
+
+       if (*ppos >= PAGE_CACHE_SIZE)
+               return 0;
+
+       page = (char *)__get_free_page(GFP_KERNEL);
+       if (page == NULL)
+               return -ENOMEM;
+
+       rc = LPROCFS_ENTRY_CHECK(inode);
+       if (rc < 0)
+               goto out;
+
+       OBD_FAIL_TIMEOUT(OBD_FAIL_LPROC_REMOVE, 10);
+       if (dp->read_proc != NULL)
+               rc = dp->read_proc(page, &start, *ppos, PAGE_CACHE_SIZE,
+                                  &eof, dp->data);
+       else
+               rc = 0;
+
+        if (rc <= 0)
+                goto out;
+
+        /* for lustre proc read, the read count must be less than PAGE_SIZE */
+        LASSERT(eof == 1);
+
+        if (start == NULL) {
+                rc -= *ppos;
+                if (rc < 0)
+                        rc = 0;
+                if (rc == 0)
+                        goto out;
+                start = page + *ppos;
+        } else if (start < page) {
+                start = page;
+        }
+
+        count = (rc < size) ? rc : size;
+       if (copy_to_user(buf, start, count)) {
+                rc = -EFAULT;
+                goto out;
+        }
+        *ppos += count;
+
+out:
+        free_page((unsigned long)page);
+        return rc;
+}
+
+ssize_t
+lprocfs_fops_write(struct file *f, const char __user *buf, size_t size,
+                  loff_t *ppos)
+{
+       struct inode *inode = f->f_dentry->d_inode;
+       struct proc_dir_entry *dp = PDE(inode);
+       int rc;
+
+       rc = LPROCFS_ENTRY_CHECK(inode);
+       if (rc < 0)
+               return rc;
+
+       if (dp->write_proc != NULL)
+               rc = dp->write_proc(f, buf, size, dp->data);
+       else
+               rc = -EIO;
+
+       return rc;
+}
+
+static struct file_operations lprocfs_generic_fops = {
+        .owner = THIS_MODULE,
+        .read = lprocfs_fops_read,
+        .write = lprocfs_fops_write,
+};
+
+/* for b=10866, global variable */
+DECLARE_RWSEM(_lprocfs_lock);
+EXPORT_SYMBOL(_lprocfs_lock);
+
+static struct proc_dir_entry *__lprocfs_srch(struct proc_dir_entry *head,
+                                            const char *name)
+{
+       struct proc_dir_entry *temp;
+
+       if (head == NULL)
+               return NULL;
+
+       temp = head->subdir;
+       while (temp != NULL) {
+               if (strcmp(temp->name, name) == 0)
+                       return temp;
+               temp = temp->next;
+       }
+       return NULL;
+}
+
+struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
+                                   const char *name)
+{
+       struct proc_dir_entry *temp;
+
+       LPROCFS_SRCH_ENTRY();
+       temp = __lprocfs_srch(head, name);
+       LPROCFS_SRCH_EXIT();
+       return temp;
+}
+EXPORT_SYMBOL(lprocfs_srch);
+
+static int __lprocfs_add_vars(struct proc_dir_entry *root,
+                             struct lprocfs_vars *list,
+                             void *data)
+{
+        int rc = 0;
+
+        if (root == NULL || list == NULL)
+                return -EINVAL;
+
+        while (list->name != NULL) {
+                struct proc_dir_entry *cur_root, *proc;
+                char *pathcopy, *cur, *next, pathbuf[64];
+                int pathsize = strlen(list->name) + 1;
+
+                proc = NULL;
+                cur_root = root;
+
+                /* need copy of path for strsep */
+                if (strlen(list->name) > sizeof(pathbuf) - 1) {
+                        OBD_ALLOC(pathcopy, pathsize);
+                        if (pathcopy == NULL)
+                                GOTO(out, rc = -ENOMEM);
+                } else {
+                        pathcopy = pathbuf;
+                }
+
+                next = pathcopy;
+                strcpy(pathcopy, list->name);
+
+                while (cur_root != NULL && (cur = strsep(&next, "/"))) {
+                        if (*cur =='\0') /* skip double/trailing "/" */
+                                continue;
+
+                        proc = __lprocfs_srch(cur_root, cur);
+                        CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
+                               cur_root->name, cur, next,
+                               (proc ? "exists" : "new"));
+                        if (next != NULL) {
+                                cur_root = (proc ? proc :
+                                            proc_mkdir(cur, cur_root));
+                        } else if (proc == NULL) {
+                                mode_t mode = 0;
+                                if (list->proc_mode != 0000) {
+                                        mode = list->proc_mode;
+                                } else {
+                                        if (list->read_fptr)
+                                                mode = 0444;
+                                        if (list->write_fptr)
+                                                mode |= 0200;
+                                }
+                                proc = create_proc_entry(cur, mode, cur_root);
+                        }
+                }
+
+                if (pathcopy != pathbuf)
+                        OBD_FREE(pathcopy, pathsize);
+
+                if (cur_root == NULL || proc == NULL) {
+                       CERROR("LprocFS: No memory to create /proc entry %s\n",
+                              list->name);
+                       GOTO(out, rc = -ENOMEM);
+                }
+
+                if (list->fops)
+                        proc->proc_fops = list->fops;
+                else
+                        proc->proc_fops = &lprocfs_generic_fops;
+                proc->read_proc = list->read_fptr;
+                proc->write_proc = list->write_fptr;
+                proc->data = (list->data ? list->data : data);
+                list++;
+        }
+out:
+        return rc;
+}
+
+int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
+                    void *data)
+{
+       int rc = 0;
+
+       LPROCFS_WRITE_ENTRY();
+       rc = __lprocfs_add_vars(root, list, data);
+       LPROCFS_WRITE_EXIT();
+
+       return rc;
+}
+EXPORT_SYMBOL(lprocfs_add_vars);
+#endif
 
 /**
  * Add /proc entries.
@@ -131,8 +337,8 @@ static const struct file_operations lprocfs_generic_fops = { };
  *         < 0 on error
  */
 int
-lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
-                void *data)
+lprocfs_seq_add_vars(struct proc_dir_entry *root, struct lprocfs_seq_vars *list,
+                    void *data)
 {
        if (root == NULL || list == NULL)
                return -EINVAL;
@@ -158,14 +364,10 @@ lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
        }
        return 0;
 }
-EXPORT_SYMBOL(lprocfs_add_vars);
+EXPORT_SYMBOL(lprocfs_seq_add_vars);
 
 #ifndef HAVE_ONLY_PROCFS_SEQ
-/* for b=10866, global variable */
-DECLARE_RWSEM(_lprocfs_lock);
-EXPORT_SYMBOL(_lprocfs_lock);
-
-void lprocfs_remove_nolock(struct proc_dir_entry **proot)
+static void lprocfs_remove_nolock(struct proc_dir_entry **proot)
 {
        struct proc_dir_entry *root = *proot;
        struct proc_dir_entry *temp = root;
@@ -197,8 +399,31 @@ void lprocfs_remove_nolock(struct proc_dir_entry **proot)
                         break;
         }
 }
+#endif
 
-void remove_proc_subtree(const char *name, struct proc_dir_entry *parent)
+void lprocfs_remove(struct proc_dir_entry **rooth)
+{
+#ifndef HAVE_ONLY_PROCFS_SEQ
+       LPROCFS_WRITE_ENTRY(); /* search vs remove race */
+       lprocfs_remove_nolock(rooth);
+       LPROCFS_WRITE_EXIT();
+#else
+       proc_remove(*rooth);
+       *rooth = NULL;
+#endif
+}
+EXPORT_SYMBOL(lprocfs_remove);
+
+void lprocfs_remove_proc_entry(const char *name, struct proc_dir_entry *parent)
+{
+        LASSERT(parent != NULL);
+        remove_proc_entry(name, parent);
+}
+EXPORT_SYMBOL(lprocfs_remove_proc_entry);
+
+#ifndef HAVE_ONLY_PROCFS_SEQ
+void lprocfs_try_remove_proc_entry(const char *name,
+                                  struct proc_dir_entry *parent)
 {
        struct proc_dir_entry    *t = NULL;
        struct proc_dir_entry   **p;
@@ -241,32 +466,43 @@ void remove_proc_subtree(const char *name, struct proc_dir_entry *parent)
 
        return;
 }
-EXPORT_SYMBOL(remove_proc_subtree);
-#endif
+EXPORT_SYMBOL(lprocfs_try_remove_proc_entry);
 
-void lprocfs_remove(struct proc_dir_entry **rooth)
+struct proc_dir_entry *lprocfs_register(const char *name,
+                                       struct proc_dir_entry *parent,
+                                       struct lprocfs_vars *list, void *data)
 {
-#ifndef HAVE_ONLY_PROCFS_SEQ
-       LPROCFS_WRITE_ENTRY(); /* search vs remove race */
-       lprocfs_remove_nolock(rooth);
-       LPROCFS_WRITE_EXIT();
-#else
-       proc_remove(*rooth);
-       *rooth = NULL;
-#endif
-}
-EXPORT_SYMBOL(lprocfs_remove);
+       struct proc_dir_entry *entry;
+       int rc;
 
-void lprocfs_remove_proc_entry(const char *name, struct proc_dir_entry *parent)
-{
-       LASSERT(parent != NULL);
-       remove_proc_entry(name, parent);
+       LPROCFS_WRITE_ENTRY();
+       entry = __lprocfs_srch(parent, name);
+       if (entry != NULL) {
+               CERROR("entry '%s' already registered\n", name);
+               GOTO(out, entry = ERR_PTR(-EALREADY));
+       }
+
+       entry = proc_mkdir(name, parent);
+       if (entry == NULL)
+               GOTO(out, entry = ERR_PTR(-ENOMEM));
+
+       if (list != NULL) {
+               rc = __lprocfs_add_vars(entry, list, data);
+               if (rc != 0) {
+                       lprocfs_remove_nolock(&entry);
+                       GOTO(out, entry = ERR_PTR(rc));
+               }
+       }
+out:
+       LPROCFS_WRITE_EXIT();
+       return entry;
 }
-EXPORT_SYMBOL(lprocfs_remove_proc_entry);
+EXPORT_SYMBOL(lprocfs_register);
+#endif
 
 struct proc_dir_entry *
-lprocfs_register(const char *name, struct proc_dir_entry *parent,
-                struct lprocfs_vars *list, void *data)
+lprocfs_seq_register(const char *name, struct proc_dir_entry *parent,
+                    struct lprocfs_seq_vars *list, void *data)
 {
        struct proc_dir_entry *newchild;
 
@@ -275,7 +511,7 @@ lprocfs_register(const char *name, struct proc_dir_entry *parent,
                return ERR_PTR(-ENOMEM);
 
        if (list != NULL) {
-               int rc = lprocfs_add_vars(newchild, list, data);
+               int rc = lprocfs_seq_add_vars(newchild, list, data);
                if (rc) {
                        lprocfs_remove(&newchild);
                        return ERR_PTR(rc);
@@ -283,7 +519,7 @@ lprocfs_register(const char *name, struct proc_dir_entry *parent,
        }
        return newchild;
 }
-EXPORT_SYMBOL(lprocfs_register);
+EXPORT_SYMBOL(lprocfs_seq_register);
 
 /* Generic callbacks */
 int lprocfs_uint_seq_show(struct seq_file *m, void *data)
@@ -904,7 +1140,7 @@ int lprocfs_state_seq_show(struct seq_file *m, void *data)
 }
 EXPORT_SYMBOL(lprocfs_state_seq_show);
 
-int lprocfs_at_hist_helper(struct seq_file *m, struct adaptive_timeout *at)
+int lprocfs_seq_at_hist_helper(struct seq_file *m, struct adaptive_timeout *at)
 {
        int i;
        for (i = 0; i < AT_BINS; i++)
@@ -912,7 +1148,7 @@ int lprocfs_at_hist_helper(struct seq_file *m, struct adaptive_timeout *at)
        seq_printf(m, "\n");
        return 0;
 }
-EXPORT_SYMBOL(lprocfs_at_hist_helper);
+EXPORT_SYMBOL(lprocfs_seq_at_hist_helper);
 
 /* See also ptlrpc_lprocfs_timeouts_show_seq */
 int lprocfs_timeouts_seq_show(struct seq_file *m, void *data)
@@ -941,7 +1177,7 @@ int lprocfs_timeouts_seq_show(struct seq_file *m, void *data)
        s2dhms(&ts, now - worstt);
        seq_printf(m, "%-10s : cur %3u  worst %3u (at %ld, "DHMS_FMT" ago) ",
                   "network", cur, worst, worstt, DHMS_VARS(&ts));
-       lprocfs_at_hist_helper(m, &imp->imp_at.iat_net_latency);
+       lprocfs_seq_at_hist_helper(m, &imp->imp_at.iat_net_latency);
 
        for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
                if (imp->imp_at.iat_portal[i] == 0)
@@ -953,7 +1189,7 @@ int lprocfs_timeouts_seq_show(struct seq_file *m, void *data)
                seq_printf(m, "portal %-2d  : cur %3u  worst %3u (at %ld, "
                           DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
                           cur, worst, worstt, DHMS_VARS(&ts));
-               lprocfs_at_hist_helper(m, &imp->imp_at.iat_service_estimate[i]);
+               lprocfs_seq_at_hist_helper(m, &imp->imp_at.iat_service_estimate[i]);
        }
 
        LPROCFS_CLIMP_EXIT(obd);
@@ -985,9 +1221,9 @@ lprocfs_obd_setup(struct obd_device *obd)
        LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
        LASSERT(obd->obd_type->typ_procroot != NULL);
 
-       obd->obd_proc_entry = lprocfs_register(obd->obd_name,
-                                              obd->obd_type->typ_procroot,
-                                              obd->obd_vars, obd);
+       obd->obd_proc_entry = lprocfs_seq_register(obd->obd_name,
+                                                  obd->obd_type->typ_procroot,
+                                                  obd->obd_vars, obd);
        if (IS_ERR(obd->obd_proc_entry)) {
                rc = PTR_ERR(obd->obd_proc_entry);
                CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
@@ -1239,7 +1475,7 @@ out:
        return (rc < 0) ? rc : 0;
 }
 
-struct seq_operations lprocfs_stats_seq_sops = {
+static const struct seq_operations lprocfs_stats_seq_sops = {
        .start  = lprocfs_stats_seq_start,
        .stop   = lprocfs_stats_seq_stop,
        .next   = lprocfs_stats_seq_next,
@@ -1251,10 +1487,10 @@ static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
        struct seq_file *seq;
        int rc;
 
-#ifndef HAVE_ONLY_PROCFS_SEQ
-       if (LPROCFS_ENTRY_CHECK(PDE(inode)))
-               return -ENOENT;
-#endif
+       rc = LPROCFS_ENTRY_CHECK(inode);
+       if (rc < 0)
+               return rc;
+
        rc = seq_open(file, &lprocfs_stats_seq_sops);
        if (rc)
                return rc;
@@ -1263,7 +1499,7 @@ static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
        return 0;
 }
 
-struct file_operations lprocfs_stats_seq_fops = {
+static const struct file_operations lprocfs_stats_seq_fops = {
         .owner   = THIS_MODULE,
         .open    = lprocfs_stats_seq_open,
         .read    = seq_read,