Skip to contentSkip to conversation

nfs: fix nfs_writepage()

PATCH In review Peter Zijlstra 3 participants 13 messages Oct 17, 2007 NFS client

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 nfs: fix nfs_writepage()

I noticed that ->writepage() didn't actually do anything since it doesn't generate a write request for the given page.

The below is an attempt at fixing it, and it works for me. Although I'm not quite sure its the proper fix.

---
 fs/nfs/write.c |   20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
fs/nfs/write.c +20 -0
Index: linux-2.6/fs/nfs/write.c
===================================================================
@@ -332,10 +332,30 @@ static int nfs_page_async_flush(struct n
 static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio)
 {
 	struct inode *inode = page_file_mapping(page)->host;
+	struct rpc_cred *cred;
+	struct nfs_open_context *ctx;
+	int status;
 
 	nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE);
 	nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1);
 
+	cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
+	if (IS_ERR(cred))
+		return PTR_ERR(cred);
+
+	ctx = nfs_find_open_context(inode, cred, FMODE_WRITE);
+	if (!ctx)
+		return -EBADF;
+
+	status = nfs_writepage_setup(ctx, page, 0, nfs_page_length(page));
+
+	put_nfs_open_context(ctx);
+
+	if (status < 0) {
+		nfs_set_pageerror(page);
+		return status;
+	}
+
 	nfs_pageio_cond_complete(pgio, page_file_index(page));
 	return nfs_page_async_flush(pgio, page);
 }
#1 lore raw
Quoted 36 lines · Peter Zijlstra

I noticed that ->writepage() didn't actually do anything since it doesn't generate a write request for the given page.

The below is an attempt at fixing it, and it works for me. Although I'm not quite sure its the proper fix.

---
 fs/nfs/write.c |   20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

Index: linux-2.6/fs/nfs/write.c
===================================================================

fs/nfs/write.c +13 -0
@@ -332,10 +332,30 @@ static int nfs_page_async_flush(struct n
 static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio)
 {
 	struct inode *inode = page_file_mapping(page)->host;
+	struct rpc_cred *cred;
+	struct nfs_open_context *ctx;
+	int status;
 
 	nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE);
 	nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1);
 
+	cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
+	if (IS_ERR(cred))
+		return PTR_ERR(cred);
+
+	ctx = nfs_find_open_context(inode, cred, FMODE_WRITE);
+	if (!ctx)
+		return -EBADF;
+
+	status = nfs_writepage_setup(ctx, page, 0, nfs_page_length(page));
+

fs/nfs/write.c static int nfs_page_async_flush(struct n · line 361

Quoted 10 lines
fs/nfs/write.c +7 -0
+	put_nfs_open_context(ctx);
+
+	if (status < 0) {
+		nfs_set_pageerror(page);
+		return status;
+	}
+
 	nfs_pageio_cond_complete(pgio, page_file_index(page));
 	return nfs_page_async_flush(pgio, page);
 }

NACK. writepage()'s job is simply to start writeout on the page. nfs_vm_page_mkwrite(), and nfs_commit_write() actually set up the nfs_page structure before we ever get to writepage().

Cheers
Trond

#2 lore raw
Quoted 43 lines · Trond Myklebust
Quoted 42 lines · Peter Zijlstra

I noticed that ->writepage() didn't actually do anything since it doesn't generate a write request for the given page.

The below is an attempt at fixing it, and it works for me. Although I'm not quite sure its the proper fix.

---
 fs/nfs/write.c |   20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

Index: linux-2.6/fs/nfs/write.c
===================================================================

fs/nfs/write.c +19 -0
@@ -332,10 +332,30 @@ static int nfs_page_async_flush(struct n
 static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio)
 {
 	struct inode *inode = page_file_mapping(page)->host;
+	struct rpc_cred *cred;
+	struct nfs_open_context *ctx;
+	int status;
 
 	nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE);
 	nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1);
 
+	cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
+	if (IS_ERR(cred))
+		return PTR_ERR(cred);
+
+	ctx = nfs_find_open_context(inode, cred, FMODE_WRITE);
+	if (!ctx)
+		return -EBADF;
+
+	status = nfs_writepage_setup(ctx, page, 0, nfs_page_length(page));
+
+	put_nfs_open_context(ctx);
+
+	if (status < 0) {
+		nfs_set_pageerror(page);
+		return status;
+	}
Quoted 8 lines

fs/nfs/write.c static int nfs_page_async_flush(struct n · line 361

Quoted 4 lines
fs/nfs/write.c +1 -0
+
 	nfs_pageio_cond_complete(pgio, page_file_index(page));
 	return nfs_page_async_flush(pgio, page);
 }

NACK. writepage()'s job is simply to start writeout on the page. nfs_vm_page_mkwrite(), and nfs_commit_write() actually set up the nfs_page structure before we ever get to writepage().

Do all a_ops require this? From what I can gather other address_spaces do not require this, but I might be wrong.

The thing is, swapper_space just calls ->writepage() and expects the page to be written out. So either the a_ops usage of swapper_space is deviant or NFS' is.

#3 lore raw
Quoted 3 lines · Peter Zijlstra

The thing is, swapper_space just calls ->writepage() and expects the page to be written out. So either the a_ops usage of swapper_space is deviant or NFS' is.

Could somebody please document WTF writepage() is supposed to do, and WTF page_mkwrite() is for?

I thought that page_mkwrite() was supposed to finally allow us to deal with dirty pages in a clean manner: the caller gets to tell the filesystem that it wants the entire page written out, and then dirties the page. What is the point if the VM then expects to be able to circumvent this?

Trond

#4 lore raw
Quoted 6 lines · Trond Myklebust
Quoted 3 lines · Peter Zijlstra

The thing is, swapper_space just calls ->writepage() and expects the page to be written out. So either the a_ops usage of swapper_space is deviant or NFS' is.

Quoted 8 lines

Could somebody please document WTF writepage() is supposed to do, and WTF page_mkwrite() is for?

I thought that page_mkwrite() was supposed to finally allow us to deal with dirty pages in a clean manner: the caller gets to tell the filesystem that it wants the entire page written out, and then dirties the page. What is the point if the VM then expects to be able to circumvent this?

Put differently:
* _who_ is dirtying the page when the swapper is trying to write the page out?
* why are they not calling either page_mkwrite() or commit_write()?

Trond

#5 lore raw
Quoted 5 lines · Trond Myklebust

Put differently:
* _who_ is dirtying the page when the swapper is trying to write the page out?
* why are they not calling either page_mkwrite() or commit_write()?

Apparently Peter has some broken patches in his tree that cause this. It can for sure not happen in mainline and that's absolutely intentional.

#6 lore raw
Quoted 9 lines · Christoph Hellwig
Quoted 5 lines · Trond Myklebust

Put differently:
* _who_ is dirtying the page when the swapper is trying to write the page out?
* why are they not calling either page_mkwrite() or commit_write()?

Apparently Peter has some broken patches in his tree that cause this. It can for sure not happen in mainline and that's absolutely intentional.

Yeah, I got fooled by thinking swapper_space was 'proper' usage.

#7 lore raw
Quoted 4 lines · Peter Zijlstra
Quoted 2 lines

Apparently Peter has some broken patches in his tree that cause this. It can for sure not happen in mainline and that's absolutely intentional.

Yeah, I got fooled by thinking swapper_space was 'proper' usage.

The swapper space is and always has been special because it's not owned by a filesystem but rather the VM, so it can be sloppy about some things.

#8 lore raw
In reply to Trond Myklebust
Quoted 16 lines · Trond Myklebust
Quoted 6 lines · Trond Myklebust
Quoted 3 lines · Peter Zijlstra

The thing is, swapper_space just calls ->writepage() and expects the page to be written out. So either the a_ops usage of swapper_space is deviant or NFS' is.

Quoted 8 lines

Could somebody please document WTF writepage() is supposed to do, and WTF page_mkwrite() is for?

I thought that page_mkwrite() was supposed to finally allow us to deal with dirty pages in a clean manner: the caller gets to tell the filesystem that it wants the entire page written out, and then dirties the page. What is the point if the VM then expects to be able to circumvent this?

Quoted 5 lines

Put differently:
* _who_ is dirtying the page when the swapper is trying to write the page out?
* why are they not calling either page_mkwrite() or commit_write()?

I'm writing anonymous pages (I'm the crazy person doing swap over NFS). And anonymous is dirty by default.

#9 lore raw
Quoted 17 lines · Peter Zijlstra
Quoted 16 lines · Trond Myklebust
Quoted 14 lines · Trond Myklebust
Quoted 3 lines · Peter Zijlstra

The thing is, swapper_space just calls ->writepage() and expects the page to be written out. So either the a_ops usage of swapper_space is deviant or NFS' is.

Could somebody please document WTF writepage() is supposed to do, and WTF page_mkwrite() is for?

I thought that page_mkwrite() was supposed to finally allow us to deal with dirty pages in a clean manner: the caller gets to tell the filesystem that it wants the entire page written out, and then dirties the page. What is the point if the VM then expects to be able to circumvent this?

Quoted 8 lines
Quoted 5 lines

Put differently:
* _who_ is dirtying the page when the swapper is trying to write the page out?
* why are they not calling either page_mkwrite() or commit_write()?

I'm writing anonymous pages (I'm the crazy person doing swap over NFS). And anonymous is dirty by default.

I'd really prefer to _know_ that these writes are coming from the swapper. That makes it possible to give them a correct credential and open context.

