Blob Blame History Raw
From: NeilBrown <neilb@suse.com>
Subject: Fix kABI for "Ensure we commit after writeback is complete"
Patch-mainline: Never, kabi
References: bsc#1111809

These two structures, nfs_pageio_descriptor and nfs_pgio_header, need
an extra field.

For nfs_pgio_header, the structure is always allocated by common code,
so it should be safe to just move it to the end of the structure.

For nfs_pageio_descriptor, the structure is allocated on the stack in:
  direct.c
  read.c
  write.c
  pnfs.c

As pnfs is in nfsv4.ko while the rest are in nfs.ko, this extra field
is a real part of the kABI. If some vendor module, such as an altered
version of nfsv4, allocated the structre on the stack, that would cause problems.

Fortunately nfs_pageio_descriptor() contains unused space.
Only one of pg_mirrors_static and pg_mirrors_dynamic is used at a time,
and we can tell which one by examining where pg_mirrors points.
So store the extra field in whichever space is currently unused.

Signed-off-by: NeilBrown <neilb@suse.com>


---
 fs/nfs/pagelist.c        |   18 ++++++++++++++----
 fs/nfs/write.c           |    2 +-
 include/linux/nfs_page.h |   12 +++++++++++-
 include/linux/nfs_xdr.h  |    4 +++-
 4 files changed, 29 insertions(+), 7 deletions(-)

