Whamcloud - gitweb
LU-3916 lprocfs: export lprocfs setup race
[fs/lustre-release.git] / lustre / obdclass / lprocfs_status.c
index 8b52d52..885287c 100644 (file)
@@ -62,14 +62,12 @@ EXPORT_SYMBOL(_lprocfs_lock);
 
 int lprocfs_single_release(struct inode *inode, struct file *file)
 {
-        LPROCFS_EXIT();
         return single_release(inode, file);
 }
 EXPORT_SYMBOL(lprocfs_single_release);
 
 int lprocfs_seq_release(struct inode *inode, struct file *file)
 {
-        LPROCFS_EXIT();
         return seq_release(inode, file);
 }
 EXPORT_SYMBOL(lprocfs_seq_release);
@@ -205,7 +203,7 @@ static ssize_t lprocfs_fops_read(struct file *f, char __user *buf,
         if (page == NULL)
                 return -ENOMEM;
 
-        if (LPROCFS_ENTRY_AND_CHECK(dp)) {
+       if (LPROCFS_ENTRY_CHECK(dp)) {
                 rc = -ENOENT;
                 goto out;
         }
@@ -214,7 +212,6 @@ static ssize_t lprocfs_fops_read(struct file *f, char __user *buf,
         if (dp->read_proc)
                rc = dp->read_proc(page, &start, *ppos, PAGE_CACHE_SIZE,
                                    &eof, dp->data);
-        LPROCFS_EXIT();
         if (rc <= 0)
                 goto out;
 
@@ -250,11 +247,10 @@ static ssize_t lprocfs_fops_write(struct file *f, const char __user *buf,
         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
         int rc = -EIO;
 
-        if (LPROCFS_ENTRY_AND_CHECK(dp))
+       if (LPROCFS_ENTRY_CHECK(dp))
                 return -ENOENT;
         if (dp->write_proc)
                 rc = dp->write_proc(f, buf, size, dp->data);
-        LPROCFS_EXIT();
         return rc;
 }
 
@@ -276,13 +272,13 @@ int lprocfs_evict_client_open(struct inode *inode, struct file *f)
 
 int lprocfs_evict_client_release(struct inode *inode, struct file *f)
 {
-        struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
-        struct obd_device *obd = dp->data;
+       struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
+       struct obd_device *obd = dp->data;
 
-        cfs_atomic_dec(&obd->obd_evict_inprogress);
-        cfs_waitq_signal(&obd->obd_evict_inprogress_waitq);
+       cfs_atomic_dec(&obd->obd_evict_inprogress);
+       wake_up(&obd->obd_evict_inprogress_waitq);
 
-        return 0;
+       return 0;
 }
 
 struct file_operations lprocfs_evict_client_fops = {
@@ -776,7 +772,6 @@ void lprocfs_stats_collect(struct lprocfs_stats *stats, int idx,
 {
        unsigned int                    num_entry;
        struct lprocfs_counter          *percpu_cntr;
-       struct lprocfs_counter_header   *cntr_header;
        int                             i;
        unsigned long                   flags = 0;
 
@@ -795,7 +790,6 @@ void lprocfs_stats_collect(struct lprocfs_stats *stats, int idx,
        for (i = 0; i < num_entry; i++) {
                if (stats->ls_percpu[i] == NULL)
                        continue;
-               cntr_header = &stats->ls_cnt_header[idx];
                percpu_cntr = lprocfs_stats_counter_get(stats, i, idx);
 
                cnt->lc_count += percpu_cntr->lc_count;
@@ -884,6 +878,7 @@ static const char *obd_connect_names[] = {
        "lightweight_conn",
        "short_io",
        "pingless",
+       "flock_deadlock",
        "unknown",
         NULL
 };
@@ -1288,7 +1283,7 @@ struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
        if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
                num_entry = 1;
        else
-               num_entry = cfs_num_possible_cpus();
+               num_entry = num_possible_cpus();
 
        /* alloc percpu pointers for all possible cpu slots */
        LIBCFS_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_entry]));
@@ -1341,7 +1336,7 @@ void lprocfs_free_stats(struct lprocfs_stats **statsh)
        if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
                num_entry = 1;
        else
-               num_entry = cfs_num_possible_cpus();
+               num_entry = num_possible_cpus();
 
        percpusize = lprocfs_stats_counter_size(stats);
        for (i = 0; i < num_entry; i++)
@@ -1357,7 +1352,6 @@ EXPORT_SYMBOL(lprocfs_free_stats);
 void lprocfs_clear_stats(struct lprocfs_stats *stats)
 {
        struct lprocfs_counter          *percpu_cntr;
-       struct lprocfs_counter_header   *header;
        int                             i;
        int                             j;
        unsigned int                    num_entry;
@@ -1369,7 +1363,6 @@ void lprocfs_clear_stats(struct lprocfs_stats *stats)
                if (stats->ls_percpu[i] == NULL)
                        continue;
                for (j = 0; j < stats->ls_num; j++) {
-                       header = &stats->ls_cnt_header[j];
                        percpu_cntr = lprocfs_stats_counter_get(stats, i, j);
                        percpu_cntr->lc_count           = 0;
                        percpu_cntr->lc_min             = LC_MIN_INIT;
@@ -1426,7 +1419,7 @@ static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
        if (idx == 0) {
                struct timeval now;
 
-               cfs_gettimeofday(&now);
+               do_gettimeofday(&now);
                rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
                                "snapshot_time", now.tv_sec, now.tv_usec);
                if (rc < 0)
@@ -1472,14 +1465,12 @@ static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
         struct seq_file *seq;
         int rc;
 
-        if (LPROCFS_ENTRY_AND_CHECK(dp))
+       if (LPROCFS_ENTRY_CHECK(dp))
                 return -ENOENT;
 
         rc = seq_open(file, &lprocfs_stats_seq_sops);
-        if (rc) {
-                LPROCFS_EXIT();
+       if (rc)
                 return rc;
-        }
         seq = file->private_data;
         seq->private = dp->data;
         return 0;
@@ -1628,6 +1619,8 @@ 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);
+
+       CLASSERT(NUM_OBD_STATS == OBD_COUNTER_OFFSET(putref) + 1);
 }
 EXPORT_SYMBOL(lprocfs_init_ops_stats);
 
@@ -1641,8 +1634,7 @@ int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
         LASSERT(obd->obd_proc_entry != NULL);
         LASSERT(obd->obd_cntr_base == 0);
 
-        num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
-                num_private_stats - 1 /* o_owner */;
+       num_stats = NUM_OBD_STATS + num_private_stats;
         stats = lprocfs_alloc_stats(num_stats, 0);
         if (stats == NULL)
                 return -ENOMEM;
@@ -1677,12 +1669,18 @@ void lprocfs_free_obd_stats(struct obd_device *obd)
 }
 EXPORT_SYMBOL(lprocfs_free_obd_stats);
 
-#define LPROCFS_MD_OP_INIT(base, stats, op)                             \
-do {                                                                    \
-        unsigned int coffset = base + MD_COUNTER_OFFSET(op);            \
-        LASSERT(coffset < stats->ls_num);                               \
-        lprocfs_counter_init(stats, coffset, 0, #op, "reqs");           \
-} while (0)
+/* Note that we only init md counters for ops whose offset is less
+ * than NUM_MD_STATS. This is explained in a comment in the definition
+ * of struct md_ops. */
+#define LPROCFS_MD_OP_INIT(base, stats, op)                                   \
+       do {                                                                   \
+               unsigned int _idx = base + MD_COUNTER_OFFSET(op);              \
+                                                                              \
+               if (MD_COUNTER_OFFSET(op) < NUM_MD_STATS) {                    \
+                       LASSERT(_idx < stats->ls_num);                         \
+                       lprocfs_counter_init(stats, _idx, 0, #op, "reqs");     \
+               }                                                              \
+       } while (0)
 
 void lprocfs_init_mps_stats(int num_private_stats, struct lprocfs_stats *stats)
 {
@@ -1700,7 +1698,7 @@ void lprocfs_init_mps_stats(int num_private_stats, struct lprocfs_stats *stats)
         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
         LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
         LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
-        LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
+       LPROCFS_MD_OP_INIT(num_private_stats, stats, fsync);
         LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
@@ -1722,52 +1720,65 @@ void lprocfs_init_mps_stats(int num_private_stats, struct lprocfs_stats *stats)
 EXPORT_SYMBOL(lprocfs_init_mps_stats);
 
 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);
+                          unsigned int num_private_stats)
+{
+       struct lprocfs_stats *stats;
+       unsigned int num_stats;
+       int rc, i;
+
+       CLASSERT(offsetof(struct md_ops, MD_STATS_FIRST_OP) == 0);
+       CLASSERT(_MD_COUNTER_OFFSET(MD_STATS_FIRST_OP) == 0);
+       CLASSERT(_MD_COUNTER_OFFSET(MD_STATS_LAST_OP) > 0);
+
+       /* TODO Ensure that this function is only used where
+        * appropriate by adding an assertion to the effect that
+        * obd->obd_type->typ_md_ops is not NULL. We can't do this now
+        * because mdt_procfs_init() uses this function to allocate
+        * the stats backing /proc/fs/lustre/mdt/.../md_stats but the
+        * mdt layer does not use the md_ops interface. This is
+        * confusing and a waste of memory. See LU-2484.
+        */
+       LASSERT(obd->obd_proc_entry != NULL);
+       LASSERT(obd->obd_md_stats == NULL);
+       LASSERT(obd->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;
+       num_stats = NUM_MD_STATS + num_private_stats;
+       stats = lprocfs_alloc_stats(num_stats, 0);
+       if (stats == NULL)
+               return -ENOMEM;
 
-        lprocfs_init_mps_stats(num_private_stats, stats);
+       lprocfs_init_mps_stats(num_private_stats, stats);
 
-        for (i = num_private_stats; i < num_stats; i++) {
+       for (i = num_private_stats; i < num_stats; i++) {
                if (stats->ls_cnt_header[i].lc_name == NULL) {
-                        CERROR("Missing md_stat initializer md_op "
-                               "operation at offset %d. Aborting.\n",
-                               i - num_private_stats);
-                        LBUG();
-                }
-        }
-        rc = lprocfs_register_stats(obd->obd_proc_entry, "md_stats", stats);
-        if (rc < 0) {
-                lprocfs_free_stats(&stats);
-        } else {
-                obd->md_stats  = stats;
-                obd->md_cntr_base = num_private_stats;
-        }
-        return rc;
+                       CERROR("Missing md_stat initializer md_op "
+                              "operation at offset %d. Aborting.\n",
+                              i - num_private_stats);
+                       LBUG();
+               }
+       }
+
+       rc = lprocfs_register_stats(obd->obd_proc_entry, "md_stats", stats);
+       if (rc < 0) {
+               lprocfs_free_stats(&stats);
+       } else {
+               obd->obd_md_stats = stats;
+               obd->obd_md_cntr_base = num_private_stats;
+       }
+
+       return rc;
 }
 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
 
 void lprocfs_free_md_stats(struct obd_device *obd)
 {
-        struct lprocfs_stats *stats = obd->md_stats;
+       struct lprocfs_stats *stats = obd->obd_md_stats;
 
-        if (stats != NULL) {
-                obd->md_stats = NULL;
-                obd->md_cntr_base = 0;
-                lprocfs_free_stats(&stats);
-        }
+       if (stats != NULL) {
+               obd->obd_md_stats = NULL;
+               obd->obd_md_cntr_base = 0;
+               lprocfs_free_stats(&stats);
+       }
 }
 EXPORT_SYMBOL(lprocfs_free_md_stats);
 
@@ -1958,6 +1969,13 @@ int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
         if (!nid || *nid == LNET_NID_ANY)
                 RETURN(0);
 
+       spin_lock(&exp->exp_lock);
+       if (exp->exp_nid_stats != NULL) {
+               spin_unlock(&exp->exp_lock);
+               RETURN(-EALREADY);
+       }
+       spin_unlock(&exp->exp_lock);
+
         obd = exp->exp_obd;
 
         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
@@ -1977,19 +1995,12 @@ int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
                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) {
-                exp->exp_nid_stats = old_stat;
-                GOTO(destroy_new, rc = -EALREADY);
-        }
+       /* Return -EALREADY here so that we know that the /proc
+        * entry already has been created */
+       if (old_stat != new_stat) {
+               nidstat_putref(old_stat);
+               GOTO(destroy_new, rc = -EALREADY);
+       }
         /* not found - create */
         OBD_ALLOC(buffer, LNET_NIDSTR_SIZE);
         if (buffer == NULL)
@@ -2025,7 +2036,9 @@ int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
                 GOTO(destroy_new_ns, rc);
         }
 
-        exp->exp_nid_stats = new_stat;
+       spin_lock(&exp->exp_lock);
+       exp->exp_nid_stats = new_stat;
+       spin_unlock(&exp->exp_lock);
         *newnid = 1;
         /* protect competitive add to list, not need locking on destroy */
        spin_lock(&obd->obd_nid_lock);
@@ -2210,18 +2223,20 @@ int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
         }
 
         units = 1;
-        switch(*end) {
-        case 'p': case 'P':
-                units <<= 10;
-        case 't': case 'T':
-                units <<= 10;
-        case 'g': case 'G':
-                units <<= 10;
-        case 'm': case 'M':
-                units <<= 10;
-        case 'k': case 'K':
-                units <<= 10;
-        }
+       if (end != NULL) {
+               switch (*end) {
+               case 'p': case 'P':
+                       units <<= 10;
+               case 't': case 'T':
+                       units <<= 10;
+               case 'g': case 'G':
+                       units <<= 10;
+               case 'm': case 'M':
+                       units <<= 10;
+               case 'k': case 'K':
+                       units <<= 10;
+               }
+       }
         /* Specified units override the multiplier */
         if (units)
                 mult = mult < 0 ? -units : units;
@@ -2330,12 +2345,12 @@ EXPORT_SYMBOL(lprocfs_oh_tally);
 
 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
 {
-        unsigned int val;
+       unsigned int val = 0;
 
-        for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
-                ;
+       if (likely(value != 0))
+               val = min(fls(value - 1), OBD_HIST_MAX);
 
-        lprocfs_oh_tally(oh, val);
+       lprocfs_oh_tally(oh, val);
 }
 EXPORT_SYMBOL(lprocfs_oh_tally_log2);