From: Sakari Ailus <sakari.ailus@linux.intel.com>
To: linux-media@vger.kernel.org
Cc: hans@jjverkuil.nl, laurent.pinchart@ideasonboard.com,
Prabhakar <prabhakar.csengg@gmail.com>,
"Kate Hsuan" <hpa@redhat.com>,
"Dave Stevenson" <dave.stevenson@raspberrypi.com>,
"Tommaso Merciai" <tomm.merciai@gmail.com>,
"Benjamin Mugnier" <benjamin.mugnier@foss.st.com>,
"Sylvain Petinot" <sylvain.petinot@foss.st.com>,
"Christophe JAILLET" <christophe.jaillet@wanadoo.fr>,
"Julien Massot" <julien.massot@collabora.com>,
"Naushir Patuck" <naush@raspberrypi.com>,
"Yan, Dongcheng" <dongcheng.yan@intel.com>,
"Stefan Klug" <stefan.klug@ideasonboard.com>,
"Mirela Rabulea" <mirela.rabulea@nxp.com>,
"André Apitzsch" <git@apitzsch.eu>,
"Heimir Thor Sverrisson" <heimir.sverrisson@gmail.com>,
"Kieran Bingham" <kieran.bingham@ideasonboard.com>,
"Mehdi Djait" <mehdi.djait@linux.intel.com>,
"Ricardo Ribalda Delgado" <ribalda@kernel.org>,
"Hans de Goede" <hansg@kernel.org>,
"Jacopo Mondi" <jacopo.mondi@ideasonboard.com>,
"Tomi Valkeinen" <tomi.valkeinen@ideasonboard.com>,
"David Plowman" <david.plowman@raspberrypi.com>,
"Yu, Ong Hock" <ong.hock.yu@intel.com>,
"Ng, Khai Wen" <khai.wen.ng@intel.com>,
"Jai Luthra" <jai.luthra@ideasonboard.com>,
"Rishikesh Donadkar" <r-donadkar@ti.com>
Subject: [PATCH v6 08/16] media: v4l2-subdev: Move op check to sub-device op wrappers
Date: Wed, 1 Jul 2026 15:26:25 +0300 [thread overview]
Message-ID: <20260701122634.1728782-8-sakari.ailus@linux.intel.com> (raw)
In-Reply-To: <20260607215356.842932-1-sakari.ailus@linux.intel.com>
In anticipation of performing work for sub-device operation when the
driver doesn't implement one, move the check of operation existence to the
wrapper itself.
No functional change intended.
Many drivers implement set_fmt() pad op that simply returns the format
just as get_fmt() would do, usually because the driver only supports a
single one. The arguments to set_fmt() and get_fmt() are about to get
differentiated so call get_fmt() always if set_fmt() isn't supported by
the driver. This avoids changing drivers now and allows removing
boilerplate code from existing drivers.
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
drivers/media/v4l2-core/v4l2-subdev.c | 117 ++++++++++++++++++--------
include/media/v4l2-subdev.h | 6 +-
2 files changed, 84 insertions(+), 39 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 070a9e607fe3..86be4d51c9a5 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -244,20 +244,24 @@ static inline int check_format(struct v4l2_subdev *sd,
check_state(sd, state, format->which, format->pad, format->stream);
}
+#define do_subdev_call(sd, check, o, f, args...) \
+ (!(sd)->ops->o->f ? -ENOIOCTLCMD : (check) ? : \
+ (sd)->ops->o->f(sd, ##args))
+
static int call_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_format *format)
{
- return check_format(sd, state, format) ? :
- sd->ops->pad->get_fmt(sd, state, format);
+ return do_subdev_call(sd, check_format(sd, state, format), pad, get_fmt,
+ state, format);
}
static int call_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_format *format)
{
- return check_format(sd, state, format) ? :
- sd->ops->pad->set_fmt(sd, state, format);
+ return do_subdev_call(sd, check_format(sd, state, format), pad, set_fmt,
+ state, format);
}
static int call_enum_mbus_code(struct v4l2_subdev *sd,
@@ -267,9 +271,20 @@ static int call_enum_mbus_code(struct v4l2_subdev *sd,
if (!code)
return -EINVAL;
- return check_which(code->which) ? : check_pad(sd, code->pad) ? :
- check_state(sd, state, code->which, code->pad, code->stream) ? :
- sd->ops->pad->enum_mbus_code(sd, state, code);
+ /*
+ * FIXME: Convert the check below to use the ternary operator once
+ * smatch can handle it.
+ */
+ return do_subdev_call(sd,
+ ({
+ int ret = check_which(code->which);
+ if (!ret)
+ ret = check_pad(sd, code->pad);
+ if (!ret)
+ ret = check_state(sd, state, code->which,
+ code->pad, code->stream);
+ ret;
+ }), pad, enum_mbus_code, state, code);
}
static int call_enum_frame_size(struct v4l2_subdev *sd,
@@ -279,9 +294,20 @@ static int call_enum_frame_size(struct v4l2_subdev *sd,
if (!fse)
return -EINVAL;
- return check_which(fse->which) ? : check_pad(sd, fse->pad) ? :
- check_state(sd, state, fse->which, fse->pad, fse->stream) ? :
- sd->ops->pad->enum_frame_size(sd, state, fse);
+ /*
+ * FIXME: Convert the check below to use the ternary operator once
+ * smatch can handle it.
+ */
+ return do_subdev_call(sd,
+ ({
+ int ret = check_which(fse->which);
+ if (!ret)
+ ret = check_pad(sd, fse->pad);
+ if (!ret)
+ ret = check_state(sd, state, fse->which,
+ fse->pad, fse->stream);
+ ret;
+ }), pad, enum_frame_size, state, fse);
}
static int call_enum_frame_interval(struct v4l2_subdev *sd,
@@ -291,9 +317,20 @@ static int call_enum_frame_interval(struct v4l2_subdev *sd,
if (!fie)
return -EINVAL;
- return check_which(fie->which) ? : check_pad(sd, fie->pad) ? :
- check_state(sd, state, fie->which, fie->pad, fie->stream) ? :
- sd->ops->pad->enum_frame_interval(sd, state, fie);
+ /*
+ * FIXME: Convert the check below to use the ternary operator once
+ * smatch can handle it.
+ */
+ return do_subdev_call(sd,
+ ({
+ int ret = check_which(fie->which);
+ if (!ret)
+ ret = check_pad(sd, fie->pad);
+ if (!ret)
+ ret = check_state(sd, state, fie->which,
+ fie->pad, fie->stream);
+ ret;
+ }), pad, enum_frame_interval, state, fie);
}
static inline int check_selection(struct v4l2_subdev *sd,
@@ -311,16 +348,16 @@ static int call_get_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_selection *sel)
{
- return check_selection(sd, state, sel) ? :
- sd->ops->pad->get_selection(sd, state, sel);
+ return do_subdev_call(sd, check_selection(sd, state, sel),
+ pad, get_selection, state, sel);
}
static int call_set_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_selection *sel)
{
- return check_selection(sd, state, sel) ? :
- sd->ops->pad->set_selection(sd, state, sel);
+ return do_subdev_call(sd, check_selection(sd, state, sel),
+ pad, set_selection, state, sel);
}
static inline int check_frame_interval(struct v4l2_subdev *sd,
@@ -338,16 +375,16 @@ static int call_get_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_frame_interval *fi)
{
- return check_frame_interval(sd, state, fi) ? :
- sd->ops->pad->get_frame_interval(sd, state, fi);
+ return do_subdev_call(sd, check_frame_interval(sd, state, fi),
+ pad, get_frame_interval, state, fi);
}
static int call_set_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_frame_interval *fi)
{
- return check_frame_interval(sd, state, fi) ? :
- sd->ops->pad->set_frame_interval(sd, state, fi);
+ return do_subdev_call(sd, check_frame_interval(sd, state, fi),
+ pad, set_frame_interval, state, fi);
}
static int call_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
@@ -361,6 +398,9 @@ static int call_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
return -EOPNOTSUPP;
#endif
+ if (!sd->ops->pad->get_frame_desc)
+ return -ENOIOCTLCMD;
+
memset(fd, 0, sizeof(*fd));
ret = sd->ops->pad->get_frame_desc(sd, pad, fd);
@@ -405,12 +445,12 @@ static inline int check_edid(struct v4l2_subdev *sd,
static int call_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
{
- return check_edid(sd, edid) ? : sd->ops->pad->get_edid(sd, edid);
+ return do_subdev_call(sd, check_edid(sd, edid), pad, get_edid, edid);
}
static int call_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
{
- return check_edid(sd, edid) ? : sd->ops->pad->set_edid(sd, edid);
+ return do_subdev_call(sd, check_edid(sd, edid), pad, set_edid, edid);
}
static int call_s_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
@@ -419,8 +459,8 @@ static int call_s_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
if (!timings)
return -EINVAL;
- return check_pad(sd, pad) ? :
- sd->ops->pad->s_dv_timings(sd, pad, timings);
+ return do_subdev_call(sd, check_pad(sd, pad),
+ pad, s_dv_timings, pad, timings);
}
static int call_g_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
@@ -429,8 +469,8 @@ static int call_g_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
if (!timings)
return -EINVAL;
- return check_pad(sd, pad) ? :
- sd->ops->pad->g_dv_timings(sd, pad, timings);
+ return do_subdev_call(sd, check_pad(sd, pad),
+ pad, g_dv_timings, pad, timings);
}
static int call_query_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
@@ -439,8 +479,8 @@ static int call_query_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
if (!timings)
return -EINVAL;
- return check_pad(sd, pad) ? :
- sd->ops->pad->query_dv_timings(sd, pad, timings);
+ return do_subdev_call(sd, check_pad(sd, pad),
+ pad, query_dv_timings, pad, timings);
}
static int call_dv_timings_cap(struct v4l2_subdev *sd,
@@ -449,8 +489,8 @@ static int call_dv_timings_cap(struct v4l2_subdev *sd,
if (!cap)
return -EINVAL;
- return check_pad(sd, cap->pad) ? :
- sd->ops->pad->dv_timings_cap(sd, cap);
+ return do_subdev_call(sd, check_pad(sd, cap->pad),
+ pad, dv_timings_cap, cap);
}
static int call_enum_dv_timings(struct v4l2_subdev *sd,
@@ -459,8 +499,8 @@ static int call_enum_dv_timings(struct v4l2_subdev *sd,
if (!dvt)
return -EINVAL;
- return check_pad(sd, dvt->pad) ? :
- sd->ops->pad->enum_dv_timings(sd, dvt);
+ return do_subdev_call(sd, check_pad(sd, dvt->pad),
+ pad, enum_dv_timings, dvt);
}
static int call_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
@@ -468,14 +508,17 @@ static int call_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
{
memset(config, 0, sizeof(*config));
- return check_pad(sd, pad) ? :
- sd->ops->pad->get_mbus_config(sd, pad, config);
+ return do_subdev_call(sd, check_pad(sd, pad), pad, get_mbus_config,
+ pad, config);
}
static int call_s_stream(struct v4l2_subdev *sd, int enable)
{
int ret;
+ if (!sd->ops->video->s_stream)
+ return -ENOIOCTLCMD;
+
/*
* The .s_stream() operation must never be called to start or stop an
* already started or stopped subdev. Catch offenders but don't return
@@ -509,7 +552,7 @@ static int call_s_stream(struct v4l2_subdev *sd, int enable)
* wrapper handles the case where the caller does not provide the called
* subdev's state. This should be removed when all the callers are fixed.
*/
-#define DEFINE_STATE_WRAPPER(f, arg_type) \
+#define DEFINE_STATE_WRAPPER(f, arg_type) \
static int call_##f##_state(struct v4l2_subdev *sd, \
struct v4l2_subdev_state *_state, \
arg_type *arg) \
@@ -526,7 +569,7 @@ static int call_s_stream(struct v4l2_subdev *sd, int enable)
#else /* CONFIG_MEDIA_CONTROLLER */
-#define DEFINE_STATE_WRAPPER(f, arg_type) \
+#define DEFINE_STATE_WRAPPER(f, arg_type) \
static int call_##f##_state(struct v4l2_subdev *sd, \
struct v4l2_subdev_state *state, \
arg_type *arg) \
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index b797923738b6..e08615179e7b 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -1951,14 +1951,16 @@ extern const struct v4l2_subdev_ops v4l2_subdev_call_wrappers;
int __result; \
if (!__sd) \
__result = -ENODEV; \
- else if (!(__sd->ops->o && __sd->ops->o->f)) \
+ else if (!__sd->ops->o) \
__result = -ENOIOCTLCMD; \
else if (v4l2_subdev_call_wrappers.o && \
v4l2_subdev_call_wrappers.o->f) \
__result = v4l2_subdev_call_wrappers.o->f( \
__sd, ##args); \
- else \
+ else if (__sd->ops->o->f) \
__result = __sd->ops->o->f(__sd, ##args); \
+ else \
+ __result = -ENOIOCTLCMD; \
__result; \
})
--
2.47.3
next prev parent reply other threads:[~2026-07-01 12:23 UTC|newest]
Thread overview: 99+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-07 21:53 [PATCH v5 00/10] Metadata series preparation Sakari Ailus
2026-06-07 21:53 ` [PATCH v5 01/10] media: Documentation: Improve pixel rate calculation documentation Sakari Ailus
2026-06-07 21:53 ` [PATCH v5 02/10] media: imx219: Scale the vblank limits according to rate_factor Sakari Ailus
2026-06-08 7:26 ` Laurent Pinchart
2026-06-08 15:29 ` Dave Stevenson
2026-06-08 21:28 ` Laurent Pinchart
2026-06-09 5:58 ` Jai Luthra
2026-06-09 6:01 ` Jai Luthra
2026-06-10 11:48 ` Laurent Pinchart
2026-06-07 21:53 ` [PATCH v5 03/10] media: imx219: Account rate_factor in setting upper exposure limit Sakari Ailus
2026-06-07 22:05 ` sashiko-bot
2026-06-08 9:06 ` Laurent Pinchart
2026-06-08 13:44 ` Sakari Ailus
2026-06-08 15:42 ` Dave Stevenson
2026-06-08 21:38 ` Laurent Pinchart
2026-06-18 10:40 ` Sakari Ailus
2026-07-02 17:04 ` Dave Stevenson
2026-07-03 21:36 ` Sakari Ailus
2026-06-07 21:53 ` [PATCH v5 04/10] media: imx219: Make control handler ops for PIXEL_RATE NULL Sakari Ailus
2026-06-08 7:36 ` Laurent Pinchart
2026-06-08 7:53 ` Jacopo Mondi
2026-06-08 8:03 ` Laurent Pinchart
2026-06-08 8:14 ` Sakari Ailus
2026-06-08 8:24 ` Laurent Pinchart
2026-06-08 10:21 ` Sakari Ailus
2026-06-08 10:27 ` Laurent Pinchart
2026-06-08 13:47 ` Sakari Ailus
2026-06-08 14:42 ` Laurent Pinchart
2026-06-09 6:29 ` Jacopo Mondi
2026-06-09 14:55 ` Hans Verkuil
2026-06-09 15:15 ` Laurent Pinchart
2026-06-09 15:56 ` Dave Stevenson
2026-06-09 16:07 ` Laurent Pinchart
2026-06-09 16:44 ` Dave Stevenson
2026-06-07 21:53 ` [PATCH v5 05/10] media: imx219: Rename "binning" as "bin_hv" in imx219_set_pad_format Sakari Ailus
2026-06-08 15:45 ` Dave Stevenson
2026-06-07 21:53 ` [PATCH v5 06/10] media: imx219: Fix vertical blanking and exposure for analogue binning Sakari Ailus
2026-06-07 22:07 ` sashiko-bot
2026-06-08 6:58 ` Jacopo Mondi
2026-06-08 9:10 ` Laurent Pinchart
2026-06-08 14:07 ` Sakari Ailus
2026-06-08 16:23 ` Jai Luthra
2026-06-08 21:52 ` Laurent Pinchart
2026-06-10 8:27 ` Sakari Ailus
2026-06-10 8:45 ` Jai Luthra
2026-06-08 10:31 ` Jai Luthra
2026-06-08 11:19 ` Jai Luthra
2026-06-10 9:47 ` Sakari Ailus
2026-06-10 10:29 ` Jai Luthra
2026-06-10 10:57 ` Jai Luthra
2026-06-11 8:58 ` Sakari Ailus
2026-06-08 18:06 ` Dave Stevenson
2026-06-09 16:48 ` Jai Luthra
2026-06-10 10:30 ` Sakari Ailus
2026-06-10 11:59 ` Jai Luthra
2026-06-10 10:13 ` Sakari Ailus
2026-06-10 16:00 ` Jai Luthra
2026-06-08 21:01 ` Laurent Pinchart
2026-06-07 21:53 ` [PATCH v5 07/10] media: Improve enable_streams and disable_streams documentation Sakari Ailus
2026-06-08 9:29 ` Laurent Pinchart
2026-06-08 14:28 ` Sakari Ailus
2026-06-07 21:53 ` [PATCH v5 08/10] media: v4l2-subdev: Move subdev client capabilities into a new struct Sakari Ailus
2026-06-08 9:34 ` Laurent Pinchart
2026-06-08 14:35 ` Sakari Ailus
2026-06-07 21:53 ` [PATCH v5 09/10] media: v4l2-subdev: Add v4l2_subdev_get_fmt_ci() Sakari Ailus
2026-06-08 7:48 ` Laurent Pinchart
2026-06-07 21:53 ` [PATCH v5 10/10] media: v4l2-subdev: Add struct v4l2_subdev_client_info pointer to pad ops Sakari Ailus
2026-06-08 10:16 ` Laurent Pinchart
2026-06-28 14:20 ` Sakari Ailus
2026-07-01 12:26 ` [PATCH v6 00/16] Metadata series preparation Sakari Ailus
2026-07-01 12:26 ` [PATCH v6 01/16] media: Documentation: Improve pixel rate calculation documentation Sakari Ailus
2026-07-01 12:26 ` [PATCH v6 02/16] media: imx219: Account rate_factor in setting upper exposure limit Sakari Ailus
2026-07-02 17:10 ` Dave Stevenson
2026-07-01 12:26 ` [PATCH v6 03/16] media: imx219: Account for rate_factor in control steps Sakari Ailus
2026-07-02 17:09 ` Dave Stevenson
2026-07-01 12:26 ` [PATCH v6 04/16] media: imx219: The horizontal blanking step is 8 Sakari Ailus
2026-07-02 13:57 ` Dave Stevenson
2026-07-01 12:26 ` [PATCH v6 05/16] media: imx219: Rename "binning" as "bin_hv" in imx219_set_pad_format Sakari Ailus
2026-07-01 12:26 ` [PATCH v6 06/16] media: Improve enable_streams and disable_streams documentation Sakari Ailus
2026-07-01 12:26 ` [PATCH v6 07/16] media: v4l2-subdev: Move subdev client capabilities into a new struct Sakari Ailus
2026-07-01 16:17 ` Frank Li
2026-07-01 12:26 ` Sakari Ailus [this message]
2026-07-01 16:37 ` [PATCH v6 08/16] media: v4l2-subdev: Move op check to sub-device op wrappers Frank Li
2026-07-04 12:11 ` Sakari Ailus
2026-07-01 12:26 ` [PATCH v6 09/16] media: v4l2-subdev: Always call get_fmt() if set_fmt() is unavailable Sakari Ailus
2026-07-01 16:42 ` Frank Li
2026-07-04 12:15 ` Sakari Ailus
2026-07-01 12:26 ` [PATCH v6 10/16] media: rdacm20: Don't assign set_fmt() Sakari Ailus
2026-07-01 12:26 ` [PATCH v6 11/16] " Sakari Ailus
2026-07-01 12:26 ` [PATCH v6 12/16] media: gc0310: " Sakari Ailus
2026-07-01 12:26 ` [PATCH v6 13/16] media: v4l2-subdev: Add v4l2_subdev_call_ci_state_{active,try} Sakari Ailus
2026-07-01 16:57 ` Frank Li
2026-07-04 12:16 ` Sakari Ailus
2026-07-01 12:26 ` [PATCH v6 14/16] media: mt9m001: Pass sub-device state to set_selection() callback Sakari Ailus
2026-07-01 12:26 ` [PATCH v6 15/16] media: cvs: Drop comments on sub-device operations Sakari Ailus
2026-07-01 12:26 ` [PATCH v6 15/15] media: v4l2-subdev: Add struct v4l2_subdev_client_info pointer to pad ops Sakari Ailus
2026-07-01 17:00 ` Frank Li
2026-07-01 12:26 ` [PATCH v6 16/16] " Sakari Ailus
2026-07-01 17:01 ` Frank Li
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=20260701122634.1728782-8-sakari.ailus@linux.intel.com \
--to=sakari.ailus@linux.intel.com \
--cc=benjamin.mugnier@foss.st.com \
--cc=christophe.jaillet@wanadoo.fr \
--cc=dave.stevenson@raspberrypi.com \
--cc=david.plowman@raspberrypi.com \
--cc=dongcheng.yan@intel.com \
--cc=git@apitzsch.eu \
--cc=hans@jjverkuil.nl \
--cc=hansg@kernel.org \
--cc=heimir.sverrisson@gmail.com \
--cc=hpa@redhat.com \
--cc=jacopo.mondi@ideasonboard.com \
--cc=jai.luthra@ideasonboard.com \
--cc=julien.massot@collabora.com \
--cc=khai.wen.ng@intel.com \
--cc=kieran.bingham@ideasonboard.com \
--cc=laurent.pinchart@ideasonboard.com \
--cc=linux-media@vger.kernel.org \
--cc=mehdi.djait@linux.intel.com \
--cc=mirela.rabulea@nxp.com \
--cc=naush@raspberrypi.com \
--cc=ong.hock.yu@intel.com \
--cc=prabhakar.csengg@gmail.com \
--cc=r-donadkar@ti.com \
--cc=ribalda@kernel.org \
--cc=stefan.klug@ideasonboard.com \
--cc=sylvain.petinot@foss.st.com \
--cc=tomi.valkeinen@ideasonboard.com \
--cc=tomm.merciai@gmail.com \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox