about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2013-06-25 19:46:02 +0000
committerEric Wong <normalperson@yhbt.net>2013-06-25 19:46:02 +0000
commit0ad0f16bce2769a599eb718261e0283e79c57639 (patch)
tree320edb81f1278eac4a774a598b9c9584e0bfba3a
parent86e5d10649f14fe3b3c8af37fd8ec04cc337fc9e (diff)
downloadcmogstored-0ad0f16bce2769a599eb718261e0283e79c57639.tar.gz
st_rdev matching is necessary for cases where the block devices
are aliased (not via symlinks), and mountlist returns a different
name for the device than what iostat uses.  This is the case for
my cryptmount(8) setup, where /dev/mapper/FOO and /dev/dm-N refer
to the same device (with matching st_dev and st_rdev numbers),
but neither is a symlink to the other (nor are they hardlinks).

stat() on block devices in /dev should always be fast and
non-blocking, as /dev is expected to be non-networked on any
reasonable system (at least those serving as a MogileFS storage
node).
-rw-r--r--mnt.c24
1 files changed, 24 insertions, 0 deletions
diff --git a/mnt.c b/mnt.c
index 7205c2c..4f5aeb7 100644
--- a/mnt.c
+++ b/mnt.c
@@ -285,9 +285,12 @@ void mog_mnt_release(const struct mount_entry *me)
         CHECK(int, 0, pthread_mutex_unlock(&by_dev_lock) );
 }
 
+#define MOG_DEV_T_INVAL ((dev_t)-1)
+
 struct mnt_update {
         const char *prefix;
         size_t prefixlen;
+        dev_t st_rdev;
         char util[MOG_IOUTIL_LEN];
 };
 
@@ -297,6 +300,10 @@ struct mnt_update {
  */
 static bool me_update_match(struct mount_entry *me, struct mnt_update *update)
 {
+        if (update->st_rdev != MOG_DEV_T_INVAL
+            && me->me_dev == update->st_rdev)
+                return true;
+
         if (strlen(me->me_devname) < update->prefixlen)
                 return false;
         return memcmp(update->prefix, me->me_devname, update->prefixlen) == 0;
@@ -334,10 +341,27 @@ static bool update_util_each(void *ent, void *upd)
 void mog_mnt_update_util(struct mog_iostat *iostat)
 {
         struct mnt_update update;
+        struct stat st;
         const char *devsuffix = iostat->dev;
 
         update.prefix = xasprintf("/dev/%s", devsuffix);
         update.prefixlen = strlen(update.prefix);
+
+        /*
+         * st_rdev matching is necessary for cryptmount(8) on Linux, where
+         * /dev/mapper/FOO is NOT a symlink to /dev/dm-N, but /dev/dm-N
+         * and /dev/mapper/FOO both refer to the same device (where
+         * /dev/mapper/FOO is the mounted device name, mountlist never
+         * sees /dev/dm-N).
+         *
+         * FIXME: parse /proc/partitions under Linux like mogstored does
+         * may avoid this stat.
+         */
+        if (stat(update.prefix, &st) == 0 && S_ISBLK(st.st_mode))
+                update.st_rdev = st.st_rdev;
+        else
+                update.st_rdev = MOG_DEV_T_INVAL;
+
         assert(sizeof(update.util) == sizeof(iostat->util));
         memcpy(&update.util, iostat->util, sizeof(update.util));