linux-nfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "J. Bruce Fields" <bfields@redhat.com>
To: linux-nfs@vger.kernel.org
Cc: Christoph Hellwig <hch@infradead.org>,
	"J. Bruce Fields" <bfields@redhat.com>
Subject: [PATCH 43/52] nfsd4: separate splice and readv cases
Date: Thu, 22 May 2014 15:32:18 -0400	[thread overview]
Message-ID: <1400787148-25941-44-git-send-email-bfields@redhat.com> (raw)
In-Reply-To: <1400787148-25941-1-git-send-email-bfields@redhat.com>

From: "J. Bruce Fields" <bfields@redhat.com>

The splice and readv cases are actually quite different--for example the
former case ignores the array of vectors we build up for the latter.

It is probably clearer to separate the two cases entirely.

There's some code duplication between the split out encoders, but this
is only temporary and will be fixed by a later patch.

Signed-off-by: J. Bruce Fields <bfields@redhat.com>
---
 fs/nfsd/nfs4xdr.c | 173 +++++++++++++++++++++++++++++++++++++++++-------------
 fs/nfsd/vfs.c     | 121 +++++++++++++++++++++++---------------
 fs/nfsd/vfs.h     |   8 +++
 3 files changed, 214 insertions(+), 88 deletions(-)

diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 1ca547d..bf853fd 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3069,41 +3069,84 @@ nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struc
 	return nfserr;
 }
 
-static __be32
-nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
-		  struct nfsd4_read *read)
+static __be32 nfsd4_encode_splice_read(
+				struct nfsd4_compoundres *resp,
+				struct nfsd4_read *read,
+				struct file *file, unsigned long maxcount)
 {
-	u32 eof;
-	int v;
-	struct page *page;
-	unsigned long maxcount; 
 	struct xdr_stream *xdr = &resp->xdr;
-	int starting_len = xdr->buf->len;
+	u32 eof;
+	int starting_len = xdr->buf->len - 8;
 	int space_left;
-	long len;
+	__be32 nfserr;
+	__be32 tmp;
 	__be32 *p;
 
-	if (nfserr)
-		return nfserr;
-
-	p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */
-	if (!p) {
-		WARN_ON_ONCE(resp->rqstp->rq_splice_ok);
+	/*
+	 * Don't inline pages unless we know there's room for eof,
+	 * count, and possible padding:
+	 */
+	if (xdr->end - xdr->p < 3)
 		return nfserr_resource;
+
+	nfserr = nfsd_splice_read(read->rd_rqstp, file,
+				  read->rd_offset, &maxcount);
+	if (nfserr) {
+		/*
+		 * nfsd_splice_actor may have already messed with the
+		 * page length; reset it so as not to confuse
+		 * xdr_truncate_encode:
+		 */
+		xdr->buf->page_len = 0;
+		return nfserr;
 	}
 
-	/* Make sure there will be room for padding if needed: */
-	if (xdr->end - xdr->p < 1)
-		return nfserr_resource;
+	eof = (read->rd_offset + maxcount >=
+	       read->rd_fhp->fh_dentry->d_inode->i_size);
 
-	if (resp->xdr.buf->page_len) {
-		WARN_ON_ONCE(resp->rqstp->rq_splice_ok);
-		return nfserr_resource;
+	tmp = htonl(eof);
+	write_bytes_to_xdr_buf(xdr->buf, starting_len    , &tmp, 4);
+	tmp = htonl(maxcount);
+	write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4);
+
+	resp->xdr.buf->page_len = maxcount;
+	xdr->buf->len += maxcount;
+	xdr->page_ptr += (maxcount + PAGE_SIZE - 1) / PAGE_SIZE;
+	xdr->iov = xdr->buf->tail;
+
+	/* Use rest of head for padding and remaining ops: */
+	resp->xdr.buf->tail[0].iov_base = xdr->p;
+	resp->xdr.buf->tail[0].iov_len = 0;
+	if (maxcount&3) {
+		p = xdr_reserve_space(xdr, 4);
+		WRITE32(0);
+		resp->xdr.buf->tail[0].iov_base += maxcount&3;
+		resp->xdr.buf->tail[0].iov_len = 4 - (maxcount&3);
+		xdr->buf->len -= (maxcount&3);
 	}
 
-	maxcount = svc_max_payload(resp->rqstp);
-	if (maxcount > read->rd_length)
-		maxcount = read->rd_length;
+	space_left = min_t(int, (void *)xdr->end - (void *)xdr->p,
+				xdr->buf->buflen - xdr->buf->len);
+	xdr->buf->buflen = xdr->buf->len + space_left;
+	xdr->end = (__be32 *)((void *)xdr->end + space_left);
+
+	return 0;
+}
+
+static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
+				 struct nfsd4_read *read,
+				 struct file *file, unsigned long maxcount)
+{
+	struct xdr_stream *xdr = &resp->xdr;
+	u32 eof;
+	int v;
+	struct page *page;
+	int starting_len = xdr->buf->len - 8;
+	int space_left;
+	long len;
+	__be32 nfserr;
+	__be32 tmp;
+	__be32 *p;
 
 	len = maxcount;
 	v = 0;
@@ -3124,34 +3167,26 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
 	}
 	read->rd_vlen = v;
 
