]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/krbd.cc
Import ceph 15.2.8
[ceph.git] / ceph / src / krbd.cc
index 0019f6f5fec803313881b611e0da3b5d7149ac0e..0d463dea52e92dfa7085044e32afb657d8ed054e 100644 (file)
@@ -66,6 +66,7 @@ DEFINE_UDEV_UPTR(device)  /* udev_device_uptr */
 struct krbd_ctx {
   CephContext *cct;
   struct udev *udev;
+  uint32_t flags;  /* KRBD_CTX_F_* */
 };
 
 struct krbd_spec {
@@ -380,14 +381,47 @@ private:
   std::string *m_pdevnode;
 };
 
-static int do_map(struct udev *udev, const krbd_spec& spec, const string& buf,
+static const char *get_event_source(const krbd_ctx *ctx)
+{
+  if (ctx->flags & KRBD_CTX_F_NOUDEV) {
+    /*
+     * For block devices (unlike network interfaces, they don't
+     * carry any namespace tags), the kernel broadcasts uevents
+     * into all network namespaces that are owned by the initial
+     * user namespace.  This restriction is new in 4.18: starting
+     * with 2.6.35 and through 4.17 the kernel broadcast uevents
+     * into all network namespaces, period.
+     *
+     * However, when invoked from a non-initial user namespace,
+     * udev_monitor_receive_device() has always ignored both kernel
+     * and udev uevents by virtue of requiring SCM_CREDENTIALS and
+     * checking that ucred->uid == 0.  When UIDs and GIDs are sent to
+     * a process in a user namespace, they are translated according
+     * to that process's UID and GID mappings and, unless root in the
+     * user namespace is mapped to the global root, that check fails.
+     * Normally they show up as 65534(nobody) because the global root
+     * is not mapped.
+     */
+    return "kernel";
+  }
+
+  /*
+   * Like most netlink messages, udev uevents don't cross network
+   * namespace boundaries and are therefore confined to the initial
+   * network namespace.
+   */
+  return "udev";
+}
+
+static int do_map(krbd_ctx *ctx, const krbd_spec& spec, const string& buf,
                   string *pname)
 {
   bool mapped;
   int fds[2];
   int r;
 
-  udev_monitor_uptr mon(udev_monitor_new_from_netlink(udev, "udev"));
+  udev_monitor_uptr mon(udev_monitor_new_from_netlink(ctx->udev,
+                                                      get_event_source(ctx)));
   if (!mon)
     return -ENOMEM;
 
@@ -473,7 +507,7 @@ static int map_image(struct krbd_ctx *ctx, const krbd_spec& spec,
   if (r < 0)
     return r;
 
-  return do_map(ctx->udev, spec, buf, pname);
+  return do_map(ctx, spec, buf, pname);
 }
 
 static int devno_to_krbd_id(struct udev *udev, dev_t devno, string *pid)
@@ -681,13 +715,14 @@ private:
   dev_t m_devno;
 };
 
-static int do_unmap(struct udev *udev, dev_t devno, const string& buf)
+static int do_unmap(krbd_ctx *ctx, dev_t devno, const string& buf)
 {
   bool unmapped;
   int fds[2];
   int r;
 
-  udev_monitor_uptr mon(udev_monitor_new_from_netlink(udev, "udev"));
+  udev_monitor_uptr mon(udev_monitor_new_from_netlink(ctx->udev,
+                                                      get_event_source(ctx)));
   if (!mon)
     return -ENOMEM;
 
@@ -710,7 +745,8 @@ static int do_unmap(struct udev *udev, dev_t devno, const string& buf)
   if (pipe2(fds, O_NONBLOCK) < 0)
     return -errno;
 
-  auto unmapper = make_named_thread("unmapper", [&buf, sysfs_r_fd = fds[1]]() {
+  auto unmapper = make_named_thread(
+      "unmapper", [&buf, sysfs_r_fd = fds[1], flags = ctx->flags]() {
     /*
      * On final device close(), kernel sends a block change event, in
      * response to which udev apparently runs blkid on the device.  This
@@ -722,7 +758,7 @@ static int do_unmap(struct udev *udev, dev_t devno, const string& buf)
       if (sysfs_r == -EBUSY && tries < 2) {
         if (!tries) {
           usleep(250 * 1000);
-        } else {
+        } else if (!(flags & KRBD_CTX_F_NOUDEV)) {
           /*
            * libudev does not provide the "wait until the queue is empty"
            * API or the sufficient amount of primitives to build it from.
@@ -805,7 +841,7 @@ static int unmap_image(struct krbd_ctx *ctx, const char *devnode,
   }
 
   append_unmap_options(&buf, options);
-  return do_unmap(ctx->udev, wholedevno, buf);
+  return do_unmap(ctx, wholedevno, buf);
 }
 
 static int unmap_image(struct krbd_ctx *ctx, const krbd_spec& spec,
@@ -837,7 +873,7 @@ static int unmap_image(struct krbd_ctx *ctx, const krbd_spec& spec,
   }
 
   append_unmap_options(&buf, options);
-  return do_unmap(ctx->udev, devno, buf);
+  return do_unmap(ctx, devno, buf);
 }
 
 static bool dump_one_image(Formatter *f, TextTable *tbl,
@@ -955,7 +991,7 @@ static int is_mapped_image(struct udev *udev, const krbd_spec& spec,
   return 0;  /* not mapped */
 }
 
-extern "C" int krbd_create_from_context(rados_config_t cct,
+extern "C" int krbd_create_from_context(rados_config_t cct, uint32_t flags,
                                         struct krbd_ctx **pctx)
 {
   struct krbd_ctx *ctx = new struct krbd_ctx();
@@ -966,6 +1002,7 @@ extern "C" int krbd_create_from_context(rados_config_t cct,
     delete ctx;
     return -ENOMEM;
   }
+  ctx->flags = flags;
 
   *pctx = ctx;
   return 0;