Whamcloud - gitweb
LU-473 llite: improve error for 2.x cli + 1.8 srv
[fs/lustre-release.git] / lustre / obdclass / lprocfs_status.c
index 1ed1903..eed7097 100644 (file)
@@ -30,6 +30,9 @@
  * Use is subject to license terms.
  */
 /*
+ * Copyright (c) 2011 Whamcloud, Inc.
+ */
+/*
  * This file is part of Lustre, http://www.lustre.org/
  * Lustre is a trademark of Sun Microsystems, Inc.
  *
@@ -68,28 +71,36 @@ int lprocfs_seq_release(struct inode *inode, struct file *file)
 }
 EXPORT_SYMBOL(lprocfs_seq_release);
 
-struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
-                                    const char *name)
+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;
-        LPROCFS_ENTRY();
 
         temp = head->subdir;
         while (temp != NULL) {
                 if (strcmp(temp->name, name) == 0) {
-                        LPROCFS_EXIT();
                         return temp;
                 }
 
                 temp = temp->next;
         }
-        LPROCFS_EXIT();
         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;
+}
+
 /* lprocfs API calls */
 
 /* Function that emulates snprintf but also has the side effect of advancing
@@ -131,9 +142,11 @@ cfs_proc_dir_entry_t *lprocfs_add_simple(struct proc_dir_entry *root,
                 mode |= 0200;
         if (fops)
                 mode = 0644;
+        LPROCFS_WRITE_ENTRY();
         proc = create_proc_entry(name, mode, root);
         if (!proc) {
                 CERROR("LprocFS: No memory to create /proc entry %s", name);
+                LPROCFS_WRITE_EXIT();
                 return ERR_PTR(-ENOMEM);
         }
         proc->read_proc = read_proc;
@@ -141,6 +154,7 @@ cfs_proc_dir_entry_t *lprocfs_add_simple(struct proc_dir_entry *root,
         proc->data = data;
         if (fops)
                 proc->proc_fops = fops;
+        LPROCFS_WRITE_EXIT();
         return proc;
 }
 
@@ -288,9 +302,12 @@ EXPORT_SYMBOL(lprocfs_evict_client_fops);
 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;
 
+        LPROCFS_WRITE_ENTRY();
         while (list->name != NULL) {
                 struct proc_dir_entry *cur_root, *proc;
                 char *pathcopy, *cur, *next, pathbuf[64];
@@ -303,7 +320,7 @@ int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
                 if (strlen(list->name) > sizeof(pathbuf) - 1) {
                         OBD_ALLOC(pathcopy, pathsize);
                         if (pathcopy == NULL)
-                                return -ENOMEM;
+                                GOTO(out, rc = -ENOMEM);
                 } else {
                         pathcopy = pathbuf;
                 }
@@ -315,7 +332,7 @@ int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
                         if (*cur =='\0') /* skip double/trailing "/" */
                                 continue;
 
-                        proc = lprocfs_srch(cur_root, cur);
+                        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"));
@@ -342,7 +359,7 @@ int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
                 if (cur_root == NULL || proc == NULL) {
                         CERROR("LprocFS: No memory to create /proc entry %s",
                                list->name);
-                        return -ENOMEM;
+                        GOTO(out, rc = -ENOMEM);
                 }
 
                 if (list->fops)
@@ -354,7 +371,9 @@ int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
                 proc->data = (list->data ? list->data : data);
                 list++;
         }
-        return 0;
+out:
+        LPROCFS_WRITE_EXIT();
+        return rc;
 }
 
 void lprocfs_remove(struct proc_dir_entry **rooth)
@@ -385,9 +404,23 @@ void lprocfs_remove(struct proc_dir_entry **rooth)
                          "0x%p  %s/%s len %d\n", rm_entry, temp->name,
                          rm_entry->name, (int)strlen(rm_entry->name));
 