-	nfserr = nfsd_read_file(read->rd_rqstp, read->rd_fhp, read->rd_filp,
-			read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen,
-			&maxcount);
-
-	if (nfserr) {
-		/*
-		 * nfsd_splice_actor may have already messed with the
-		 * page length; reset it so as not to confuse
-		 * xdr_truncate_encode:
-		 */
-		xdr->buf->page_len = 0;
-		xdr_truncate_encode(xdr, starting_len);
+	nfserr = nfsd_readv(file, read->rd_offset, resp->rqstp->rq_vec,
+			read->rd_vlen, &maxcount);
+	if (nfserr)
 		return nfserr;
-	}
+
 	eof = (read->rd_offset + maxcount >=
 	       read->rd_fhp->fh_dentry->d_inode->i_size);
 
-	WRITE32(eof);
-	WRITE32(maxcount);
-	WARN_ON_ONCE(resp->xdr.buf->head[0].iov_len != (char *)p
-				- (char *)resp->xdr.buf->head[0].iov_base);
+	tmp = htonl(eof);
+	write_bytes_to_xdr_buf(xdr->buf, starting_len    , &tmp, 4);
+	tmp = htonl(maxcount);
+	write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4);
+
 	resp->xdr.buf->page_len = maxcount;
 	xdr->buf->len += maxcount;
 	xdr->page_ptr += v;
 	xdr->iov = xdr->buf->tail;
 
 	/* Use rest of head for padding and remaining ops: */
-	resp->xdr.buf->tail[0].iov_base = p;
+	resp->xdr.buf->tail[0].iov_base = xdr->p;
 	resp->xdr.buf->tail[0].iov_len = 0;
 	if (maxcount&3) {
 		p = xdr_reserve_space(xdr, 4);
@@ -3167,6 +3202,60 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
 	xdr->end = (__be32 *)((void *)xdr->end + space_left);
 
 	return 0;
+
+}
+
+static __be32
+nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
+		  struct nfsd4_read *read)
+{
+	unsigned long maxcount;
+	struct xdr_stream *xdr = &resp->xdr;
+	struct file *file = read->rd_filp;
+	int starting_len = xdr->buf->len;
+	struct raparms *ra;
+	__be32 *p;
+	__be32 err;
+
+	if (nfserr)
+		return nfserr;
+
+	p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */
+	if (!p) {
+		WARN_ON_ONCE(resp->rqstp->rq_splice_ok);
+		return nfserr_resource;
+	}
+
+	if (resp->xdr.buf->page_len) {
+		WARN_ON_ONCE(resp->rqstp->rq_splice_ok);
+		return nfserr_resource;
+	}
+
+	xdr_commit_encode(xdr);
+
+	maxcount = svc_max_payload(resp->rqstp);
+	if (maxcount > read->rd_length)
+		maxcount = read->rd_length;
+
+	if (!read->rd_filp) {
+		err = nfsd_get_tmp_read_open(resp->rqstp, read->rd_fhp,
+						&file, &ra);
+		if (err)
+			goto err_truncate;
+	}
+
+	if (file->f_op->splice_read && resp->rqstp->rq_splice_ok)
+		err = nfsd4_encode_splice_read(resp, read, file, maxcount);
+	else
+		err = nfsd4_encode_readv(resp, read, file, maxcount);
+
+	if (!read->rd_filp)
+		nfsd_put_tmp_read_open(file, ra);
+
+err_truncate:
+	if (err)
+		xdr_truncate_encode(xdr, starting_len);
+	return err;
 }
 
 static __be32
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index ce781da..c0fbe24 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -820,41 +820,54 @@ static int nfsd_direct_splice_actor(struct pipe_inode_info *pipe,
 	return __splice_from_pipe(pipe, sd, nfsd_splice_actor);
 }
 
