From: Mathura_Kumar <academic1mathura@gmail.com>
To: criu@lists.linux.dev
Cc: academic1mathura@gmail.com, avagin@gmail.com,
ptikhomirov@virtuozzo.com, rstoyanov@fedoraproject.org
Subject: [PATCH v3 5/5]Added bitmask flag and user struct argument size as input for extensibility
Date: Wed, 8 Apr 2026 15:21:33 +0530 [thread overview]
Message-ID: <20260408095219.26350-6-academic1mathura@gmail.com> (raw)
In-Reply-To: <20260408095219.26350-1-academic1mathura@gmail.com>
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=yes, Size: 17604 bytes --]
Signed-off-by: Mathura_Kumar <academic1mathura@gmail.com>
---
Documentation/userspace-api/ipc.rst | 24 ++--
include/linux/compat.h | 4 +-
include/linux/syscalls.h | 4 +-
ipc/mqueue.c | 179 +++++++++++++++-----------
kernel/sys_ni.c | 2 +
tools/testing/selftests/ipc/mq_peek.c | 54 ++++++--
6 files changed, 163 insertions(+), 104 deletions(-)
diff --git a/Documentation/userspace-api/ipc.rst b/Documentation/userspace-api/ipc.rst
index 14a5f0ce7230..3fc46621b5c6 100644
--- a/Documentation/userspace-api/ipc.rst
+++ b/Documentation/userspace-api/ipc.rst
@@ -54,13 +54,10 @@ SYNOPSIS
ssize_t mq_timedreceive2(mqd_t mqdes,
struct mq_timedreceive2_args *uargs,
- unsigned int flags,
+ size_t usize, unsigned int flags,
unsigned long index,
const struct timespec *abs_timeout);
-Note: No glibc wrapper exists for this syscall. Callers must invoke it
-directly using syscall(2).
-
DESCRIPTION
mq_timedreceive2() receives or peeks at a message from the
message queue referred to by the descriptor mqdes.
@@ -78,14 +75,19 @@ DESCRIPTION
If not NULL, the priority of the received message is
stored here.
+ The usize argument take size of struct to make mq_timedreceive2_args
+ extensible in future if required.
+
The flags argument controls receive behavior. The following
flag is defined:
``MQ_PEEK``
Copy the message into msg_ptr without removing it from
- the queue. The queue is not modified. If this flag is
- not set, behavior is identical to mq_timedreceive() and
- the message is consumed.
+ the queue. The queue is not modified.
+
+ ``MQ_RECV``
+ Copy the message into msg_ptr and consume a single message by
+ invoking the existing do_mq_timedreceive() handler.
The index argument selects which message to operate on within
the priority-ordered queue. index 0 refers to the highest
@@ -116,7 +118,7 @@ ERRORS
``EINVAL``
flags contains an unknown value, or index is nonzero
- and MQ_PEEK is not set.
+ and contradictory flag was passed.
``EMSGSIZE``
msg_len is less than the mq_msgsize attribute of
@@ -137,7 +139,7 @@ consolidated into struct mq_timedreceive2_args rather than passed
as individual syscall arguments. Due to limited six arguments,
The original mq_timedreceive() consumes all six slots,
leaving no room for extension. Consolidating the buffer parameters
-into a struct recovers two argument slots for flags and index while
+into a struct recovers three argument slots for flags, size and index while
keeping the interface clean and forward-compatible.
Future extensions can be made by adding new flag bits without
@@ -220,3 +222,7 @@ Tests for mq_timedreceive2() should cover the following:
threads returns consistent results and does not corrupt queue
state. Verify that a concurrent mq_receive() and mq_peek() do
not race.
+
+9) Contradictory Operation: verify that simultaneous inconsistent flag work as
+ expected.
+
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 9f5ca26e76d8..837a59559fa5 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -803,8 +803,8 @@ asmlinkage long compat_sys_pwritev64v2(unsigned long fd,
unsigned long vlen, loff_t pos, rwf_t flags);
#endif
asmlinkage long compat_sys_mq_timedreceive2(mqd_t mqdes, struct compat_mq_timedreceive2_args __user *uargs,
- unsigned int flags, unsigned long index,
- struct old_timespec32 __user *abs_timeout);
+ size_t usize, unsigned int flags, const unsigned long index,
+ const struct old_timespec32 __user *abs_timeout);
/*
* Deprecated system calls which are still defined in
* include/uapi/asm-generic/unistd.h and wanted by >= 1 arch
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 993e570c90ab..e5b544464a44 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -750,8 +750,8 @@ asmlinkage long sys_mq_timedsend_time32(mqd_t mqdes,
const struct old_timespec32 __user *u_abs_timeout);
asmlinkage long
sys_mq_timedreceive2(mqd_t mqdes, struct mq_timedreceive2_args __user *uargs,
- unsigned int flags, unsigned long index,
- struct __kernel_timespec __user *abs_timeout);
+ size_t usize, unsigned int flags, const unsigned long index,
+ const struct __kernel_timespec __user *abs_timeout);
asmlinkage long sys_msgget(key_t key, int msgflg);
asmlinkage long sys_old_msgctl(int msqid, int cmd, struct msqid_ds __user *buf);
asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf);
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 78dc414967a2..2d4c285e4aa1 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -38,6 +38,7 @@
#include <linux/sched/wake_q.h>
#include <linux/sched/signal.h>
#include <linux/sched/user.h>
+#include <linux/uaccess.h>
#include <net/sock.h>
#include "util.h"
@@ -53,7 +54,10 @@ struct mqueue_fs_context {
#define SEND 0
#define RECV 1
-#define MQ_PEEK 2
+
+#define MQ_PEEK 0x02
+#define MQ_RECV 0x04
+#define MQ_VALID_FLAGS (MQ_PEEK | MQ_RECV)
#define STATE_NONE 0
#define STATE_READY 1
@@ -1266,78 +1270,85 @@ static int do_mq_timedreceive2(mqd_t mqdes, struct mq_timedreceive2_args *args,
struct inode *inode;
struct mqueue_inode_info *info;
- if (!(flags & MQ_PEEK)) {
- return do_mq_timedreceive(mqdes, args->msg_ptr, args->msg_len,
- args->msg_prio, ts);
- }
- audit_mq_sendrecv(mqdes, args->msg_len, 0, ts);
- CLASS(fd, f)(mqdes);
- if (fd_empty(f))
- return -EBADF;
-
- inode = file_inode(fd_file(f));
- if (unlikely(fd_file(f)->f_op != &mqueue_file_operations))
- return -EBADF;
- info = MQUEUE_I(inode);
- audit_file(fd_file(f));
+ if (flags & (~MQ_VALID_FLAGS))
+ return -EINVAL;
+ if ((flags & MQ_RECV) && (flags & MQ_PEEK))
+ return -EINVAL;
+ if (flags & MQ_PEEK) {
+ audit_mq_sendrecv(mqdes, args->msg_len, 0, ts);
+ CLASS(fd, f)(mqdes);
+ if (fd_empty(f))
+ return -EBADF;
+
+ inode = file_inode(fd_file(f));
+ if (unlikely(fd_file(f)->f_op != &mqueue_file_operations))
+ return -EBADF;
+ info = MQUEUE_I(inode);
+ audit_file(fd_file(f));
- if (unlikely(!(fd_file(f)->f_mode & FMODE_READ)))
- return -EBADF;
+ if (unlikely(!(fd_file(f)->f_mode & FMODE_READ)))
+ return -EBADF;
- if (unlikely(args->msg_len < info->attr.mq_msgsize))
- return -EMSGSIZE;
- if (index >= (unsigned long)info->attr.mq_maxmsg)
- return -ENOENT;
+ if (unlikely(args->msg_len < info->attr.mq_msgsize))
+ return -EMSGSIZE;
+ if (index >= (unsigned long)info->attr.mq_maxmsg)
+ return -ENOENT;
- spin_lock(&info->lock);
- if (info->attr.mq_curmsgs == 0) {
- spin_unlock(&info->lock);
- return -EAGAIN;
- }
- msg_ptr = mq_peek_index(info, index);
- if (!msg_ptr) {
+ spin_lock(&info->lock);
+ if (info->attr.mq_curmsgs == 0) {
+ spin_unlock(&info->lock);
+ return -EAGAIN;
+ }
+ msg_ptr = mq_peek_index(info, index);
+ if (!msg_ptr) {
+ spin_unlock(&info->lock);
+ return -ENOENT;
+ }
+ k_m_type = msg_ptr->m_type;
+ k_m_ts = msg_ptr->m_ts;
spin_unlock(&info->lock);
- return -ENOENT;
- }
- k_m_type = msg_ptr->m_type;
- k_m_ts = msg_ptr->m_ts;
- spin_unlock(&info->lock);
- k_msg_buffer = alloc_msg(k_m_ts);
- if (!k_msg_buffer)
- return -ENOMEM;
+ k_msg_buffer = alloc_msg(k_m_ts);
+ if (!k_msg_buffer)
+ return -ENOMEM;
/*
* Two spin locks are necessary here. We are avoiding atomic memory
* allocation and premature allocation before confirming that
* a message actually exists to peek.
*/
- spin_lock(&info->lock);
- msg_ptr = mq_peek_index(info, index);
- if (!msg_ptr || msg_ptr->m_type != k_m_type ||
- msg_ptr->m_ts != k_m_ts) {
- spin_unlock(&info->lock);
- free_msg(k_msg_buffer);
- return -EAGAIN;
- }
- if (IS_ERR(copy_msg(msg_ptr, k_msg_buffer, k_m_ts))) {
+ spin_lock(&info->lock);
+ msg_ptr = mq_peek_index(info, index);
+ if (!msg_ptr || msg_ptr->m_type != k_m_type ||
+ msg_ptr->m_ts != k_m_ts) {
+ spin_unlock(&info->lock);
+ free_msg(k_msg_buffer);
+ return -EAGAIN;
+ }
+ if (IS_ERR(copy_msg(msg_ptr, k_msg_buffer, k_m_ts))) {
+ spin_unlock(&info->lock);
+ free_msg(k_msg_buffer);
+ return -EINVAL;
+ }
spin_unlock(&info->lock);
- free_msg(k_msg_buffer);
- return -EINVAL;
- }
- spin_unlock(&info->lock);
- ret = k_msg_buffer->m_ts;
- if (args->msg_prio && put_user(k_m_type, args->msg_prio)) {
+ ret = k_msg_buffer->m_ts;
+ if (args->msg_prio && put_user(k_m_type, args->msg_prio)) {
+ free_msg(k_msg_buffer);
+ return -EFAULT;
+ }
+ if (store_msg(args->msg_ptr, k_msg_buffer, k_m_ts)) {
+ free_msg(k_msg_buffer);
+ return -EFAULT;
+ }
free_msg(k_msg_buffer);
- return -EFAULT;
+ return ret;
}
- if (store_msg(args->msg_ptr, k_msg_buffer, k_m_ts)) {
- free_msg(k_msg_buffer);
- return -EFAULT;
+ if (flags & MQ_RECV) {
+ return do_mq_timedreceive(mqdes, args->msg_ptr, args->msg_len, args->msg_prio, ts);
}
- free_msg(k_msg_buffer);
- return ret;
+
+ return -EINVAL;
}
SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
@@ -1368,17 +1379,22 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
return do_mq_timedreceive(mqdes, u_msg_ptr, msg_len, u_msg_prio, p);
}
-SYSCALL_DEFINE5(mq_timedreceive2, mqd_t, mqdes,
- struct mq_timedreceive2_args __user *, uargs, unsigned int,
- flags, const unsigned long, index,
- const struct __kernel_timespec __user *, u_abs_timeout)
+SYSCALL_DEFINE6(mq_timedreceive2, mqd_t, mqdes,
+ struct mq_timedreceive2_args __user *, uargs, size_t, usize,
+ unsigned int, flags, const unsigned long, index,
+ const struct __kernel_timespec __user *, u_abs_timeout)
{
- struct mq_timedreceive2_args args;
+ struct mq_timedreceive2_args k_args;
struct timespec64 ts, *p = NULL;
+ int err;
- if (copy_from_user(&args, uargs, sizeof(args)))
- return -EFAULT;
-
+ if (unlikely(usize < sizeof(struct mq_timedreceive2_args)))
+ return -EINVAL;
+ if (unlikely(usize > PAGE_SIZE))
+ return -E2BIG;
+ err = copy_struct_from_user(&k_args, sizeof(k_args), uargs, usize);
+ if (err)
+ return err;
if (u_abs_timeout) {
int res = prepare_timeout(u_abs_timeout, &ts);
@@ -1386,7 +1402,7 @@ SYSCALL_DEFINE5(mq_timedreceive2, mqd_t, mqdes,
return res;
p = &ts;
}
- return do_mq_timedreceive2(mqdes, &args, flags, index, p);
+ return do_mq_timedreceive2(mqdes, &k_args, flags, index, p);
}
/*
@@ -1633,12 +1649,18 @@ static inline int put_compat_mq_attr(const struct mq_attr *attr,
}
static inline int get_compat_mq_args(struct mq_timedreceive2_args *args,
- struct compat_mq_timedreceive2_args __user *uargs)
+ struct compat_mq_timedreceive2_args __user *uargs, size_t usize)
{
struct compat_mq_timedreceive2_args v;
+ int err;
- if (copy_from_user(&v, uargs, sizeof(v)))
- return -EFAULT;
+ if (unlikely(usize < sizeof(struct compat_mq_timedreceive2_args)))
+ return -EINVAL;
+ if (unlikely(usize > PAGE_SIZE))
+ return -E2BIG;
+ err = copy_struct_from_user(&v, sizeof(v), uargs, usize);
+ if (err)
+ return err;
memset(args, 0, sizeof(*args));
args->msg_len = (size_t)v.msg_len;
@@ -1700,17 +1722,18 @@ COMPAT_SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
return 0;
}
-COMPAT_SYSCALL_DEFINE5(mq_timedreceive2, mqd_t, mqdes,
- struct compat_mq_timedreceive2_args __user *, uargs,
- unsigned int, flags, const unsigned long, index,
- const struct old_timespec32 __user *, u_abs_timeout)
+COMPAT_SYSCALL_DEFINE6(mq_timedreceive2, mqd_t, mqdes,
+ struct compat_mq_timedreceive2_args __user *, uargs, size_t, usize,
+ unsigned int, flags, const unsigned long, index,
+ const struct old_timespec32 __user *, u_abs_timeout)
{
- struct mq_timedreceive2_args args;
+ struct mq_timedreceive2_args k_args;
struct timespec64 ts, *p = NULL;
+ int err;
- if (get_compat_mq_args(&args, uargs))
- return -EFAULT;
-
+ err = get_compat_mq_args(&k_args, uargs, usize);
+ if (err)
+ return err;
if (u_abs_timeout) {
int res = compat_prepare_timeout(u_abs_timeout, &ts);
@@ -1718,7 +1741,7 @@ COMPAT_SYSCALL_DEFINE5(mq_timedreceive2, mqd_t, mqdes,
return res;
p = &ts;
}
- return do_mq_timedreceive2(mqdes, &args, flags, index, p);
+ return do_mq_timedreceive2(mqdes, &k_args, flags, index, p);
}
#endif
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 658d6b8274b3..af956bc4e6fe 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -391,6 +391,8 @@ COND_SYSCALL(setuid16);
/* restartable sequence */
COND_SYSCALL(rseq);
COND_SYSCALL(rseq_slice_yield);
+
+/* ipc */
COND_SYSCALL(mq_timedreceive2);
COND_SYSCALL(uretprobe);
diff --git a/tools/testing/selftests/ipc/mq_peek.c b/tools/testing/selftests/ipc/mq_peek.c
index d08596ae6e1c..0ec3f2fca82c 100644
--- a/tools/testing/selftests/ipc/mq_peek.c
+++ b/tools/testing/selftests/ipc/mq_peek.c
@@ -40,7 +40,8 @@
#endif
#endif
-#define MQ_PEEK 2U
+#define MQ_PEEK 0x02
+#define MQ_RECV 0x04
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
@@ -52,11 +53,13 @@ struct mq_timedreceive2_args {
char *msg_ptr;
};
-static long mq_timedreceive2(mqd_t mqdes, struct mq_timedreceive2_args *uargs,
- unsigned int flags, unsigned long index,
+#define u_struct_size sizeof(struct mq_timedreceive2_args)
+
+static long mq_timedreceive2(mqd_t mqdes, struct mq_timedreceive2_args *uargs, size_t usize,
+ unsigned int flags, const unsigned long index,
const struct timespec *timeout)
{
- return syscall(__NR_mq_timedreceive2, (long)mqdes, uargs, (long)flags,
+ return syscall(__NR_mq_timedreceive2, mqdes, uargs, usize, flags,
index, timeout);
}
@@ -109,7 +112,7 @@ static long peek(mqd_t mqd, unsigned long index, char *buf, size_t bufsz,
.msg_prio = prio,
.msg_ptr = buf,
};
- return mq_timedreceive2(mqd, &args, MQ_PEEK, index, NULL);
+ return mq_timedreceive2(mqd, &args, u_struct_size, MQ_PEEK, index, NULL);
}
static long queue_depth(mqd_t mqd)
@@ -226,7 +229,7 @@ static void test_peek_buffer_too_small(void)
send_msg(mqd, PRIO_HIGH, "hello", 5);
- ret = mq_timedreceive2(mqd, &args, MQ_PEEK, 0, NULL);
+ ret = mq_timedreceive2(mqd, &args, u_struct_size, MQ_PEEK, 0, NULL);
if (ret == -1 && errno == EMSGSIZE)
ksft_test_result_pass("peek with small buf [EMSGSIZE]\n");
else
@@ -246,11 +249,10 @@ static void test_peek_bad_msg_ptr(void)
.msg_prio = &prio,
.msg_ptr = (char *)0x1,
};
-
long ret;
send_msg(mqd, PRIO_HIGH, "payload", 7);
- ret = mq_timedreceive2(mqd, &args, MQ_PEEK, 0, NULL);
+ ret = mq_timedreceive2(mqd, &args, u_struct_size, MQ_PEEK, 0, NULL);
if (ret == -1 && errno == EFAULT)
ksft_test_result_pass("peek bad msg_ptr [EFAULT]\n");
else
@@ -588,7 +590,7 @@ static void test_no_peek_flag_is_receive(void)
send_msg(mqd, PRIO_HIGH, "consume-me", 10);
- ret = mq_timedreceive2(mqd, &args, 0, 0, NULL);
+ ret = mq_timedreceive2(mqd, &args, u_struct_size, MQ_RECV, 0, NULL);
if (ret < 0) {
ksft_test_result_fail("no-peek receive failed: ret=%ld errno=%d\n", ret, errno);
mq_close(mqd);
@@ -615,8 +617,7 @@ static void *receiver_thread(void *arg)
ssize_t r;
while ((r = mq_receive(ctx->mqd, buf, sizeof(buf), &prio)) > 0)
- ;
-
+ ;
return NULL;
}
@@ -680,7 +681,7 @@ static void test_peek_null_prio_ptr(void)
send_msg(mqd, PRIO_MED, "no-prio-needed", 14);
- ret = mq_timedreceive2(mqd, &args, MQ_PEEK, 0, NULL);
+ ret = mq_timedreceive2(mqd, &args, u_struct_size, MQ_PEEK, 0, NULL);
if (ret >= 0)
ksft_test_result_pass("peek with NULL msg_prio ptr: OK\n");
else
@@ -734,6 +735,32 @@ static void test_peek_priority_matches_receive(void)
mq_close(mqd);
}
+static void test_contradictory_operation(void)
+{
+ mqd_t mqd = open_queue("contra_op", MAX_MSG_SIZE);
+ char buf[MAX_MSG_SIZE];
+ struct mq_timedreceive2_args args = {
+ .msg_len = sizeof(buf),
+ .msg_prio = NULL,
+ .msg_ptr = buf,
+ };
+ long ret;
+
+ send_msg(mqd, PRIO_HIGH, "A", 1);
+ send_msg(mqd, PRIO_MED, "B", 1);
+ send_msg(mqd, PRIO_LOW, "C", 1);
+
+ ret = mq_timedreceive2(mqd, &args, u_struct_size, MQ_PEEK | MQ_RECV, 0, 0);
+
+ if (ret == -1 && errno == EINVAL)
+ ksft_test_result_pass("Handler rejected invalid/contradictory request [EINVAL]\n");
+ else
+ ksft_test_result_fail("Handler did not reject invalid request: ret=%ld errno=%d (%m)\n",
+ ret, errno);
+
+ mq_close(mqd);
+}
+
static const struct {
const char *name;
void (*fn)(void);
@@ -756,6 +783,7 @@ static const struct {
{ "NULL msg_prio ptr", test_peek_null_prio_ptr },
{ "peeked prio matches mq_receive",
test_peek_priority_matches_receive },
+ {"two_contradictory_operation_togther", test_contradictory_operation}
};
int main(void)
@@ -769,7 +797,7 @@ int main(void)
{
struct mq_timedreceive2_args probe_args = { 0 };
- sc_ret = mq_timedreceive2((mqd_t)-1, &probe_args, MQ_PEEK, 0,
+ sc_ret = mq_timedreceive2((mqd_t)-1, &probe_args, u_struct_size, MQ_PEEK, 0,
NULL);
if (sc_ret == -1 && errno == ENOSYS)
ksft_exit_skip("mq_timedreceive2 syscall not available (NR=%d ENOSYS) — is the kernel too old?\n",
--
2.43.0
next prev parent reply other threads:[~2026-04-08 9:53 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-08 9:51 [PATCH v3 0/5] Add new system call for non-destructive peek and inspection to posix ipc mqueue Mathura_Kumar
2026-04-08 9:51 ` [PATCH v3 1/5]IPC: Added New system call do_mq_timedreceive2() for non-destructive peek on posix mqueue Mathura_Kumar
2026-04-13 16:34 ` Andrei Vagin
2026-04-14 0:04 ` Mathura
2026-04-14 0:52 ` Andrei Vagin
2026-04-08 9:51 ` [PATCH v3 2/5]IPC: Added system call number in all most common arch Mathura_Kumar
2026-04-08 9:51 ` [PATCH v3 3/5]IPC: Prepared Documentation and test Mathura_Kumar
2026-04-08 9:51 ` [PATCH v3 4/5]IPC:Added entry in performance tools for new system call Mathura_Kumar
2026-04-08 9:51 ` Mathura_Kumar [this message]
2026-04-13 16:36 ` [PATCH v3 0/5] Add new system call for non-destructive peek and inspection to posix ipc mqueue Andrei Vagin
[not found] ` <CA+QNo220nhDmyazh=JQi0OEfhsGAc7az+GRkM=G5KdZj4+SyNg@mail.gmail.com>
2026-04-13 23:30 ` Mathura
2026-04-14 0:11 ` Andrei Vagin
2026-04-14 0:40 ` Mathura
2026-04-14 16:39 ` Andrei Vagin
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=20260408095219.26350-6-academic1mathura@gmail.com \
--to=academic1mathura@gmail.com \
--cc=avagin@gmail.com \
--cc=criu@lists.linux.dev \
--cc=ptikhomirov@virtuozzo.com \
--cc=rstoyanov@fedoraproject.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox