about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2013-06-21 03:34:20 +0000
committerEric Wong <normalperson@yhbt.net>2013-07-10 00:55:48 +0000
commitc86b6a2c769c821a64fc14c62a953244b41cb190 (patch)
treee5f6dad36d8d2cdf5b2fcdd36a4284ef9f50f75d
parentf56b866f92e195ffd24a2f8f80e8e2cef226c775 (diff)
downloadcmogstored-c86b6a2c769c821a64fc14c62a953244b41cb190.tar.gz
We will have structures inside the dev struct accessed by multiple
threads frequently, so keep it cache-aligned.

To reduce memory usage for large-numbered devices, avoid storing the
prefix on output and instead just rely on the printf-family of
routines to generate stringified output in uncommon code paths.
-rw-r--r--cmogstored.h1
-rw-r--r--dev.c44
-rw-r--r--path_parser.rl2
3 files changed, 26 insertions, 21 deletions
diff --git a/cmogstored.h b/cmogstored.h
index 1134827..66193b7 100644
--- a/cmogstored.h
+++ b/cmogstored.h
@@ -100,7 +100,6 @@ struct mog_wbuf;
 struct mog_dev {
         dev_t st_dev;
         uint32_t devid;
-        char prefix[FLEXIBLE_ARRAY_MEMBER];
 };
 
 struct mog_rbuf {
diff --git a/dev.c b/dev.c
index 7454b2d..cd39c5d 100644
--- a/dev.c
+++ b/dev.c
@@ -4,25 +4,31 @@
  */
 #include "cmogstored.h"
 
+static int stat_prefix(struct mog_svc *svc, struct stat *sb, uint32_t mog_devid)
+{
+        char prefix[sizeof("/dev" MOG_STR(MOG_DEVID_MAX) "/")];
+        int rc;
+
+        assert(mog_devid <= MOG_DEVID_MAX && "mog_devid not filtered");
+        rc = snprintf(prefix, sizeof(prefix), "/dev%u/", mog_devid);
+        assert(rc > 0 && rc < (int)sizeof(prefix) && "we suck at snprintf");
+
+        return mog_stat(svc, prefix, sb);
+}
+
 static struct mog_dev *mog_dev_new(struct mog_svc *svc, uint32_t mog_devid)
 {
         struct mog_dev *dev;
         struct stat sb;
-        char *devprefix = xasprintf("/dev%u/", mog_devid);
-        size_t len = strlen(devprefix);
 
-        if (mog_stat(svc, devprefix, &sb) < 0) {
-                PRESERVE_ERRNO( free(devprefix) );
+        /* we have no space on stack */
+        if (mog_devid > MOG_DEVID_MAX)
                 return NULL;
-        }
 
-        dev = xmalloc(sizeof(struct mog_dev) + len);
-
-        assert(devprefix[len - 1] == '/' && "not trailing slash");
-        devprefix[len - 1] = '\0';
-        memcpy(dev->prefix, devprefix, len);
-        free(devprefix);
+        if (stat_prefix(svc, &sb, mog_devid) < 0)
+                return NULL;
 
+        dev = mog_cachealign(sizeof(struct mog_dev));
         dev->devid = mog_devid;
         dev->st_dev = sb.st_dev;
 
@@ -46,7 +52,7 @@ struct mog_dev *mog_dev_for(struct mog_svc *svc, uint32_t mog_devid)
                  * Possible FS/device error, it could come back, so do
                  * not remove here.
                  */
-                if (mog_stat(svc, ret->prefix, &sb) < 0)
+                if (stat_prefix(svc, &sb, ret->devid) < 0)
                         goto out;
 
                 /* st_dev may change due to remount, update if needed */
@@ -112,7 +118,7 @@ const struct mog_dev *dev, struct mog_svc *svc, int fd, struct statvfs *v)
                 static const char usage_fmt[] =
                         "available: %llu\n"
                         "device: %s\n"
-                        "disk: %s%s\n"
+                        "disk: %s/dev%u\n"
                         "time: %lld\n"
                         "total: %llu\n"
                         "use: %u%%\n"
@@ -121,18 +127,18 @@ const struct mog_dev *dev, struct mog_svc *svc, int fd, struct statvfs *v)
                 errno = 0;
                 rc = dprintf(fd, usage_fmt,
                              available, me->me_devname, svc->docroot,
-                             dev->prefix, now, total, use, used);
+                             (unsigned)dev->devid, now, total, use, used);
 
                 PRESERVE_ERRNO( mog_mnt_release(me) );
                 if (rc < 0 || errno == ENOSPC) {
                         PRESERVE_ERRNO(do {
-                                syslog(LOG_ERR, "dprintf(%s%s/usage): %m",
-                                       svc->docroot, dev->prefix);
+                                syslog(LOG_ERR, "dprintf(%s/dev%u/usage): %m",
+                                       svc->docroot, (unsigned)dev->devid);
                         } while (0));
                 }
         } else {
-                syslog(LOG_ERR, "mount entry not found for %s%s",
-                       svc->docroot, dev->prefix);
+                syslog(LOG_ERR, "mount entry not found for %s/dev%u",
+                       svc->docroot, (unsigned)dev->devid);
                 errno = ENODEV;
         }
 
@@ -149,7 +155,7 @@ int mog_dev_mkusage(const struct mog_dev *dev, struct mog_svc *svc)
         if (!svc->mgmt_mfd)
                 return 0;
 
-        usage_path = xasprintf("%s/usage", dev->prefix);
+        usage_path = xasprintf("/dev%u/usage", (unsigned)dev->devid);
         tmp_path = xasprintf("%s.%x", usage_path, (unsigned)getpid());
 
         if (mog_unlink(svc, tmp_path) < 0 && errno != ENOENT) goto out;
diff --git a/path_parser.rl b/path_parser.rl
index fc77c98..e403607 100644
--- a/path_parser.rl
+++ b/path_parser.rl
@@ -11,7 +11,7 @@
 
         devid = "dev"
                 (digit+) $ {
-                        /* no overflow checking here, no need */
+                        /* no overflow checking here, we do it in mog_dev_new */
                         *mog_devid *= 10;
                         *mog_devid += fc - '0';
                 }