All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
To: lizefan-hv44wF8Li93QT0dZR+AlfA@public.gmane.org,
	mhocko-AlSwsSmVLrQ@public.gmane.org,
	hannes-druUgvl0LCNAfugRpC6u6w@public.gmane.org,
	bsingharora-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
	kamezawa.hiroyu-+CUm20s59erQFUHtdCDX3A@public.gmane.org
Cc: containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org,
	cgroups-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Subject: [PATCH 08/12] cgroup, memcg: move cgroup->event_list[_lock] and event callbacks into memcg
Date: Thu, 15 Aug 2013 12:02:26 -0400	[thread overview]
Message-ID: <1376582550-12548-9-git-send-email-tj@kernel.org> (raw)
In-Reply-To: <1376582550-12548-1-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

cgroup_event is being moved from cgroup core to memcg and the
implementation is already moved by the previous patch.  This patch
moves the data fields and callbacks.

* cgroup->event_list[_lock] are moved to mem_cgroup.

* cftype->[un]register_event() are moved to cgroup_event.  This makes
  it impossible for individual cftype definitions to specify their
  event callbacks.  This is worked around by simply hard-coding
  filename to event callback mapping in cgroup_write_event_control().
  This is awkward and inflexible, which is actually desirable given
  that we don't want to grow more usages of this feature.

* eventfd_ctx declaration is removed from cgroup.h, which makes
  vmpressure.h miss eventfd_ctx declaration.  Include eventfd.h from
  vmpressure.h.

v2: Use file name from dentry instead of cftype.  This will allow
    removing all cftype handling in the function.

Signed-off-by: Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Cc: Johannes Weiner <hannes-druUgvl0LCNAfugRpC6u6w@public.gmane.org>
Cc: Michal Hocko <mhocko-AlSwsSmVLrQ@public.gmane.org>
Cc: Balbir Singh <bsingharora-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 include/linux/cgroup.h     | 24 -------------
 include/linux/vmpressure.h |  1 +
 kernel/cgroup.c            |  2 --
 mm/memcontrol.c            | 87 ++++++++++++++++++++++++++++++++--------------
 4 files changed, 61 insertions(+), 53 deletions(-)

diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index b83b348..d2cad3f 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -29,7 +29,6 @@ struct cgroup_subsys;
 struct inode;
 struct cgroup;
 struct css_id;
-struct eventfd_ctx;
 
 extern int cgroup_init_early(void);
 extern int cgroup_init(void);
@@ -239,10 +238,6 @@ struct cgroup {
 	struct rcu_head rcu_head;
 	struct work_struct destroy_work;
 
-	/* List of events which userspace want to receive */
-	struct list_head event_list;
-	spinlock_t event_list_lock;
-
 	/* directory xattrs */
 	struct simple_xattrs xattrs;
 };
@@ -506,25 +501,6 @@ struct cftype {
 	int (*trigger)(struct cgroup_subsys_state *css, unsigned int event);
 
 	int (*release)(struct inode *inode, struct file *file);
-
-	/*
-	 * register_event() callback will be used to add new userspace
-	 * waiter for changes related to the cftype. Implement it if
-	 * you want to provide this functionality. Use eventfd_signal()
-	 * on eventfd to send notification to userspace.
-	 */
-	int (*register_event)(struct cgroup_subsys_state *css,
-			      struct cftype *cft, struct eventfd_ctx *eventfd,
-			      const char *args);
-	/*
-	 * unregister_event() callback will be called when userspace
-	 * closes the eventfd or on cgroup removing.
-	 * This callback must be implemented, if you want provide
-	 * notification functionality.
-	 */
-	void (*unregister_event)(struct cgroup_subsys_state *css,
-				 struct cftype *cft,
-				 struct eventfd_ctx *eventfd);
 };
 
 /*
diff --git a/include/linux/vmpressure.h b/include/linux/vmpressure.h
index b239482..324ea7a 100644
--- a/include/linux/vmpressure.h
+++ b/include/linux/vmpressure.h
@@ -7,6 +7,7 @@
 #include <linux/gfp.h>
 #include <linux/types.h>
 #include <linux/cgroup.h>
+#include <linux/eventfd.h>
 
 struct vmpressure {
 	unsigned long scanned;
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 1579ca8..4368a6c 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -1353,8 +1353,6 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp)
 	INIT_LIST_HEAD(&cgrp->pidlists);
 	mutex_init(&cgrp->pidlist_mutex);
 	cgrp->dummy_css.cgroup = cgrp;
-	INIT_LIST_HEAD(&cgrp->event_list);
-	spin_lock_init(&cgrp->event_list_lock);
 	simple_xattrs_init(&cgrp->xattrs);
 }
 
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index ef75925..9b833e1 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -261,6 +261,22 @@ struct cgroup_event {
 	 */
 	struct list_head list;
 	/*
+	 * register_event() callback will be used to add new userspace
+	 * waiter for changes related to this event.  Use eventfd_signal()
+	 * on eventfd to send notification to userspace.
+	 */
+	int (*register_event)(struct cgroup_subsys_state *css,
+			      struct cftype *cft, struct eventfd_ctx *eventfd,
+			      const char *args);
+	/*
+	 * unregister_event() callback will be called when userspace closes
+	 * the eventfd or on cgroup removing.  This callback must be set,
+	 * if you want provide notification functionality.
+	 */
+	void (*unregister_event)(struct cgroup_subsys_state *css,
+				 struct cftype *cft,
+				 struct eventfd_ctx *eventfd);
+	/*
 	 * All fields below needed to unregister event when
 	 * userspace closes eventfd.
 	 */
@@ -373,6 +389,10 @@ struct mem_cgroup {
 	atomic_t	numainfo_updating;
 #endif
 
+	/* List of events which userspace want to receive */
+	struct list_head event_list;
+	spinlock_t event_list_lock;
+
 	struct mem_cgroup_per_node *nodeinfo[0];
 	/* WARNING: nodeinfo must be the last member here */
 };
@@ -5963,7 +5983,7 @@ static void cgroup_event_remove(struct work_struct *work)
 
 	remove_wait_queue(event->wqh, &event->wait);
 
-	event->cft->unregister_event(css, event->cft, event->eventfd);
+	event->unregister_event(css, event->cft, event->eventfd);
 
 	/* Notify userspace the event is going away. */
 	eventfd_signal(event->eventfd, 1);
@@ -5983,7 +6003,7 @@ static int cgroup_event_wake(wait_queue_t *wait, unsigned mode,
 {
 	struct cgroup_event *event = container_of(wait,
 			struct cgroup_event, wait);
-	struct cgroup *cgrp = event->css->cgroup;
+	struct mem_cgroup *memcg = mem_cgroup_from_css(event->css);
 	unsigned long flags = (unsigned long)key;
 
 	if (flags & POLLHUP) {
@@ -5996,7 +6016,7 @@ static int cgroup_event_wake(wait_queue_t *wait, unsigned mode,
 		 * side will require wqh->lock via remove_wait_queue(),
 		 * which we hold.
 		 */
-		spin_lock(&cgrp->event_list_lock);
+		spin_lock(&memcg->event_list_lock);
 		if (!list_empty(&event->list)) {
 			list_del_init(&event->list);
 			/*
@@ -6005,7 +6025,7 @@ static int cgroup_event_wake(wait_queue_t *wait, unsigned mode,
 			 */
 			schedule_work(&event->remove);
 		}
-		spin_unlock(&cgrp->event_list_lock);
+		spin_unlock(&memcg->event_list_lock);
 	}
 
 	return 0;
@@ -6030,12 +6050,13 @@ static void cgroup_event_ptable_queue_proc(struct file *file,
 static int cgroup_write_event_control(struct cgroup_subsys_state *css,
 				      struct cftype *cft, const char *buffer)
 {
-	struct cgroup *cgrp = css->cgroup;
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
 	struct cgroup_event *event;
 	struct cgroup_subsys_state *cfile_css;
 	unsigned int efd, cfd;
 	struct file *efile;
 	struct file *cfile;
+	const char *name;
 	char *endp;
 	int ret;
 
@@ -6090,6 +6111,31 @@ static int cgroup_write_event_control(struct cgroup_subsys_state *css,
 	}
 
 	/*
+	 * Determine the event callbacks and set them in @event.  This used
+	 * to be done via struct cftype but cgroup core no longer knows
+	 * about these events.  The following is crude but the whole thing
+	 * is for compatibility anyway.
+	 */
+	name = cfile->f_dentry->d_name.name;
+
+	if (!strcmp(name, "memory.usage_in_bytes")) {
+		event->register_event = mem_cgroup_usage_register_event;
+		event->unregister_event = mem_cgroup_usage_unregister_event;
+	} else if (!strcmp(name, "memory.oom_control")) {
+		event->register_event = mem_cgroup_oom_register_event;
+		event->unregister_event = mem_cgroup_oom_unregister_event;
+	} else if (!strcmp(name, "memory.pressure_level")) {
+		event->register_event = vmpressure_register_event;
+		event->unregister_event = vmpressure_unregister_event;
+	} else if (!strcmp(name, "memory.memsw.usage_in_bytes")) {
+		event->register_event = mem_cgroup_usage_register_event;
+		event->unregister_event = mem_cgroup_usage_unregister_event;
+	} else {
+		ret = -EINVAL;
+		goto out_put_cfile;
+	}
+
+	/*
 	 * Verify @cfile should belong to @css.  Also, remaining events are
 	 * automatically removed on cgroup destruction but the removal is
 	 * asynchronous, so take an extra ref on @css.
@@ -6105,21 +6151,15 @@ static int cgroup_write_event_control(struct cgroup_subsys_state *css,
 	if (ret)
 		goto out_put_cfile;
 
-	if (!event->cft->register_event || !event->cft->unregister_event) {
-		ret = -EINVAL;
-		goto out_put_css;
-	}
-
-	ret = event->cft->register_event(css, event->cft,
-			event->eventfd, buffer);
+	ret = event->register_event(css, event->cft, event->eventfd, buffer);
 	if (ret)
 		goto out_put_css;
 
 	efile->f_op->poll(efile, &event->pt);
 
-	spin_lock(&cgrp->event_list_lock);
-	list_add(&event->list, &cgrp->event_list);
-	spin_unlock(&cgrp->event_list_lock);
+	spin_lock(&memcg->event_list_lock);
+	list_add(&event->list, &memcg->event_list);
+	spin_unlock(&memcg->event_list_lock);
 
 	fput(cfile);
 	fput(efile);
@@ -6145,8 +6185,6 @@ static struct cftype mem_cgroup_files[] = {
 		.name = "usage_in_bytes",
 		.private = MEMFILE_PRIVATE(_MEM, RES_USAGE),
 		.read = mem_cgroup_read,
-		.register_event = mem_cgroup_usage_register_event,
-		.unregister_event = mem_cgroup_usage_unregister_event,
 	},
 	{
 		.name = "max_usage_in_bytes",
@@ -6206,14 +6244,10 @@ static struct cftype mem_cgroup_files[] = {
 		.name = "oom_control",
 		.read_map = mem_cgroup_oom_control_read,
 		.write_u64 = mem_cgroup_oom_control_write,
-		.register_event = mem_cgroup_oom_register_event,
-		.unregister_event = mem_cgroup_oom_unregister_event,
 		.private = MEMFILE_PRIVATE(_OOM_TYPE, OOM_CONTROL),
 	},
 	{
 		.name = "pressure_level",
-		.register_event = vmpressure_register_event,
-		.unregister_event = vmpressure_unregister_event,
 	},
 #ifdef CONFIG_NUMA
 	{
@@ -6261,8 +6295,6 @@ static struct cftype memsw_cgroup_files[] = {
 		.name = "memsw.usage_in_bytes",
 		.private = MEMFILE_PRIVATE(_MEMSWAP, RES_USAGE),
 		.read = mem_cgroup_read,
-		.register_event = mem_cgroup_usage_register_event,
-		.unregister_event = mem_cgroup_usage_unregister_event,
 	},
 	{
 		.name = "memsw.max_usage_in_bytes",
@@ -6453,6 +6485,8 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
 	mutex_init(&memcg->thresholds_lock);
 	spin_lock_init(&memcg->move_lock);
 	vmpressure_init(&memcg->vmpressure);
+	INIT_LIST_HEAD(&memcg->event_list);
+	spin_lock_init(&memcg->event_list_lock);
 
 	return &memcg->css;
 
@@ -6525,7 +6559,6 @@ static void mem_cgroup_invalidate_reclaim_iterators(struct mem_cgroup *memcg)
 static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
 {
 	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
-	struct cgroup *cgrp = css->cgroup;
 	struct cgroup_event *event, *tmp;
 
 	/*
@@ -6533,12 +6566,12 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
 	 * Notify userspace about cgroup removing only after rmdir of cgroup
 	 * directory to avoid race between userspace and kernelspace.
 	 */
-	spin_lock(&cgrp->event_list_lock);
-	list_for_each_entry_safe(event, tmp, &cgrp->event_list, list) {
+	spin_lock(&memcg->event_list_lock);
+	list_for_each_entry_safe(event, tmp, &memcg->event_list, list) {
 		list_del_init(&event->list);
 		schedule_work(&event->remove);
 	}
-	spin_unlock(&cgrp->event_list_lock);
+	spin_unlock(&memcg->event_list_lock);
 
 	kmem_cgroup_css_offline(memcg);
 
-- 
1.8.3.1

  parent reply	other threads:[~2013-08-15 16:02 UTC|newest]

Thread overview: 73+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-08-15 16:02 [PATCHSET v2 cgroup/for-3.12] cgroup: make cgroup_event specific to memcg Tejun Heo
     [not found] ` <1376582550-12548-1-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2013-08-15 16:02   ` [PATCH 01/12] cgroup: rename cgroup_css_from_dir() to css_from_dir() and update its syntax Tejun Heo
2013-08-15 16:02   ` Tejun Heo
2013-08-15 16:02   ` [PATCH 02/12] cgroup: make cgroup_css() take cgroup_subsys * instead and allow NULL subsys Tejun Heo
2013-08-15 16:02   ` Tejun Heo
2013-08-15 16:02   ` [PATCH 03/12] cgroup: implement CFTYPE_NO_PREFIX Tejun Heo
2013-08-15 16:02   ` Tejun Heo
2013-08-15 16:02   ` [PATCH 04/12] cgroup: make cgroup_event hold onto cgroup_subsys_state instead of cgroup Tejun Heo
2013-08-15 16:02   ` Tejun Heo
2013-08-15 16:02   ` [PATCH 05/12] cgroup: make cgroup_write_event_control() use css_from_dir() instead of __d_cgrp() Tejun Heo
     [not found]     ` <1376582550-12548-6-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2013-08-26 22:38       ` Tejun Heo
2013-08-15 16:02   ` Tejun Heo
2013-08-15 16:02   ` [PATCH 06/12] cgroup, memcg: move cgroup_event implementation to memcg Tejun Heo
2013-08-15 16:02   ` Tejun Heo
     [not found]     ` <1376582550-12548-7-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2013-08-27 14:20       ` Michal Hocko
     [not found]         ` <20130827142002.GC13302-2MMpYkNvuYDjFM9bn6wA6Q@public.gmane.org>
2013-08-27 20:00           ` Tejun Heo
     [not found]             ` <20130827200002.GD12212-9pTldWuhBndy/B6EtB590w@public.gmane.org>
2013-08-28 14:29               ` Michal Hocko
2013-08-28 14:29               ` Michal Hocko
2013-08-27 20:00           ` Tejun Heo
2013-08-29 18:19       ` [PATCH v3 " Tejun Heo
2013-08-29 18:19       ` Tejun Heo
     [not found]         ` <20130829181911.GA8517-9pTldWuhBndy/B6EtB590w@public.gmane.org>
2013-08-30 10:47           ` Michal Hocko
     [not found]             ` <20130830104755.GC28658-2MMpYkNvuYDjFM9bn6wA6Q@public.gmane.org>
2013-08-30 10:52               ` Tejun Heo
2013-08-30 10:52               ` Tejun Heo
     [not found]                 ` <20130830105210.GA30910-Gd/HAXX7CRxy/B6EtB590w@public.gmane.org>
2013-08-30 11:05                   ` Michal Hocko
2013-08-30 11:05                   ` Michal Hocko
2013-08-30 10:47           ` Michal Hocko
2013-08-15 16:02   ` [PATCH 07/12] memcg: cgroup_write_event_control() now knows @css is for memcg Tejun Heo
2013-08-15 16:02   ` Tejun Heo
2013-08-15 16:02   ` [PATCH 08/12] cgroup, memcg: move cgroup->event_list[_lock] and event callbacks into memcg Tejun Heo
2013-08-15 16:02   ` Tejun Heo [this message]
     [not found]     ` <1376582550-12548-9-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2013-08-30 11:08       ` Michal Hocko
     [not found]         ` <20130830110846.GB31605-2MMpYkNvuYDjFM9bn6wA6Q@public.gmane.org>
2013-09-03 21:56           ` Tejun Heo
     [not found]             ` <20130903215646.GA31091-9pTldWuhBndy/B6EtB590w@public.gmane.org>
2013-09-04  7:11               ` Michal Hocko
2013-09-03 21:56           ` Tejun Heo
2013-08-15 16:02   ` [PATCH 09/12] memcg: remove cgroup_event->cft Tejun Heo
2013-08-15 16:02   ` Tejun Heo
     [not found]     ` <1376582550-12548-10-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2013-08-30 11:13       ` Michal Hocko
2013-08-15 16:02   ` [PATCH 10/12] memcg: make cgroup_event deal with mem_cgroup instead of cgroup_subsys_state Tejun Heo
     [not found]     ` <1376582550-12548-11-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2013-08-30 11:15       ` Michal Hocko
2013-08-30 11:15       ` Michal Hocko
2013-08-15 16:02   ` Tejun Heo
2013-08-15 16:02   ` [PATCH 11/12] memcg: rename cgroup_event to mem_cgroup_event Tejun Heo
     [not found]     ` <1376582550-12548-12-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2013-08-23  3:42       ` Li Zefan
2013-08-23  3:42       ` Li Zefan
     [not found]         ` <5216DA08.8040406-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
2013-08-23 16:40           ` Tejun Heo
2013-08-30 11:19       ` Michal Hocko
2013-08-30 11:19       ` Michal Hocko
2013-08-15 16:02   ` Tejun Heo
2013-08-15 16:02   ` [PATCH 12/12] cgroup: unexport cgroup_css() and remove __file_cft() Tejun Heo
2013-08-15 16:02   ` Tejun Heo
2013-08-21 20:12   ` [PATCHSET v2 cgroup/for-3.12] cgroup: make cgroup_event specific to memcg Tejun Heo
2013-08-21 20:12   ` Tejun Heo
     [not found]     ` <20130821201239.GB2436-Gd/HAXX7CRxy/B6EtB590w@public.gmane.org>
2013-08-23  3:43       ` Li Zefan
     [not found]         ` <5216DA6F.3080508-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
2013-08-23 12:31           ` Tejun Heo
2013-08-23  3:43       ` Li Zefan
2013-08-24 18:20       ` Michal Hocko
2013-08-24 18:20       ` Michal Hocko
     [not found]         ` <20130824182005.GA15897-2MMpYkNvuYDjFM9bn6wA6Q@public.gmane.org>
2013-08-24 18:25           ` Tejun Heo
2013-08-26 14:15   ` Kirill A. Shutemov
     [not found]     ` <20130826141536.GA14985-oKw7cIdHH8eLwutG50LtGA@public.gmane.org>
2013-08-26 15:17       ` Tejun Heo
     [not found]         ` <20130826151747.GD25171-Gd/HAXX7CRxy/B6EtB590w@public.gmane.org>
2013-08-26 14:29           ` Kirill A. Shutemov
     [not found]             ` <20130826142918.GB14985-oKw7cIdHH8eLwutG50LtGA@public.gmane.org>
2013-08-26 15:30               ` Tejun Heo
2013-08-26 15:30               ` Tejun Heo
     [not found]                 ` <20130826153028.GE25171-Gd/HAXX7CRxy/B6EtB590w@public.gmane.org>
2013-08-26 14:35                   ` Kirill A. Shutemov
2013-08-26 14:15   ` Kirill A. Shutemov
2013-11-10  4:48   ` Tejun Heo
2013-11-10  4:48   ` Tejun Heo
     [not found]     ` <20131110044811.GA25112-9pTldWuhBndy/B6EtB590w@public.gmane.org>
2013-11-11 14:10       ` Michal Hocko
     [not found]         ` <20131111141010.GB14497-2MMpYkNvuYDjFM9bn6wA6Q@public.gmane.org>
2013-11-22 23:39           ` Tejun Heo
2013-11-22 23:39           ` Tejun Heo
     [not found]             ` <20131122233947.GH8981-9pTldWuhBndy/B6EtB590w@public.gmane.org>
2013-11-25 10:33               ` Michal Hocko
2013-11-25 10:33               ` Michal Hocko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1376582550-12548-9-git-send-email-tj@kernel.org \
    --to=tj-dgejt+ai2ygdnm+yrofe0a@public.gmane.org \
    --cc=bsingharora-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
    --cc=cgroups-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org \
    --cc=hannes-druUgvl0LCNAfugRpC6u6w@public.gmane.org \
    --cc=kamezawa.hiroyu-+CUm20s59erQFUHtdCDX3A@public.gmane.org \
    --cc=lizefan-hv44wF8Li93QT0dZR+AlfA@public.gmane.org \
    --cc=mhocko-AlSwsSmVLrQ@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.