Could you perhaps funnel them through a new a_op->swap_out() and default back to ->writepage() for those filesystems that don't define it?

#10 lore raw
Quoted 27 lines · Trond Myklebust
Quoted 17 lines · Peter Zijlstra
Quoted 16 lines · Trond Myklebust
Quoted 14 lines · Trond Myklebust
Quoted 3 lines · Peter Zijlstra

The thing is, swapper_space just calls ->writepage() and expects the page to be written out. So either the a_ops usage of swapper_space is deviant or NFS' is.

Could somebody please document WTF writepage() is supposed to do, and WTF page_mkwrite() is for?

I thought that page_mkwrite() was supposed to finally allow us to deal with dirty pages in a clean manner: the caller gets to tell the filesystem that it wants the entire page written out, and then dirties the page. What is the point if the VM then expects to be able to circumvent this?

Quoted 8 lines
Quoted 5 lines

Put differently:
* _who_ is dirtying the page when the swapper is trying to write the page out?
* why are they not calling either page_mkwrite() or commit_write()?

I'm writing anonymous pages (I'm the crazy person doing swap over NFS). And anonymous is dirty by default.

Quoted 6 lines

I'd really prefer to _know_ that these writes are coming from the swapper. That makes it possible to give them a correct credential and open context.

Could you perhaps funnel them through a new a_op->swap_out() and default back to ->writepage() for those filesystems that don't define it?

Sure, will do that.

#11 lore raw
Quoted 28 lines · Peter Zijlstra
Quoted 27 lines · Trond Myklebust
Quoted 25 lines · Peter Zijlstra
Quoted 16 lines · Trond Myklebust
Quoted 6 lines · Trond Myklebust
Quoted 3 lines · Peter Zijlstra

The thing is, swapper_space just calls ->writepage() and expects the page to be written out. So either the a_ops usage of swapper_space is deviant or NFS' is.

Quoted 8 lines

Could somebody please document WTF writepage() is supposed to do, and WTF page_mkwrite() is for?

I thought that page_mkwrite() was supposed to finally allow us to deal with dirty pages in a clean manner: the caller gets to tell the filesystem that it wants the entire page written out, and then dirties the page. What is the point if the VM then expects to be able to circumvent this?

Quoted 5 lines

Put differently:
* _who_ is dirtying the page when the swapper is trying to write the page out?
* why are they not calling either page_mkwrite() or commit_write()?

I'm writing anonymous pages (I'm the crazy person doing swap over NFS). And anonymous is dirty by default.

Quoted 8 lines
Quoted 6 lines

I'd really prefer to _know_ that these writes are coming from the swapper. That makes it possible to give them a correct credential and open context.

Could you perhaps funnel them through a new a_op->swap_out() and default back to ->writepage() for those filesystems that don't define it?

Sure, will do that.

OTOH these pages will have PageSwapCache() and IS_SWAPFILE(inode) will be true, so ->writepage() can already know. Do you still prefer ->swap_out() ?

#12 lore raw
Quoted 33 lines · Peter Zijlstra
Quoted 32 lines · Peter Zijlstra
Quoted 31 lines · Trond Myklebust
Quoted 17 lines · Peter Zijlstra
Quoted 16 lines · Trond Myklebust
Quoted 14 lines · Trond Myklebust
Quoted 3 lines · Peter Zijlstra

The thing is, swapper_space just calls ->writepage() and expects the page to be written out. So either the a_ops usage of swapper_space is deviant or NFS' is.

Could somebody please document WTF writepage() is supposed to do, and WTF page_mkwrite() is for?

I thought that page_mkwrite() was supposed to finally allow us to deal with dirty pages in a clean manner: the caller gets to tell the filesystem that it wants the entire page written out, and then dirties the page. What is the point if the VM then expects to be able to circumvent this?

Quoted 8 lines
Quoted 5 lines

Put differently:
* _who_ is dirtying the page when the swapper is trying to write the page out?
* why are they not calling either page_mkwrite() or commit_write()?

I'm writing anonymous pages (I'm the crazy person doing swap over NFS). And anonymous is dirty by default.

I'd really prefer to _know_ that these writes are coming from the swapper. That makes it possible to give them a correct credential and open context.

Quoted 8 lines
Quoted 4 lines
Quoted 2 lines

Could you perhaps funnel them through a new a_op->swap_out() and default back to ->writepage() for those filesystems that don't define it?

Sure, will do that.

OTOH these pages will have PageSwapCache() and IS_SWAPFILE(inode) will be true, so ->writepage() can already know. Do you still prefer ->swap_out() ?

I think it is cleaner. PageSwapCache() is currently internal to the mm layer, and doesn't need to be exported here. Then there is the issue of overloading ->writepage(), which I don't like at all: it muddies the semantics.

As for IS_SWAPFILE(), it would be nice to get rid of that one day...

Cheers
Trond