-static __be32
-nfsd_vfs_read(struct svc_rqst *rqstp, struct file *file,
-              loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
+__be32 nfsd_finish_read(struct file *file, unsigned long *count, int host_err)
 {
-	mm_segment_t	oldfs;
-	__be32		err;
-	int		host_err;
-
-	err = nfserr_perm;
-
-	if (file->f_op->splice_read && rqstp->rq_splice_ok) {
-		struct splice_desc sd = {
-			.len		= 0,
-			.total_len	= *count,
-			.pos		= offset,
-			.u.data		= rqstp,
-		};
-
-		rqstp->rq_next_page = rqstp->rq_respages + 1;
-		host_err = splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor);
-	} else {
-		oldfs = get_fs();
-		set_fs(KERNEL_DS);
-		host_err = vfs_readv(file, (struct iovec __user *)vec, vlen, &offset);
-		set_fs(oldfs);
-	}
-
 	if (host_err >= 0) {
 		nfsdstats.io_read += host_err;
 		*count = host_err;
-		err = 0;
 		fsnotify_access(file);
+		return 0;
 	} else 
-		err = nfserrno(host_err);
-	return err;
+		return nfserrno(host_err);
+}
+
+int nfsd_splice_read(struct svc_rqst *rqstp,
+		     struct file *file, loff_t offset, unsigned long *count)
+{
+	struct splice_desc sd = {
+		.len		= 0,
+		.total_len	= *count,
+		.pos		= offset,
+		.u.data		= rqstp,
+	};
+	int host_err;
+
+	rqstp->rq_next_page = rqstp->rq_respages + 1;
+	host_err = splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor);
+	return nfsd_finish_read(file, count, host_err);
+}
+
+int nfsd_readv(struct file *file, loff_t offset, struct kvec *vec, int vlen,
+		unsigned long *count)
+{
+	mm_segment_t oldfs;
+	int host_err;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	host_err = vfs_readv(file, (struct iovec __user *)vec, vlen, &offset);
+	set_fs(oldfs);
+	return nfsd_finish_read(file, count, host_err);
+}
+
+static __be32
+nfsd_vfs_read(struct svc_rqst *rqstp, struct file *file,
+	      loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
+{
+	if (file->f_op->splice_read && rqstp->rq_splice_ok)
+		return nfsd_splice_read(rqstp, file, offset, count);
+	else
+		return nfsd_readv(file, offset, vec, vlen, count);
 }
 
 /*
@@ -944,33 +957,28 @@ out_nfserr:
 	return err;
 }
 
-/*
- * Read data from a file. count must contain the requested read count
- * on entry. On return, *count contains the number of bytes actually read.
- * N.B. After this call fhp needs an fh_put
- */
-__be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
-	loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
+__be32 nfsd_get_tmp_read_open(struct svc_rqst *rqstp, struct svc_fh *fhp,
+		struct file **file, struct raparms **ra)
 {
-	struct file *file;
 	struct inode *inode;
-	struct raparms	*ra;
 	__be32 err;
 
-	err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
+	err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, file);
 	if (err)
 		return err;
 
-	inode = file_inode(file);
+	inode = file_inode(*file);
 
 	/* Get readahead parameters */
-	ra = nfsd_get_raparms(inode->i_sb->s_dev, inode->i_ino);
-
-	if (ra && ra->p_set)
-		file->f_ra = ra->p_ra;
+	*ra = nfsd_get_raparms(inode->i_sb->s_dev, inode->i_ino);
 
-	err = nfsd_vfs_read(rqstp, file, offset, vec, vlen, count);
+	if (*ra && (*ra)->p_set)
+		(*file)->f_ra = (*ra)->p_ra;
+	return nfs_ok;
+}
 
+void nfsd_put_tmp_read_open(struct file *file, struct raparms *ra)
+{
 	/* Write back readahead params */
 	if (ra) {
 		struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex];
@@ -980,8 +988,29 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
 		ra->p_count--;
 		spin_unlock(&rab->pb_lock);
 	}
-
 	nfsd_close(file);