+#ifdef HAVE_PROCFS_USERS
+                /* if procfs uses user count to synchronize deletion of
+                 * proc entry, there is no protection for rm_entry->data,
+                 * then lprocfs_fops_read and lprocfs_fops_write maybe
+                 * call proc_dir_entry->read_proc (or write_proc) with
+                 * proc_dir_entry->data == NULL, then cause kernel Oops.
+                 * see bug19706 for detailed information */
+
+                /* procfs won't free rm_entry->data if it isn't a LINK,
+                 * and Lustre won't use rm_entry->data if it is a LINK */
+                if (S_ISLNK(rm_entry->mode))
+                        rm_entry->data = NULL;
+#else
                 /* Now, the rm_entry->deleted flags is protected
                  * by _lprocfs_lock. */
                 rm_entry->data = NULL;
+#endif
                 remove_proc_entry(rm_entry->name, temp);
                 if (temp == parent)
                         break;
@@ -685,10 +718,7 @@ void lprocfs_stats_collect(struct lprocfs_stats *stats, int idx,
 
         cnt->lc_min = LC_MIN_INIT;
 
-        if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
-                num_cpu = 1;
-        else
-                num_cpu = cfs_num_possible_cpus();
+        num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
 
         for (i = 0; i < num_cpu; i++) {
                 percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[idx];
@@ -715,6 +745,7 @@ void lprocfs_stats_collect(struct lprocfs_stats *stats, int idx,
         }
 
         cnt->lc_units = stats->ls_percpu[0]->lp_cntr[idx].lc_units;
+        lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU);
 }
 
 /**
@@ -777,10 +808,12 @@ static const char *obd_connect_names[] = {
         "large_ea",
         "full20",
         "layout_lock",
+        "64bithash",
+        "object_max_bytes",
         NULL
 };
 
-static int obd_connect_flags2str(char *page, int count, __u64 flags, char *sep)
+int obd_connect_flags2str(char *page, int count, __u64 flags, char *sep)
 {
         __u64 mask = 1;
         int i, ret = 0;
@@ -796,6 +829,7 @@ static int obd_connect_flags2str(char *page, int count, __u64 flags, char *sep)
                                 ret ? sep : "", flags & ~(mask - 1));
         return ret;
 }
+EXPORT_SYMBOL(obd_connect_flags2str);
 
 int lprocfs_rd_import(char *page, char **start, off_t off, int count,
                       int *eof, void *data)
@@ -1106,8 +1140,8 @@ static void lprocfs_free_client_stats(struct nid_stat *client_stat)
                client_stat->nid_brw_stats);
 
         LASSERTF(cfs_atomic_read(&client_stat->nid_exp_ref_count) == 0,
-                 "count %d\n",
-                 cfs_atomic_read(&client_stat->nid_exp_ref_count));
+                 "nid %s:count %d\n", libcfs_nid2str(client_stat->nid),
+                 atomic_read(&client_stat->nid_exp_ref_count));
 
         cfs_hlist_del_init(&client_stat->nid_hash);
 
@@ -1242,7 +1276,7 @@ void lprocfs_clear_stats(struct lprocfs_stats *stats)
                 }
         }
 
-        lprocfs_stats_unlock(stats);
+        lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU);
 }
 
 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
@@ -1361,11 +1395,18 @@ int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
         struct proc_dir_entry *entry;
         LASSERT(root != NULL);
 
+        LPROCFS_WRITE_ENTRY();
         entry = create_proc_entry(name, 0644, root);
+        if (entry) {
+                entry->proc_fops = &lprocfs_stats_seq_fops;
+                entry->data = stats;
+        }
+
+        LPROCFS_WRITE_EXIT();
+
         if (entry == NULL)
                 return -ENOMEM;
-        entry->proc_fops = &lprocfs_stats_seq_fops;
-        entry->data = stats;
+
         return 0;
 }
 
@@ -1391,7 +1432,7 @@ void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
                 c->lc_units = units;
         }
 
-        lprocfs_stats_unlock(stats);
+        lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU);
 }
 EXPORT_SYMBOL(lprocfs_counter_init);
 
@@ -1473,7 +1514,6 @@ void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getref);
         LPROCFS_OBD_OP_INIT(num_private_stats, stats, putref);
-        LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync_fs);
 }
 
 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
@@ -1527,23 +1567,8 @@ do {                                                                    \
         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");           \
 } while (0)
 
-int lprocfs_alloc_md_stats(struct obd_device *obd,
-                           unsigned num_private_stats)
+void lprocfs_init_mps_stats(int num_private_stats, struct lprocfs_stats *stats)
 {
-        struct lprocfs_stats *stats;
-        unsigned int num_stats;
-        int rc, i;
-
-        LASSERT(obd->md_stats == NULL);
-        LASSERT(obd->obd_proc_entry != NULL);
-        LASSERT(obd->md_cntr_base == 0);
-
-        num_stats = 1 + MD_COUNTER_OFFSET(revalidate_lock) +
-                    num_private_stats;
-        stats = lprocfs_alloc_stats(num_stats, 0);
-        if (stats == NULL)
-                return -ENOMEM;
-
         LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
         LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
         LPROCFS_MD_OP_INIT(num_private_stats, stats, find_cbdata);
@@ -1576,6 +1601,26 @@ int lprocfs_alloc_md_stats(struct obd_device *obd,
         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
         LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
+}
+
+int lprocfs_alloc_md_stats(struct obd_device *obd,
+                           unsigned num_private_stats)
+{
+        struct lprocfs_stats *stats;
+        unsigned int num_stats;
+        int rc, i;
+
+        LASSERT(obd->md_stats == NULL);
+        LASSERT(obd->obd_proc_entry != NULL);
+        LASSERT(obd->md_cntr_base == 0);
+
+        num_stats = 1 + MD_COUNTER_OFFSET(revalidate_lock) +
+                    num_private_stats;
+        stats = lprocfs_alloc_stats(num_stats, 0);
+        if (stats == NULL)
+                return -ENOMEM;
+
+        lprocfs_init_mps_stats(num_private_stats, stats);
 
         for (i = num_private_stats; i < num_stats; i++) {
                 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
@@ -1691,13 +1736,15 @@ int lprocfs_exp_print_hash(cfs_hash_t *hs, cfs_hash_bd_t *bd,
         struct exp_uuid_cb_data *data = cb_data;
         struct obd_export       *exp = cfs_hash_object(hs, hnode);
 
-        LASSERT(hs == exp->exp_lock_hash);
-        if (!*data->len) {
-                *data->len += cfs_hash_debug_header(data->page,
-                                                    data->count);
+        if (exp->exp_lock_hash != NULL) {
+                if (!*data->len) {
+                        *data->len += cfs_hash_debug_header(data->page,
+                                                            data->count);
+                }
+                *data->len += cfs_hash_debug_str(hs, data->page + *data->len,
+                                                 data->count);
         }
-        *data->len += cfs_hash_debug_str(hs, data->page + *data->len,
-                                         data->count);
+
         return 0;
 }
 
@@ -1733,10 +1780,10 @@ int lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
         struct nid_stat *stat = obj;
         int i;
         ENTRY;
-        /* object has only hash + iterate_all references.
-         * add/delete blocked by hash bucket lock */
+
         CDEBUG(D_INFO,"refcnt %d\n", cfs_atomic_read(&stat->nid_exp_ref_count));
-        if (cfs_atomic_read(&stat->nid_exp_ref_count) == 2) {
+        if (cfs_atomic_read(&stat->nid_exp_ref_count) == 1) {
+                /* object has only hash references. */
                 cfs_spin_lock(&stat->nid_obd->obd_nid_lock);
                 cfs_list_move(&stat->nid_list, data);
                 cfs_spin_unlock(&stat->nid_obd->obd_nid_lock);
@@ -1774,8 +1821,7 @@ int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
 }
 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
 
-int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int reconnect,
-                      int *newnid)
+int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
 {
         struct nid_stat *new_stat, *old_stat;
         struct obd_device *obd = NULL;
@@ -1815,15 +1861,16 @@ int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int reconnect,
                old_stat, libcfs_nid2str(*nid),
                cfs_atomic_read(&new_stat->nid_exp_ref_count));
 
+        /* We need to release old stats because lprocfs_exp_cleanup() hasn't
+         * been and will never be called. */
+        if (exp->exp_nid_stats) {
+                nidstat_putref(exp->exp_nid_stats);
+                exp->exp_nid_stats = NULL;
+        }
+
         /* Return -EALREADY here so that we know that the /proc
          * entry already has been created */
         if (old_stat != new_stat) {
-                /* if this connects to the existing export of same nid,
-                 * we need to release old stats for obd_disconnect won't
-                 * balance the reference gotten in "cfs_hash_findadd_uinque" */
-                if (reconnect && exp->exp_nid_stats)
-                        nidstat_putref(old_stat);
-
                 exp->exp_nid_stats = old_stat;
                 GOTO(destroy_new, rc = -EALREADY);
         }
@@ -2067,11 +2114,16 @@ int lprocfs_seq_create(cfs_proc_dir_entry_t *parent, char *name, mode_t mode,
         struct proc_dir_entry *entry;
         ENTRY;
 
+        LPROCFS_WRITE_ENTRY();
         entry = create_proc_entry(name, mode, parent);
+        if (entry) {
+                entry->proc_fops = seq_fops;
+                entry->data = data;
+        }
+        LPROCFS_WRITE_EXIT();
+
         if (entry == NULL)
                 RETURN(-ENOMEM);
-        entry->proc_fops = seq_fops;
-        entry->data = data;
 
         RETURN(0);
 }
@@ -2332,6 +2384,46 @@ int lprocfs_obd_rd_mntdev(char *page, char **start, off_t off,
 }
 EXPORT_SYMBOL(lprocfs_obd_rd_mntdev);
 
+int lprocfs_obd_rd_max_pages_per_rpc(char *page, char **start, off_t off,
+                                     int count, int *eof, void *data)
+{
+        struct obd_device *dev = data;
+        struct client_obd *cli = &dev->u.cli;
+        int rc;
+
+        client_obd_list_lock(&cli->cl_loi_list_lock);
+        rc = snprintf(page, count, "%d\n", cli->cl_max_pages_per_rpc);
+        client_obd_list_unlock(&cli->cl_loi_list_lock);
+        return rc;
+}
+EXPORT_SYMBOL(lprocfs_obd_rd_max_pages_per_rpc);
+
+int lprocfs_obd_wr_max_pages_per_rpc(struct file *file, const char *buffer,
+                                     unsigned long count, void *data)
+{
+        struct obd_device *dev = data;
+        struct client_obd *cli = &dev->u.cli;
+        struct obd_connect_data *ocd = &cli->cl_import->imp_connect_data;
+        int val, rc;
+
+        rc = lprocfs_write_helper(buffer, count, &val);
+        if (rc)
+                return rc;
+
+        LPROCFS_CLIMP_CHECK(dev);
+        if (val < 1 || val > ocd->ocd_brw_size >> CFS_PAGE_SHIFT) {
+                LPROCFS_CLIMP_EXIT(dev);
+                return -ERANGE;
+        }
+        client_obd_list_lock(&cli->cl_loi_list_lock);
+        cli->cl_max_pages_per_rpc = val;
+        client_obd_list_unlock(&cli->cl_loi_list_lock);
+
+        LPROCFS_CLIMP_EXIT(dev);
+        return count;
+}
+EXPORT_SYMBOL(lprocfs_obd_wr_max_pages_per_rpc);
+
 EXPORT_SYMBOL(lprocfs_register);
 EXPORT_SYMBOL(lprocfs_srch);
 EXPORT_SYMBOL(lprocfs_remove);
@@ -2347,6 +2439,7 @@ EXPORT_SYMBOL(lprocfs_free_stats);
 EXPORT_SYMBOL(lprocfs_clear_stats);
 EXPORT_SYMBOL(lprocfs_register_stats);
 EXPORT_SYMBOL(lprocfs_init_ops_stats);
+EXPORT_SYMBOL(lprocfs_init_mps_stats);
 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
 EXPORT_SYMBOL(lprocfs_alloc_md_stats);