From: Trond Myklebust <Trond.Myklebust@netapp.com>
To: Chuck Lever <chuck.lever@oracle.com>
Cc: linux-nfs@vger.kernel.org
Subject: Re: [PATCH 1/2] NFS: Clean up nfs_update_request()
Date: Tue, 17 Jun 2008 17:56:47 -0400 [thread overview]
Message-ID: <1213739807.7288.86.camel@localhost> (raw)
In-Reply-To: <B9BACB96-E0DB-4C6D-B55D-A50CC6F94474@oracle.com>
On Tue, 2008-06-17 at 17:35 -0400, Chuck Lever wrote:
> Hi Trond-
>
> On Jun 16, 2008, at 3:23 PM, Trond Myklebust wrote:
> > Simplify the loop in nfs_update_request by moving into a separate
> > function
> > the code that attempts to update an existing cached NFS write.
> >
> > Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
> > ---
> >
> > fs/nfs/write.c | 105 +++++++++++++++++++++++++++
> > +----------------------------
> > 1 files changed, 53 insertions(+), 52 deletions(-)
> >
> > diff --git a/fs/nfs/write.c b/fs/nfs/write.c
> > index 8f12157..a675dc9 100644
> > --- a/fs/nfs/write.c
> > +++ b/fs/nfs/write.c
> > @@ -34,9 +34,8 @@
> > /*
> > * Local function declarations
> > */
> > -static struct nfs_page * nfs_update_request(struct nfs_open_context*,
> > - struct page *,
> > - unsigned int, unsigned int);
> > +static struct nfs_page * nfs_setup_write_request(struct
> > nfs_open_context *ctx,
> > + struct page *page, unsigned int offset, unsigned int bytes);
> > static void nfs_pageio_init_write(struct nfs_pageio_descriptor *desc,
> > struct inode *inode, int ioflags);
> > static void nfs_redirty_request(struct nfs_page *req);
> > @@ -178,7 +177,7 @@ static int nfs_writepage_setup(struct
> > nfs_open_context *ctx, struct page *page,
> > int ret;
> >
> > for (;;) {
> > - req = nfs_update_request(ctx, page, offset, count);
> > + req = nfs_setup_write_request(ctx, page, offset, count);
> > if (!IS_ERR(req))
> > break;
> > ret = PTR_ERR(req);
> > @@ -566,6 +565,41 @@ static inline int nfs_scan_commit(struct inode
> > *inode, struct list_head *dst, pg
> > }
> > #endif
> >
> > +static int nfs_try_to_update_request(struct nfs_page *req,
> > + unsigned int offset,
> > + unsigned int end)
> > +{
> > + unsigned int rqend;
> > +
> > + rqend = req->wb_offset + req->wb_bytes;
> > +
> > + /*
> > + * If the page doesn't match, or the offsets
> > + * are non-contiguous, tell the caller to
> > + * wait on the conflicting request.
> > + */
> > + if (req->wb_page == NULL
> > + || !nfs_dirty_request(req)
> > + || offset > rqend
> > + || end < req->wb_offset)
> > + return -EBUSY;
>
> I don't see how this is equivalent to what it replaces in
> nfs_update_request:
>
> > - if (req->wb_context != ctx
> > - || req->wb_page != page
>
>
> What happened to the context check, for example?
That is a deliberate change.
We hold the page lock across nfs_vm_page_mkwrite and/or
nfs_write_begin()/nfs_write_end(), so nobody else can add a new nfs_page
to page->private during that time.
For that reason, the check that is done in nfs_flush_incompatible()
together with the check for req->wb_page==NULL (done in
try_to_update_page() while still holding the inode->i_lock) means that
the above two checks are redundant.
...actually, come to think of it, the check for req->wb_page == NULL is
redundant too, since nfs_clear_request() is called at the end of
nfs_inode_remove_request(), and hence nfs_page_find_request_locked()
would fail to find anything.
> > +
> > + if (!nfs_set_page_tag_locked(req))
> > + return -EAGAIN;
>
> This -EAGAIN (and the resulting logic in nfs_setup_write_request) is
> headache-inducing. Is there a more straightforward way to break this
> up?
No. If the page is being written out, then we _must_ release all locks,
wait on the request, and try again. This is not a change compared to the
previous incarnation.
> > +
> > + /* Okay, the request matches. Update the region */
> > + if (offset < req->wb_offset) {
> > + req->wb_offset = offset;
> > + req->wb_pgbase = offset;
> > + }
> > + if (end > rqend)
> > + req->wb_bytes = end - req->wb_offset;
> > + else
> > + req->wb_bytes = rqend - req->wb_offset;
> > +
> > + return 0;
> > +}
> > +
> > /*
> > * Try to update any existing write request, or create one if there
> > is none.
> > * In order to match, the request's credentials must match those of
> > @@ -573,16 +607,15 @@ static inline int nfs_scan_commit(struct inode
> > *inode, struct list_head *dst, pg
> > *
> > * Note: Should always be called with the Page Lock held!
> > */
> > -static struct nfs_page * nfs_update_request(struct
> > nfs_open_context* ctx,
> > +static struct nfs_page * nfs_setup_write_request(struct
> > nfs_open_context* ctx,
> > struct page *page, unsigned int offset, unsigned int bytes)
> > {
> > - struct address_space *mapping = page->mapping;
> > - struct inode *inode = mapping->host;
> > + struct inode *inode = page->mapping->host;
> > struct nfs_page *req, *new = NULL;
> > - pgoff_t rqend, end;
> > + unsigned int end;
> > + int error;
> >
> > end = offset + bytes;
> > -
> > for (;;) {
> > /* Loop over all inode entries and see if we find
> > * A request for the page we wish to update
> > @@ -590,26 +623,16 @@ static struct nfs_page *
> > nfs_update_request(struct nfs_open_context* ctx,
> > spin_lock(&inode->i_lock);
> > req = nfs_page_find_request_locked(page);
> > if (req) {
> > - if (!nfs_set_page_tag_locked(req)) {
> > - int error;
> > -
> > - spin_unlock(&inode->i_lock);
> > + error = nfs_try_to_update_request(req, offset, end);
> > + spin_unlock(&inode->i_lock);
> > + if (error == 0)
> > + break;
> > + if (error == -EAGAIN)
> > error = nfs_wait_on_request(req);
> > - nfs_release_request(req);
> > - if (error < 0) {
> > - if (new) {
> > - radix_tree_preload_end();
> > - nfs_release_request(new);
> > - }
> > - return ERR_PTR(error);
> > - }
> > + nfs_release_request(req);
> > + if (error == 0)
> > continue;
> > - }
> > - spin_unlock(&inode->i_lock);
> > - if (new) {
> > - radix_tree_preload_end();
> > - nfs_release_request(new);
> > - }
> > + req = ERR_PTR(error);
> > break;
> > }
> >
> > @@ -632,32 +655,10 @@ static struct nfs_page *
> > nfs_update_request(struct nfs_open_context* ctx,
> > }
> > }
> >
> > - /* We have a request for our page.
> > - * If the creds don't match, or the
> > - * page addresses don't match,
> > - * tell the caller to wait on the conflicting
> > - * request.
> > - */
> > - rqend = req->wb_offset + req->wb_bytes;
> > - if (req->wb_context != ctx
> > - || req->wb_page != page
> > - || !nfs_dirty_request(req)
> > - || offset > rqend || end < req->wb_offset) {
> > - nfs_clear_page_tag_locked(req);
> > - return ERR_PTR(-EBUSY);
> > + if (new) {
> > + radix_tree_preload_end();
> > + nfs_release_request(new);
> > }
> > -
> > - /* Okay, the request matches. Update the region */
> > - if (offset < req->wb_offset) {
> > - req->wb_offset = offset;
> > - req->wb_pgbase = offset;
> > - req->wb_bytes = max(end, rqend) - req->wb_offset;
> > - goto out;
> > - }
> > -
> > - if (end > rqend)
> > - req->wb_bytes = end - req->wb_offset;
> > -
> > out:
>
> There's only one "goto out;" left in nfs_setup_write_request(). There
> are other return sites in nfs_setup_write_request() that simply
> "return req;" -- for what purpose is this one goto still here?
It could be replaced by a single 'return req'.
--
Trond Myklebust
Linux NFS client maintainer
NetApp
Trond.Myklebust@netapp.com
www.netapp.com
next prev parent reply other threads:[~2008-06-17 21:57 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-06-16 19:23 [PATCH 0/2] More writeback code cleanups Trond Myklebust
[not found] ` <20080616192348.20513.72423.stgit-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
2008-06-16 19:23 ` [PATCH 1/2] NFS: Clean up nfs_update_request() Trond Myklebust
[not found] ` <20080616192348.20513.3284.stgit-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
2008-06-17 21:35 ` Chuck Lever
2008-06-17 21:56 ` Trond Myklebust [this message]
2008-06-18 20:40 ` Chuck Lever
2008-06-18 21:01 ` Trond Myklebust
2008-06-18 22:05 ` Chuck Lever
2008-06-19 21:22 ` Trond Myklebust
2008-06-20 16:52 ` Chuck Lever
2008-06-20 20:36 ` Chuck Lever
2008-06-16 19:23 ` [PATCH 2/2] NFS: Allow redirtying of a completed unstable write Trond Myklebust
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=1213739807.7288.86.camel@localhost \
--to=trond.myklebust@netapp.com \
--cc=chuck.lever@oracle.com \
--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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.