+}
+
+/*
+ * Read data from a file. count must contain the requested read count
+ * on entry. On return, *count contains the number of bytes actually read.
+ * N.B. After this call fhp needs an fh_put
+ */
+__be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
+	loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
+{
+	struct file *file;
+	struct raparms	*ra;
+	__be32 err;
+
+	err = nfsd_get_tmp_read_open(rqstp, fhp, &file, &ra);
+	if (err)
+		return err;
+
+	err = nfsd_vfs_read(rqstp, file, offset, vec, vlen, count);
+
+	nfsd_put_tmp_read_open(file, ra);
+
 	return err;
 }
 
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index fbe90bd..7441e96 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -70,6 +70,14 @@ __be32		nfsd_commit(struct svc_rqst *, struct svc_fh *,
 __be32		nfsd_open(struct svc_rqst *, struct svc_fh *, umode_t,
 				int, struct file **);
 void		nfsd_close(struct file *);
+struct raparms;
+__be32		nfsd_get_tmp_read_open(struct svc_rqst *, struct svc_fh *,
+				struct file **, struct raparms **);
+void		nfsd_put_tmp_read_open(struct file *, struct raparms *);
+int		nfsd_splice_read(struct svc_rqst *,
+				struct file *, loff_t, unsigned long *);
+int		nfsd_readv(struct file *, loff_t, struct kvec *, int,
+				unsigned long *);
 __be32 		nfsd_read(struct svc_rqst *, struct svc_fh *,
 				loff_t, struct kvec *, int, unsigned long *);
 __be32 		nfsd_read_file(struct svc_rqst *, struct svc_fh *, struct file *,
-- 
1.9.0


  parent reply	other threads:[~2014-05-22 19:32 UTC|newest]

Thread overview: 67+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-05-22 19:31 xdr encoding fixes (v3) J. Bruce Fields
2014-05-22 19:31 ` [PATCH 01/52] nfsd4: READ, READDIR, etc., are idempotent J. Bruce Fields
2014-05-23  1:21   ` Kinglong Mee
2014-05-23 13:15     ` J. Bruce Fields
2014-05-22 19:31 ` [PATCH 02/52] nfsd4: allow larger 4.1 session drc slots J. Bruce Fields
2014-05-22 19:31 ` [PATCH 03/52] nfsd4: fill in some missing op_name's J. Bruce Fields
2014-05-22 19:31 ` [PATCH 04/52] nfsd4: decoding errors can still be cached and require space J. Bruce Fields
2014-05-22 19:31 ` [PATCH 05/52] nfsd4: read size estimate should include padding J. Bruce Fields
2014-05-22 19:31 ` [PATCH 06/52] nfsd4: fix write reply size estimate J. Bruce Fields
2014-05-22 19:31 ` [PATCH 07/52] nfsd4: embed xdr_stream in nfsd4_compoundres J. Bruce Fields
2014-05-22 19:31 ` [PATCH 08/52] nfsd4: tweak nfsd4_encode_getattr to take xdr_stream J. Bruce Fields
2014-05-22 19:31 ` [PATCH 09/52] nfsd4: move proc_compound xdr encode init to helper J. Bruce Fields
2014-05-22 19:31 ` [PATCH 10/52] nfsd4: reserve head space for krb5 integ/priv info J. Bruce Fields
2014-05-22 19:31 ` [PATCH 11/52] nfsd4: fix encoding of out-of-space replies J. Bruce Fields
2014-05-22 19:31 ` [PATCH 12/52] nfsd4: allow space for final error return J. Bruce Fields
2014-05-22 19:31 ` [PATCH 13/52] nfsd4: use xdr_reserve_space in attribute encoding J. Bruce Fields
2014-05-25  8:46   ` Kinglong Mee
2014-05-22 19:31 ` [PATCH 14/52] nfsd4: use xdr_stream throughout compound encoding J. Bruce Fields
2014-05-22 19:31 ` [PATCH 15/52] nfsd4: remove ADJUST_ARGS J. Bruce Fields
2014-05-22 19:31 ` [PATCH 16/52] nfsd4: no need for encode_compoundres to adjust lengths J. Bruce Fields
2014-05-22 19:31 ` [PATCH 17/52] nfsd4: keep xdr buf length updated J. Bruce Fields
2014-05-22 19:31 ` [PATCH 18/52] rpc: xdr_truncate_encode J. Bruce Fields
2014-05-22 19:31 ` [PATCH 19/52] nfsd4: use xdr_truncate_encode J. Bruce Fields
2014-05-22 19:31 ` [PATCH 20/52] nfsd4: "backfill" using write_bytes_to_xdr_buf J. Bruce Fields
2014-05-22 19:31 ` [PATCH 21/52] nfsd4: teach encoders to handle reserve_space failures J. Bruce Fields
2014-05-22 19:31 ` [PATCH 22/52] nfsd4: reserve space before inlining 0-copy pages J. Bruce Fields
2014-05-22 19:31 ` [PATCH 23/52] nfsd4: nfsd4_check_resp_size needn't recalculate length J. Bruce Fields
2014-05-22 19:31 ` [PATCH 24/52] nfsd4: remove redundant encode buffer size checking J. Bruce Fields
2014-05-22 19:32 ` [PATCH 25/52] nfsd4: size-checking cleanup J. Bruce Fields
2014-05-22 19:32 ` [PATCH 26/52] nfsd4: allow encoding across page boundaries J. Bruce Fields
2014-05-22 19:32 ` [PATCH 27/52] nfsd4: convert 4.1 replay encoding J. Bruce Fields
2014-05-22 19:32 ` [PATCH 28/52] nfsd4: don't try to encode conflicting owner if low on space J. Bruce Fields
2014-05-22 19:32 ` [PATCH 29/52] nfsd4: more precise nfsd4_max_reply J. Bruce Fields
2014-05-22 19:32 ` [PATCH 30/52] nfsd4: minor encode_read cleanup J. Bruce Fields
2014-05-22 19:32 ` [PATCH 31/52] nfsd4: nfsd4_check_resp_size should check against whole buffer J. Bruce Fields
2014-05-22 19:32 ` [PATCH 32/52] nfsd4: fix buflen calculation after read encoding J. Bruce Fields
2014-05-22 19:32 ` [PATCH 33/52] rpc: define xdr_restrict_buflen J. Bruce Fields
2014-05-22 19:32 ` [PATCH 34/52] nfsd4: adjust buflen to session channel limit J. Bruce Fields
2014-05-22 19:32 ` [PATCH 35/52] nfsd4: use session limits to release send buffer reservation J. Bruce Fields
2014-05-22 19:32 ` [PATCH 36/52] nfsd4: allow large readdirs J. Bruce Fields
2014-05-22 19:32 ` [PATCH 37/52] nfsd4: enforce rd_dircount J. Bruce Fields
2014-05-22 19:32 ` [PATCH 38/52] nfsd4: don't treat readlink like a zero-copy operation J. Bruce Fields
2014-05-22 19:32 ` [PATCH 39/52] nfsd4: better estimate of getattr response size J. Bruce Fields
2014-05-22 19:32 ` [PATCH 40/52] nfsd4: estimate sequence " J. Bruce Fields
2014-05-22 19:32 ` [PATCH 41/52] nfsd4: turn off zero-copy-read in exotic cases J. Bruce Fields
2014-05-28  8:09   ` Christoph Hellwig
2014-05-28 14:01     ` J. Bruce Fields
2014-05-28 14:13       ` Anna Schumaker
2014-05-28 14:23         ` J. Bruce Fields
2014-05-28 14:27           ` Anna Schumaker
2014-06-03  4:18           ` Weston Andros Adamson
2014-06-03 14:10             ` J. Bruce Fields
2014-06-03 14:24               ` Weston Andros Adamson
2014-06-03 14:35                 ` J. Bruce Fields
2014-05-28 21:08       ` J. Bruce Fields
2014-06-02 22:12         ` J. Bruce Fields
2014-05-22 19:32 ` [PATCH 42/52] nfsd4: nfsd_vfs_read doesn't use file handle parameter J. Bruce Fields
2014-05-22 19:32 ` J. Bruce Fields [this message]
2014-05-22 19:32 ` [PATCH 44/52] nfsd4: read encoding cleanup J. Bruce Fields
2014-05-22 19:32 ` [PATCH 45/52] nfsd4: more " J. Bruce Fields
2014-05-22 19:32 ` [PATCH 46/52] nfsd4: allow exotic read compounds J. Bruce Fields
2014-05-22 19:32 ` [PATCH 47/52] nfsd4: really fix nfs4err_resource in 4.1 case J. Bruce Fields
2014-05-22 19:32 ` [PATCH 48/52] nfsd4: kill WRITE32 J. Bruce Fields
2014-05-22 19:32 ` [PATCH 49/52] nfsd4: kill WRITE64 J. Bruce Fields
2014-05-22 19:32 ` [PATCH 50/52] nfsd4: kill WRITEMEM J. Bruce Fields
2014-05-22 19:32 ` [PATCH 51/52] nfsd4: kill write32, write64 J. Bruce Fields
2014-05-22 19:32 ` [PATCH 52/52] nfsd4: better reservation of head space for krb5 J. Bruce Fields

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=1400787148-25941-44-git-send-email-bfields@redhat.com \
    --to=bfields@redhat.com \
    --cc=hch@infradead.org \
    --cc=linux-nfs@vger.kernel.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;
as well as URLs for NNTP newsgroup(s).