]> git.proxmox.com Git - mirror_spl-debian.git/commitdiff
Make kstat.ks_update() callback atomic
authorBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 23 Oct 2012 16:17:29 +0000 (09:17 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 23 Oct 2012 16:36:19 +0000 (09:36 -0700)
Move the kstat ks_update() callback under the ks_lock.  This
enables dynamically sized kstats without modification to the
kstat API.

  * Create a kstat with the KSTAT_FLAG_VIRTUAL flag.
  * Register a ->ks_update() callback which does:
    o Frees any existing ks_data buffer.
    o Set ks_data_size to the kstat array size.
    o Set ks_data to an allocated buffer of size ks_data_size
    o Populate the array of buffers with the required data.

The buffer allocated in the ks_update() callback is guaranteed
to remain allocated and valid while the proc sequence handler
iterates over the buffer.  The lock will not be dropped until
kstat_seq_stop() function is run making it safe for concurrent
access.  To allow the ks_update() callback to perform memory
allocations the lock was changed to a mutex.

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
include/sys/kstat.h
module/spl/spl-kstat.c

index e4c88c82b7ccb71562c14addc549920d90f87d5d..45386d49acb4e66deb287b2e28c0231da70bea09 100644 (file)
@@ -30,6 +30,7 @@
 #include <sys/types.h>
 #include <sys/time.h>
 #include <sys/kmem.h>
+#include <sys/mutex.h>
 
 #define KSTAT_STRLEN            31
 
@@ -98,7 +99,7 @@ typedef struct kstat_s {
         struct proc_dir_entry *ks_proc;             /* proc linkage */
         kstat_update_t   *ks_update;                /* dynamic updates */
         void             *ks_private;               /* private data */
-        spinlock_t       ks_lock;                   /* kstat data lock */
+        kmutex_t         ks_lock;                   /* kstat data lock */
         struct list_head ks_list;                   /* kstat linkage */
 } kstat_t;
 
index 48fab972b8c8859fc1a08232e131cef1c5ed7b8f..164a8436d0c93ca6f472e7890e30610b2890b8c2 100644 (file)
@@ -267,10 +267,11 @@ kstat_seq_start(struct seq_file *f, loff_t *pos)
         ASSERT(ksp->ks_magic == KS_MAGIC);
         SENTRY;
 
+        mutex_enter(&ksp->ks_lock);
+
         /* Dynamically update kstat, on error existing kstats are used */
         (void) ksp->ks_update(ksp, KSTAT_READ);
 
-        spin_lock(&ksp->ks_lock);
        ksp->ks_snaptime = gethrtime();
 
         if (!n)
@@ -302,7 +303,7 @@ kstat_seq_stop(struct seq_file *f, void *v)
         kstat_t *ksp = (kstat_t *)f->private;
         ASSERT(ksp->ks_magic == KS_MAGIC);
 
-        spin_unlock(&ksp->ks_lock);
+        mutex_exit(&ksp->ks_lock);
 }
 
 static struct seq_operations kstat_seq_ops = {
@@ -360,7 +361,7 @@ __kstat_create(const char *ks_module, int ks_instance, const char *ks_name,
        spin_unlock(&kstat_lock);
 
         ksp->ks_magic = KS_MAGIC;
-       spin_lock_init(&ksp->ks_lock);
+       mutex_init(&ksp->ks_lock, NULL, MUTEX_DEFAULT, NULL);
        INIT_LIST_HEAD(&ksp->ks_list);
 
        ksp->ks_crtime = gethrtime();
@@ -445,11 +446,11 @@ __kstat_install(kstat_t *ksp)
        if (de_name == NULL)
                SGOTO(out, rc = -EUNATCH);
 
-       spin_lock(&ksp->ks_lock);
+       mutex_enter(&ksp->ks_lock);
        ksp->ks_proc = de_name;
        de_name->proc_fops = &proc_kstat_operations;
         de_name->data = (void *)ksp;
-       spin_unlock(&ksp->ks_lock);
+       mutex_exit(&ksp->ks_lock);
 out:
        if (rc) {
                spin_lock(&kstat_lock);
@@ -482,6 +483,7 @@ __kstat_delete(kstat_t *ksp)
        if (!(ksp->ks_flags & KSTAT_FLAG_VIRTUAL))
                 kmem_free(ksp->ks_data, ksp->ks_data_size);
 
+       mutex_destroy(&ksp->ks_lock);
        kmem_free(ksp, sizeof(*ksp));
 
        return;