about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2013-06-15 11:22:11 +0000
committerEric Wong <normalperson@yhbt.net>2013-06-15 11:22:11 +0000
commit526b74a42392715e72634faf51a5e92314c01c6a (patch)
treee4d417af533d81d16df429844f19888306959c4f
parentdf5a65a089c82659ab5e2636d140822ea18674b8 (diff)
downloadcmogstored-526b74a42392715e72634faf51a5e92314c01c6a.tar.gz
This will allow us to lookup devices for per-(mog)device I/O queues.
-rw-r--r--cmogstored.h6
-rw-r--r--dev.c60
-rw-r--r--svc.c5
-rw-r--r--svc_dev.c25
4 files changed, 77 insertions, 19 deletions
diff --git a/cmogstored.h b/cmogstored.h
index 2937049..d9e74fc 100644
--- a/cmogstored.h
+++ b/cmogstored.h
@@ -142,6 +142,8 @@ struct mog_svc {
 
         /* private */
         DIR *dir;
+        pthread_mutex_t by_mog_devid_lock;
+        Hash_table *by_mog_devid;
         Hash_table *by_st_dev;
         pthread_mutex_t devstats_lock;
         struct mog_queue *queue;
@@ -331,8 +333,10 @@ size_t mog_svc_each(Hash_processor processor, void *data);
 void mog_svc_upgrade_prepare(void);
 
 /* dev.c */
-struct mog_dev * mog_dev_new(struct mog_svc *, uint32_t mog_devid);
+struct mog_dev * mog_dev_for(struct mog_svc *, uint32_t mog_devid);
 int mog_dev_mkusage(const struct mog_dev *, struct mog_svc *);
+size_t mog_dev_hash(const void *, size_t tablesize);
+bool mog_dev_cmp(const void *a, const void *b);
 
 /* valid_path.rl */
 int mog_valid_path(const char *buf, size_t len);
diff --git a/dev.c b/dev.c
index aa915b9..7454b2d 100644
--- a/dev.c
+++ b/dev.c
@@ -4,7 +4,7 @@
  */
 #include "cmogstored.h"
 
-struct mog_dev * mog_dev_new(struct mog_svc *svc, uint32_t mog_devid)
+static struct mog_dev *mog_dev_new(struct mog_svc *svc, uint32_t mog_devid)
 {
         struct mog_dev *dev;
         struct stat sb;
@@ -29,6 +29,64 @@ struct mog_dev * mog_dev_new(struct mog_svc *svc, uint32_t mog_devid)
         return dev;
 }
 
+struct mog_dev *mog_dev_for(struct mog_svc *svc, uint32_t mog_devid)
+{
+        struct mog_dev finder;
+        struct mog_dev *ret;
+
+        finder.devid = mog_devid;
+
+        CHECK(int, 0, pthread_mutex_lock(&svc->by_mog_devid_lock));
+        ret = hash_lookup(svc->by_mog_devid, &finder);
+        if (ret) {
+                struct stat sb;
+
+                /*
+                 * devXXX dir existed before, but is no longer readable
+                 * Possible FS/device error, it could come back, so do
+                 * not remove here.
+                 */
+                if (mog_stat(svc, ret->prefix, &sb) < 0)
+                        goto out;
+
+                /* st_dev may change due to remount, update if needed */
+                ret->st_dev = sb.st_dev;
+        } else { /* create a new dev */
+                ret = mog_dev_new(svc, mog_devid);
+
+                if (!ret)
+                        goto out; /* could not stat */
+
+                switch (hash_insert_if_absent(svc->by_mog_devid, ret, NULL)) {
+                case 0:
+                        assert(0 && "mog_dev existed while adding");
+                        abort();
+                case 1: break; /* OK, inserted */
+                default: mog_oom();
+                }
+        }
+out:
+        CHECK(int, 0, pthread_mutex_unlock(&svc->by_mog_devid_lock));
+
+        return ret;
+}
+
+
+size_t mog_dev_hash(const void *x, size_t tablesize)
+{
+        const struct mog_dev *dev = x;
+
+        return dev->devid % tablesize;
+}
+
+bool mog_dev_cmp(const void *a, const void *b)
+{
+        const struct mog_dev *dev_a = a;
+        const struct mog_dev *dev_b = b;
+
+        return dev_a->devid == dev_b->devid;
+}
+
 static int
 emit_usage(
 const struct mog_dev *dev, struct mog_svc *svc, int fd, struct statvfs *v)
diff --git a/svc.c b/svc.c
index 1bf0d45..6eea3e3 100644
--- a/svc.c
+++ b/svc.c
@@ -22,6 +22,8 @@ static void svc_free(void *ptr)
         mog_free(svc->docroot);
         if (svc->by_st_dev)
                 hash_free(svc->by_st_dev);
+        if (svc->by_mog_devid)
+                hash_free(svc->by_mog_devid);
         free(svc);
 }
 
@@ -93,6 +95,9 @@ struct mog_svc * mog_svc_new(const char *docroot)
         svc->mkcol_perms = (~mog_umask) & 0777;
         svc->idle_timeout = 5;
         CHECK(int, 0, pthread_mutex_init(&svc->devstats_lock, NULL));
+        CHECK(int, 0, pthread_mutex_init(&svc->by_mog_devid_lock, NULL));
+        svc->by_mog_devid = hash_initialize(7, NULL, mog_dev_hash,
+                                        mog_dev_cmp, free);
 
         switch (hash_insert_if_absent(by_docroot, svc, NULL)) {
         case 0:
diff --git a/svc_dev.c b/svc_dev.c
index 68d8e3b..d7e1dcd 100644
--- a/svc_dev.c
+++ b/svc_dev.c
@@ -38,28 +38,19 @@ static void devlist_free(void *x)
         free(devlist);
 }
 
-static size_t devid_hash(const void *x, size_t tablesize)
-{
-        const struct mog_dev *dev = x;
-
-        return dev->devid % tablesize;
-}
-
-static bool devid_cmp(const void *a, const void *b)
-{
-        const struct mog_dev *dev_a = a;
-        const struct mog_dev *dev_b = b;
-
-        return dev_a->devid == dev_b->devid;
-}
-
 static struct mog_devlist * mog_devlist_new(dev_t st_dev)
 {
         struct mog_devlist *devlist = xmalloc(sizeof(struct mog_devlist));
 
         devlist->st_dev = st_dev;
         devlist->by_mogdevid = hash_initialize(7, NULL,
-                                               devid_hash, devid_cmp, free);
+                                               mog_dev_hash, mog_dev_cmp,
+
+                                               /*
+                                                * elements are freed when
+                                                * svc->by_mog_devid is freed
+                                                */
+                                               NULL);
 
         return devlist;
 }
@@ -126,7 +117,7 @@ static int svc_scandev(struct mog_svc *svc, size_t *nr, mog_scandev_cb cb)
                 if (*end != 0) continue;
                 if (mog_devid > 0xffffff) continue; /* MEDIUMINT in DB */
 
-                dev = mog_dev_new(svc, (uint32_t)mog_devid);
+                dev = mog_dev_for(svc, (uint32_t)mog_devid);
                 if (!dev) continue;
 
                 devlist = svc_devlist(svc, dev->st_dev);