Merge tag 'zonefs-5.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal...
[linux-2.6-microblaze.git] / fs / nfsd / export.c
index 81e7bb1..7c863f2 100644 (file)
@@ -331,12 +331,29 @@ static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc)
        fsloc->locations = NULL;
 }
 
+static int export_stats_init(struct export_stats *stats)
+{
+       stats->start_time = ktime_get_seconds();
+       return nfsd_percpu_counters_init(stats->counter, EXP_STATS_COUNTERS_NUM);
+}
+
+static void export_stats_reset(struct export_stats *stats)
+{
+       nfsd_percpu_counters_reset(stats->counter, EXP_STATS_COUNTERS_NUM);
+}
+
+static void export_stats_destroy(struct export_stats *stats)
+{
+       nfsd_percpu_counters_destroy(stats->counter, EXP_STATS_COUNTERS_NUM);
+}
+
 static void svc_export_put(struct kref *ref)
 {
        struct svc_export *exp = container_of(ref, struct svc_export, h.ref);
        path_put(&exp->ex_path);
        auth_domain_put(exp->ex_client);
        nfsd4_fslocs_free(&exp->ex_fslocs);
+       export_stats_destroy(&exp->ex_stats);
        kfree(exp->ex_uuid);
        kfree_rcu(exp, ex_rcu);
 }
@@ -692,22 +709,47 @@ static void exp_flags(struct seq_file *m, int flag, int fsid,
                kuid_t anonu, kgid_t anong, struct nfsd4_fs_locations *fslocs);
 static void show_secinfo(struct seq_file *m, struct svc_export *exp);
 
+static int is_export_stats_file(struct seq_file *m)
+{
+       /*
+        * The export_stats file uses the same ops as the exports file.
+        * We use the file's name to determine the reported info per export.
+        * There is no rename in nsfdfs, so d_name.name is stable.
+        */
+       return !strcmp(m->file->f_path.dentry->d_name.name, "export_stats");
+}
+
 static int svc_export_show(struct seq_file *m,
                           struct cache_detail *cd,
                           struct cache_head *h)
 {
-       struct svc_export *exp ;
+       struct svc_export *exp;
+       bool export_stats = is_export_stats_file(m);
 
-       if (h ==NULL) {
-               seq_puts(m, "#path domain(flags)\n");
+       if (h == NULL) {
+               if (export_stats)
+                       seq_puts(m, "#path domain start-time\n#\tstats\n");
+               else
+                       seq_puts(m, "#path domain(flags)\n");
                return 0;
        }
        exp = container_of(h, struct svc_export, h);
        seq_path(m, &exp->ex_path, " \t\n\\");
        seq_putc(m, '\t');
        seq_escape(m, exp->ex_client->name, " \t\n\\");
+       if (export_stats) {
+               seq_printf(m, "\t%lld\n", exp->ex_stats.start_time);
+               seq_printf(m, "\tfh_stale: %lld\n",
+                          percpu_counter_sum_positive(&exp->ex_stats.counter[EXP_STATS_FH_STALE]));
+               seq_printf(m, "\tio_read: %lld\n",
+                          percpu_counter_sum_positive(&exp->ex_stats.counter[EXP_STATS_IO_READ]));
+               seq_printf(m, "\tio_write: %lld\n",
+                          percpu_counter_sum_positive(&exp->ex_stats.counter[EXP_STATS_IO_WRITE]));
+               seq_putc(m, '\n');
+               return 0;
+       }
        seq_putc(m, '(');
-       if (test_bit(CACHE_VALID, &h->flags) && 
+       if (test_bit(CACHE_VALID, &h->flags) &&
            !test_bit(CACHE_NEGATIVE, &h->flags)) {
                exp_flags(m, exp->ex_flags, exp->ex_fsid,
                          exp->ex_anon_uid, exp->ex_anon_gid, &exp->ex_fslocs);
@@ -748,6 +790,7 @@ static void svc_export_init(struct cache_head *cnew, struct cache_head *citem)
        new->ex_layout_types = 0;
        new->ex_uuid = NULL;
        new->cd = item->cd;
+       export_stats_reset(&new->ex_stats);
 }
 
 static void export_update(struct cache_head *cnew, struct cache_head *citem)
@@ -780,10 +823,15 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem)
 static struct cache_head *svc_export_alloc(void)
 {
        struct svc_export *i = kmalloc(sizeof(*i), GFP_KERNEL);
-       if (i)
-               return &i->h;
-       else
+       if (!i)
+               return NULL;
+
+       if (export_stats_init(&i->ex_stats)) {
+               kfree(i);
                return NULL;
+       }
+
+       return &i->h;
 }
 
 static const struct cache_detail svc_export_cache_template = {
@@ -1245,10 +1293,14 @@ static int e_show(struct seq_file *m, void *p)
        struct cache_head *cp = p;
        struct svc_export *exp = container_of(cp, struct svc_export, h);
        struct cache_detail *cd = m->private;
+       bool export_stats = is_export_stats_file(m);
 
        if (p == SEQ_START_TOKEN) {
                seq_puts(m, "# Version 1.1\n");
-               seq_puts(m, "# Path Client(Flags) # IPs\n");
+               if (export_stats)
+                       seq_puts(m, "# Path Client Start-time\n#\tStats\n");
+               else
+                       seq_puts(m, "# Path Client(Flags) # IPs\n");
                return 0;
        }