--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -50,7 +50,7 @@ void nfs_pgheader_init(struct nfs_pageio
 	hdr->cred = hdr->req->wb_context->cred;
 	hdr->io_start = req_offset(hdr->req);
 	hdr->good_bytes = mirror->pg_count;
-	hdr->io_completion = desc->pg_io_completion;
+	hdr->io_completion = *pg_io_completion(desc);
 	hdr->dreq = desc->pg_dreq;
 	hdr->layout_private = desc->pg_layout_private;
 	hdr->release = release;
@@ -706,7 +706,6 @@ void nfs_pageio_init(struct nfs_pageio_d
 	desc->pg_ioflags = io_flags;
 	desc->pg_error = 0;
 	desc->pg_lseg = NULL;
-	desc->pg_io_completion = NULL;
 	desc->pg_dreq = NULL;
 	desc->pg_layout_private = NULL;
 	desc->pg_bsize = bsize;
@@ -717,6 +716,7 @@ void nfs_pageio_init(struct nfs_pageio_d
 	desc->pg_mirrors_dynamic = NULL;
 	desc->pg_mirrors = desc->pg_mirrors_static;
 	nfs_pageio_mirror_init(&desc->pg_mirrors[0], bsize);
+	*pg_io_completion(desc) = NULL;
 }
 EXPORT_SYMBOL_GPL(nfs_pageio_init);
 
@@ -863,13 +863,19 @@ static void nfs_pageio_setup_mirroring(s
 				       struct nfs_page *req)
 {
 	unsigned int mirror_count = 1;
+	struct nfs_io_completion *iocomp = *pg_io_completion(pgio);
+
+	*pg_io_completion(pgio) = NULL;
 
 	if (pgio->pg_ops->pg_get_mirror_count)
 		mirror_count = pgio->pg_ops->pg_get_mirror_count(pgio, req);
-	if (mirror_count == pgio->pg_mirror_count || pgio->pg_error < 0)
+	if (mirror_count == pgio->pg_mirror_count || pgio->pg_error < 0) {
+		*pg_io_completion(pgio) = iocomp;
 		return;
+	}
 
 	if (!mirror_count || mirror_count > NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX) {
+		*pg_io_completion(pgio) = iocomp;
 		pgio->pg_error = -EINVAL;
 		return;
 	}
@@ -881,6 +887,7 @@ static void nfs_pageio_setup_mirroring(s
 		mirror_count = 1;
 	}
 	pgio->pg_mirror_count = mirror_count;
+	*pg_io_completion(pgio) = iocomp;
 }
 
 /*
@@ -894,11 +901,14 @@ void nfs_pageio_stop_mirroring(struct nf
 
 static void nfs_pageio_cleanup_mirroring(struct nfs_pageio_descriptor *pgio)
 {
+	struct nfs_io_completion *iocomp = *pg_io_completion(pgio);
+	*pg_io_completion(pgio) = NULL;
 	pgio->pg_mirror_count = 1;
 	pgio->pg_mirror_idx = 0;
 	pgio->pg_mirrors = pgio->pg_mirrors_static;
 	kfree(pgio->pg_mirrors_dynamic);
 	pgio->pg_mirrors_dynamic = NULL;
+	*pg_io_completion(pgio) = iocomp;
 }
 
 static bool nfs_match_lock_context(const struct nfs_lock_context *l1,
@@ -1254,7 +1264,7 @@ int nfs_pageio_resend(struct nfs_pageio_
 {
 	LIST_HEAD(pages);
 
-	desc->pg_io_completion = hdr->io_completion;
+	*pg_io_completion(desc) = hdr->io_completion;
 	desc->pg_dreq = hdr->dreq;
 	list_splice_init(&hdr->pages, &pages);
 	while (!list_empty(&pages)) {
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -744,7 +744,7 @@ int nfs_writepages(struct address_space
 
 	nfs_pageio_init_write(&pgio, inode, wb_priority(wbc), false,
 				&nfs_async_write_completion_ops);
-	pgio.pg_io_completion = ioc;
+	*pg_io_completion(&pgio) = ioc;
 	err = write_cache_pages(mapping, wbc, nfs_writepages_callback, &pgio);
 	nfs_pageio_complete(&pgio);
 	nfs_io_completion_put(ioc);
--- a/include/linux/nfs_page.h
+++ b/include/linux/nfs_page.h
@@ -93,7 +93,6 @@ struct nfs_pageio_descriptor {
 	const struct rpc_call_ops *pg_rpc_callops;
 	const struct nfs_pgio_completion_ops *pg_completion_ops;
 	struct pnfs_layout_segment *pg_lseg;
-	struct nfs_io_completion *pg_io_completion;
 	struct nfs_direct_req	*pg_dreq;
 	void			*pg_layout_private;
 	unsigned int		pg_bsize;	/* default bsize for mirrors */
@@ -105,6 +104,17 @@ struct nfs_pageio_descriptor {
 	u32			pg_mirror_idx;	/* current mirror */
 };
 
+static inline struct nfs_io_completion **pg_io_completion(struct nfs_pageio_descriptor *desc)
+{
+	static struct nfs_io_completion *failsafe = NULL;
+	if (desc->pg_mirrors == desc->pg_mirrors_static)
+		return (struct nfs_io_completion **)&desc->pg_mirrors_dynamic;
+	if (desc->pg_mirrors == desc->pg_mirrors_dynamic)
+		return (struct nfs_io_completion **)&desc->pg_mirrors_static[0].pg_list.next;
+	WARN_ON_ONCE(1);
+	return &failsafe;
+}
+
 /* arbitrarily selected limit to number of mirrors */
 #define NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX 16
 
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1436,7 +1436,6 @@ struct nfs_pgio_header {
 	void (*release) (struct nfs_pgio_header *hdr);
 	const struct nfs_pgio_completion_ops *completion_ops;
 	const struct nfs_rw_ops	*rw_ops;
-	struct nfs_io_completion *io_completion;
 	struct nfs_direct_req	*dreq;
 	void			*layout_private;
 	spinlock_t		lock;
@@ -1460,6 +1459,9 @@ struct nfs_pgio_header {
 	struct nfs_client	*ds_clp;	/* pNFS data server */
 	int			ds_commit_idx;	/* ds index if ds_clp is set */
 	int			pgio_mirror_idx;/* mirror index in pgio layer */
+#ifndef __GENKSYMS__
+	struct nfs_io_completion *io_completion;
+#endif
 };
 
 struct nfs_mds_commit_info {